Пример #1
0
        /// <summary>
        /// Loads the assembly from the byte array and executes the best matched method based on the incoming request.
        /// </summary>
        /// <param name="assemblyBytes">Byte array containing the assembly to be loaded.</param>
        /// <param name="request"><see cref="RouteRequest"/> object containing all data for the current request.</param>
        /// <returns><see cref="RouteResponse"/> object containing the response for the current request.</returns>
        public RouteResponse Execute(byte[] assemblyBytes, RouteRequest request)
        {
            // Run the private async method synchronously.
            var task = ExecuteAsync(assemblyBytes, request);

            task.Wait();

            return(task.Result);
        }
Пример #2
0
        public RouteResponse Execute(byte[] assemblyBytes, RouteRequest request)
        {
            var assembly       = Assembly.Load(assemblyBytes);
            var baseController = typeof(BaseController);
            var classType      = assembly.GetTypes().FirstOrDefault(t => t.InheritsFrom(baseController));

            if (classType == null)
            {
                throw new EntryPointException($"Could not locate any types that inherit from '{baseController.Name}'.");
            }

            // Locate a public instance method that begins with the http method type.
            var methodType = classType.GetMethods(BindingFlags.Instance | BindingFlags.Public)
                             .Where(m => !m.Name.Equals("GetHashCode") && !m.Name.Equals("GetType"))
                             .FirstOrDefault(m => m.Name.StartsWith(request.Method, StringComparison.CurrentCultureIgnoreCase));

            if (methodType == null)
            {
                throw new EntryPointException($"No method was found for http verb '{request.Method}'.");
            }

            // Create an instance of controller.
            var instance = classType.CreateInstance();

            // Void methods are treated as a no content result, so we'll create the ExecutionResponse object ourselves with NoContent status code.
            if (methodType.ReturnType == typeof(void))
            {
                return new RouteResponse(HttpStatusCode.NoContent)
                       {
                           Body = new byte[0]
                       }
            }
            ;

            // Methods that directly return an ExecutionResponse are considered bare-metal responses, so we'll just pass it along.
            return((RouteResponse)methodType.Invoke(instance, new object[] { request }));
        }
    }
Пример #3
0
        private async Task <RouteResponse> ExecuteAsync(byte[] assemblyBytes, RouteRequest request)
        {
            var assembly       = Assembly.Load(assemblyBytes);
            var baseController = typeof(BaseController);
            var classType      = assembly.GetTypes().FirstOrDefault(t => t.InheritsFrom(baseController));

            if (classType == null)
            {
                throw new EntryPointException($"Could not locate any types that inherit from '{baseController.Name}'.");
            }

            // Locate a public instance method that begins with the http method type.
            var methodType = classType.GetMethods(BindingFlags.Instance | BindingFlags.Public)
                             .Where(m => !m.Name.Equals("GetHashCode") && !m.Name.Equals("GetType"))
                             .FirstOrDefault(m => m.Name.StartsWith(request.Method, StringComparison.CurrentCultureIgnoreCase));

            if (methodType == null)
            {
                throw new EntryPointException($"No method was found for http verb '{request.Method}'.");
            }

            // For async methods we need to ensure that the method is marked async. Otherwise we will fail
            // with an exception. We could still run it, but we don't want to promote bad code.
            if ((methodType.ReturnType == typeof(Task) || methodType.ReturnType.InheritsFrom(typeof(Task))) && !methodType.IsAsyncMethod())
            {
                throw new EntryPointException($"Found method named '{methodType.Name}' which returns Task, however the method must be marked as async.");
            }

            // Create an instance of controller and execute the method.
            var instance = classType.CreateInstance();
            var result   = methodType.Invoke(instance, new object[] { request });

            // Depending on the result, we can determine if a method is asynchronous or not
            // and treat it as such by waiting for it to complete before returning the result.
            switch (result)
            {
            // Standard synchronous return type, return it straight away.
            case RouteResponse resultTyped:
                return(resultTyped);

            // Typed async result, wait for the result then return it.
            case Task <RouteResponse> resultTaskTyped:
                return(await resultTaskTyped);

            // Untyped async result, wait for completion then return a no content result.
            case Task resultTask:
                await resultTask;

                return(RouteResponse.NoContent);

            // For void methods, we'll return a no content result, otherwise it's an unknown type so throw.
            default:
                // Void is a valid type, return an empty result.
                if (methodType.ReturnType == typeof(void))
                {
                    return(RouteResponse.NoContent);
                }

                // All other types should produce an exception because we aren't sure what they want us to do with it.
                throw new EntryPointException($"Found method named '{methodType.Name}', but has an invalid return type. Valid types are void, RouteResponse, Task, and Task<RouteResponse>.");
            }
        }