private ControllerFunction CreateControllerFunction(ControllerMethod controllerMethod) { var httpContextArgument = Expression.Parameter(typeof(IHttpContext), "httpContext"); var modelBinderArgument = Expression.Parameter(typeof(IModelBinder), "modelBinder"); var controllerArgument = Expression.Parameter(typeof(object), "controller"); var errorContainerVariable = Expression.Variable(typeof(IErrorContainer)); var foundMethod = (from method in controllerMethod.ControllerType.GetMethods(BindingFlags.Instance | BindingFlags.Public) let attribute = method.GetCustomAttribute<HttpMethodAttribute>() where attribute != null && attribute.HttpMethod == controllerMethod.Method select method).FirstOrDefault(); if (foundMethod == null) { return MethodNotFoundControllerFunction; } var parameters = foundMethod.GetParameters(); IList<ParameterExpression> variables = new List<ParameterExpression>(parameters.Length); IList<Expression> body = new List<Expression>(parameters.Length); var modelBindingGetMethod = typeof(IModelBinding).GetMethods()[0]; foreach (var parameter in parameters) { var variable = Expression.Variable(parameter.ParameterType, parameter.Name); variables.Add(variable); var attributes = parameter.GetCustomAttributes().ToList(); var modelBindingAttribute = attributes.OfType<IModelBinding>().Single(); body.Add( Expression.Assign(variable, Expression.Call(Expression.Constant(modelBindingAttribute), modelBindingGetMethod.MakeGenericMethod(parameter.ParameterType), httpContextArgument, modelBinderArgument ))); if (!attributes.OfType<NullableAttribute>().Any()) { body.Add(Expression.IfThen(Expression.Equal(variable, Expression.Constant(null)), Expression.Call(errorContainerVariable, "Log", Type.EmptyTypes, Expression.Constant(parameter.Name + " Is not found (null) and not marked as nullable.")))); } if (parameter.ParameterType.GetInterfaces().Contains(typeof(IValidate))) { body.Add(Expression.IfThen(Expression.NotEqual(variable, Expression.Constant(null)), Expression.Call(variable, "Validate", Type.EmptyTypes, errorContainerVariable))); } } var methodCallExp = Expression.Call(Expression.Convert(controllerArgument, controllerMethod.ControllerType), foundMethod, variables); var labelTarget = Expression.Label(typeof(Task<IControllerResponse>)); var parameterBindingExpression = body.Count > 0 ? (Expression)Expression.Block(body) : Expression.Empty(); var methodBody = Expression.Block( variables.Concat(new[] { errorContainerVariable }), Expression.Assign(errorContainerVariable, Expression.New(typeof(ErrorContainer))), parameterBindingExpression, Expression.IfThen(Expression.Not(Expression.Property(errorContainerVariable, "Any")), Expression.Return(labelTarget, methodCallExp)), Expression.Label(labelTarget, Expression.Call(errorContainerVariable, "GetResponse", Type.EmptyTypes)) ); var parameterExpressions = new[] { httpContextArgument, modelBinderArgument, controllerArgument }; var lambda = Expression.Lambda<ControllerFunction>(methodBody, parameterExpressions); return lambda.Compile(); }
private bool Equals(ControllerMethod other) { return _controllerType == other._controllerType && _method == other._method; }
private Task<IControllerResponse> CallMethod(IHttpContext context, IController controller) { var controllerMethod = new ControllerMethod(controller.GetType(), context.Request.Method); ControllerFunction controllerFunction; if (!ControllerFunctions.TryGetValue(controllerMethod, out controllerFunction)) { lock (SyncRoot) { if (!ControllerFunctions.TryGetValue(controllerMethod, out controllerFunction)) { ControllerFunctions[controllerMethod] = controllerFunction = CreateControllerFunction(controllerMethod); } } } return controllerFunction(context, this.ModelBinder, controller); //context.Response = await controllerResponse.Respond(context, _view).ConfigureAwait(false); }