Beispiel #1
0
        /// <summary>
        /// Preloads the list of mappings using reflections
        /// </summary>
        private void PrepareMappings()
        {
            var methods = ApiSurface.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
                          .Where(t => t.GetCustomAttribute <APIMethodAttribute>() != null);

            Mappings = new List <APIMapping>();

            foreach (var method in methods)
            {
                var attr    = method.GetCustomAttribute <APIMethodAttribute>();
                var mapping = new APIMapping(attr.Mapping, attr.Verb, method);
                Mappings.Add(mapping);
            }

            //TODO optimization by presort
        }
Beispiel #2
0
        public async Task <APIResponse> Call(HttpListenerRequest request)
        {
            //basically the world's shittiest front controller

            //reject certain things out of hand
            if (request.ContentType == "application/coffee-pot-command")
            {
                throw new TeapotException();
            }

            string requestVerb = request.HttpMethod;

            //split strings, find matching method, and call
            string rawUrl = request.RawUrl.Trim();

            if (rawUrl.Contains('?'))
            {
                rawUrl = rawUrl.Substring(0, rawUrl.IndexOf('?'));
            }
            string[] urlSegments = rawUrl.Split('/', StringSplitOptions.RemoveEmptyEntries); //that will probably bite me later

            //discard the first segment
            urlSegments = urlSegments.Skip(1).ToArray();
            int numSegments = urlSegments.Length;

            //match segments to stored methods
            Dictionary <APIMapping, int> matchedMappings = new Dictionary <APIMapping, int>();

            foreach (var potentialMapping in Mappings)
            {
                //check verbs lol
                if (!string.Equals(potentialMapping.Verb.ToString(), requestVerb, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                int matchedSegments = 0;

                if (potentialMapping.Segments.Length < numSegments && potentialMapping.UseWildcard)
                {
                    //potentialMapping has less segments than urlSegments and is wildcard -> must match up to potentialMapping.segments
                    if (Enumerable.SequenceEqual <string>(potentialMapping.Segments, urlSegments.Take(potentialMapping.Segments.Length), StringComparer.OrdinalIgnoreCase))
                    {
                        matchedSegments = potentialMapping.Segments.Length;
                    }
                }
                else if (potentialMapping.Segments.Length == numSegments && !potentialMapping.UseWildcard)
                {
                    //potentialMapping has same number of segments as urlSegments -> all must match
                    if (Enumerable.SequenceEqual <string>(potentialMapping.Segments, urlSegments, StringComparer.OrdinalIgnoreCase))
                    {
                        matchedSegments = potentialMapping.Segments.Length;
                    }
                }

                if (matchedSegments > 0)
                {
                    matchedMappings.Add(potentialMapping, matchedSegments);
                }
            }

            APIMapping mapping = default;

            //we can short-circuit two easy cases
            if (matchedMappings.Count == 0)
            {
                throw new NotImplementedException();
            }
            else if (matchedMappings.Count == 1)
            {
                mapping = matchedMappings.First().Key;
            }
            else
            {
                //use the best match
                var sortedMappings = matchedMappings.OrderByDescending(kvp => kvp.Value);
                mapping = sortedMappings.First().Key;
            }

            //get segment and body, parse query string
            string segment = mapping.Segments.Length < numSegments?string.Join('/', urlSegments.Skip(mapping.Segments.Length)) : string.Empty;

            string body       = request.GetBody();
            var    parameters = request.Url.ParseQueryString();
            Dictionary <string, string> parametersDict = parameters.AllKeys.ToDictionary(k => k, k => parameters[k]);

            //call method
            APIRequest apiRequest = new APIRequest(request.RawUrl, segment, body, parametersDict);

            if (typeof(Task <APIResponse>).IsAssignableFrom(mapping.Method.ReturnType))
            {
                return(await(Task <APIResponse>) mapping.Method.Invoke(ApiSurface, new object[] { apiRequest }));
            }
            else
            {
                return((APIResponse)mapping.Method.Invoke(ApiSurface, new object[] { apiRequest }));
            }


            throw new NotImplementedException();
        }