public Task MapAsync(Func <IContainer> container, Type type, MethodInfo method, Routing.Route route) { container.ThrowIfNull("container"); type.ThrowIfNull("type"); method.ThrowIfNull("method"); route.ThrowIfNull("route"); bool methodReturnTypeImplementsIResponse = method.ReturnType.ImplementsInterface <IResponse>(); bool methodReturnTypeIsTaskT = method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task <>); bool methodReturnTypeIsVoid = method.ReturnType == typeof(void); if (methodReturnTypeImplementsIResponse) { ParameterInfo[] parameterInfos = method.GetParameters(); ParameterExpression instanceParameterExpression = Expression.Parameter(typeof(object), "instance"); ParameterExpression parametersParameterExpression = Expression.Parameter(typeof(object[]), "parameters"); UnaryExpression unaryExpression = Expression.Convert( Expression.Call( Expression.Convert(instanceParameterExpression, type), method, parameterInfos.Select((arg, index) => Expression.Convert( Expression.ArrayIndex(parametersParameterExpression, Expression.Constant(index)), arg.ParameterType))), typeof(IResponse)); Func <object, object[], IResponse> @delegate = Expression.Lambda <Func <object, object[], IResponse> >(unaryExpression, instanceParameterExpression, parametersParameterExpression).Compile(); route.RespondWith( async context => { object instance; try { instance = container().GetInstance(type); } catch (Exception exception) { throw new ApplicationException(String.Format("Unable to resolve instance of type {0}.", type.FullName), exception); } if (instance == null) { throw new ApplicationException(String.Format("Unable to resolve instance of type {0}.", type.FullName)); } var parameterValueRetriever = new ParameterValueRetriever(_parameterMappers); object[] parameterValues = (await parameterValueRetriever.GetParameterValuesAsync(context, type, method)).ToArray(); return(@delegate(instance, parameterValues)); }, method.ReturnType); } else if (methodReturnTypeIsTaskT) { ParameterInfo[] parameterInfos = method.GetParameters(); ParameterExpression instanceParameterExpression = Expression.Parameter(typeof(object), "instance"); ParameterExpression parametersParameterExpression = Expression.Parameter(typeof(object[]), "parameters"); Type methodGenericArgumentType = method.ReturnType.GetGenericArguments()[0]; MethodInfo upcastMethodInfo = typeof(TaskExtensions) .GetMethod("Upcast", BindingFlags.Static | BindingFlags.Public) .MakeGenericMethod(methodGenericArgumentType, typeof(IResponse)); UnaryExpression unaryExpression = Expression.Convert( Expression.Call( upcastMethodInfo, Expression.Call( Expression.Convert(instanceParameterExpression, type), method, parameterInfos.Select((arg, index) => Expression.Convert( Expression.ArrayIndex(parametersParameterExpression, Expression.Constant(index)), arg.ParameterType)))), upcastMethodInfo.ReturnType); Func <object, object[], Task <IResponse> > @delegate = Expression.Lambda <Func <object, object[], Task <IResponse> > >(unaryExpression, instanceParameterExpression, parametersParameterExpression).Compile(); route.RespondWith( async context => { object instance; try { instance = container().GetInstance(type); } catch (Exception exception) { throw new ApplicationException(String.Format("Unable to resolve instance of type {0}.", type.FullName), exception); } if (instance == null) { throw new ApplicationException(String.Format("Unable to resolve instance of type {0}.", type.FullName)); } var parameterValueRetriever = new ParameterValueRetriever(_parameterMappers); object[] parameterValues = (await parameterValueRetriever.GetParameterValuesAsync(context, type, method)).ToArray(); return(await @delegate(instance, parameterValues)); }, methodGenericArgumentType); } else if (methodReturnTypeIsVoid) { ParameterInfo[] parameterInfos = method.GetParameters(); ParameterExpression instanceParameterExpression = Expression.Parameter(typeof(object), "instance"); ParameterExpression parametersParameterExpression = Expression.Parameter(typeof(object[]), "parameters"); MethodCallExpression methodCallExpression = Expression.Call( Expression.Convert(instanceParameterExpression, type), method, parameterInfos.Select((arg, index) => Expression.Convert( Expression.ArrayIndex(parametersParameterExpression, Expression.Constant(index)), arg.ParameterType))); Action <object, object[]> @delegate = Expression.Lambda <Action <object, object[]> >(methodCallExpression, instanceParameterExpression, parametersParameterExpression).Compile(); route.RespondWithNoContent( async context => { object instance; try { instance = container().GetInstance(type); } catch (Exception exception) { throw new ApplicationException(String.Format("Unable to resolve instance of type {0}.", type.FullName), exception); } if (instance == null) { throw new ApplicationException(String.Format("Unable to resolve instance of type {0}.", type.FullName)); } var parameterValueRetriever = new ParameterValueRetriever(_parameterMappers); object[] parameterValues = (await parameterValueRetriever.GetParameterValuesAsync(context, type, method)).ToArray(); @delegate(instance, parameterValues); }); } else { throw new ApplicationException(String.Format("The return type of {0}.{1} must implement {2} or be a {3} whose generic type argument implements {2}.", type.FullName, method.Name, typeof(IResponse).Name, typeof(Task <>))); } return(Task.Factory.Empty()); }