public OperationHandler(ILightNodeOptions options, Type classType, MethodInfo methodInfo) { this.ClassName = classType.Name; this.MethodName = methodInfo.Name; this.Arguments = methodInfo.GetParameters() .Select(x => new ParameterInfoSlim(x)) .ToArray(); this.ParameterNames = Arguments.Select(x => x.Name).ToList().AsReadOnly(); this.ReturnType = methodInfo.ReturnType; this.filters = options.Filters .Concat(classType.GetCustomAttributes<LightNodeFilterAttribute>(true)) .Concat(methodInfo.GetCustomAttributes<LightNodeFilterAttribute>(true)) .OrderBy(x => x.Order) .ToArray(); var operationOption = methodInfo.GetCustomAttributes<OperationOptionAttribute>(true).FirstOrDefault() ?? classType.GetCustomAttributes<OperationOptionAttribute>(true).FirstOrDefault(); this.AcceptVerb = (operationOption != null && operationOption.AcceptVerbs != null) ? operationOption.AcceptVerbs.Value : options.DefaultAcceptVerb; var verbSpecifiedAttr = methodInfo.GetCustomAttributes<HttpVerbAttribtue>(true); if (verbSpecifiedAttr.Any()) { this.AcceptVerb = verbSpecifiedAttr.Aggregate((AcceptVerbs)0, (x, y) => x | y.AcceptVerbs); } this.ForceUseFormatter = (operationOption != null && operationOption.ContentFormatter != null) ? operationOption.ContentFormatter : null; var formatterChoiceBase = new[] { options.DefaultFormatter }.Concat(options.SpecifiedFormatters).Where(x => x != null).ToArray(); this.optionFormatters = formatterChoiceBase; this.formatterByExt = formatterChoiceBase.SelectMany(x => (x.Ext ?? "").Split('|'), (fmt, ext) => new { fmt, ext }).ToLookup(x => x.ext, x => x.fmt, StringComparer.OrdinalIgnoreCase); this.formatterByMediaType = formatterChoiceBase.ToLookup(x => x.MediaType, StringComparer.OrdinalIgnoreCase); this.formatterByContentEncoding = formatterChoiceBase.ToLookup(x => x.ContentEncoding, StringComparer.OrdinalIgnoreCase); this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast<Attribute>() .ToLookup(x => x.GetType()); foreach (var argument in this.Arguments) { if (!TypeBinder.IsAllowType(argument.ParameterType)) { throw new InvalidOperationException(string.Format("parameter is not allowed, class:{0} method:{1} paramName:{2} paramType:{3}", classType.Name, methodInfo.Name, argument.Name, argument.ParameterType.FullName)); } } // prepare lambda parameters var envArg = Expression.Parameter(typeof(IDictionary<string, object>), "environment"); var envBind = Expression.Bind(typeof(LightNodeContract).GetProperty("Environment"), envArg); var args = Expression.Parameter(typeof(object[]), "args"); var parameters = methodInfo.GetParameters() .Select((x, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), x.ParameterType)) .ToArray(); // Task or Task<T> if (typeof(Task).IsAssignableFrom(this.ReturnType)) { // (object[] args) => new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda<Func<IDictionary<string, object>, object[], Task>>( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); if (this.ReturnType.IsGenericType && this.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { this.handlerBodyType = HandlerBodyType.AsyncFunc; this.methodAsyncFuncBody = lambda.Compile(); lock (taskResultExtractors) { if (!taskResultExtractors.ContainsKey(this.ReturnType)) { // (object task) => (object)((Task<>).Result) var taskParameter = Expression.Parameter(typeof(object), "task"); var resultLambda = Expression.Lambda<Func<object, object>>( Expression.Convert( Expression.Property( Expression.Convert(taskParameter, this.ReturnType), "Result"), typeof(object)), taskParameter); var compiledResultLambda = resultLambda.Compile(); taskResultExtractors[this.ReturnType] = compiledResultLambda; } } } else { this.handlerBodyType = HandlerBodyType.AsyncAction; this.methodAsyncActionBody = lambda.Compile(); } } else if (this.ReturnType == typeof(void)) // of course void { // (object[] args) => { new X().M((T1)args[0], (T2)args[1])... } var lambda = Expression.Lambda<Action<IDictionary<string, object>, object[]>>( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); this.handlerBodyType = HandlerBodyType.Action; this.methodActionBody = lambda.Compile(); } else // return T { // (object[] args) => (object)new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda<Func<IDictionary<string, object>, object[], object>>( Expression.Convert( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters) , typeof(object)), envArg, args); this.handlerBodyType = HandlerBodyType.Func; this.methodFuncBody = lambda.Compile(); } }
public OperationHandler(ILightNodeOptions options, Type classType, MethodInfo methodInfo) { this.ClassName = classType.Name; this.MethodName = methodInfo.Name; this.Arguments = methodInfo.GetParameters() .Select(x => new ParameterInfoSlim(x)) .ToArray(); this.ParameterNames = Arguments.Select(x => x.Name).ToList().AsReadOnly(); this.ReturnType = methodInfo.ReturnType; this.filters = options.Filters .Concat(classType.GetCustomAttributes <LightNodeFilterAttribute>(true)) .Concat(methodInfo.GetCustomAttributes <LightNodeFilterAttribute>(true)) .OrderBy(x => x.Order) .ToArray(); var operationOption = methodInfo.GetCustomAttributes <OperationOptionAttribute>(true).FirstOrDefault() ?? classType.GetCustomAttributes <OperationOptionAttribute>(true).FirstOrDefault(); this.AcceptVerb = (operationOption != null && operationOption.AcceptVerbs != null) ? operationOption.AcceptVerbs.Value : options.DefaultAcceptVerb; var verbSpecifiedAttr = methodInfo.GetCustomAttributes <HttpVerbAttribtue>(true); if (verbSpecifiedAttr.Any()) { this.AcceptVerb = verbSpecifiedAttr.Aggregate((AcceptVerbs)0, (x, y) => x | y.AcceptVerbs); } this.ForceUseFormatter = (operationOption != null && operationOption.ContentFormatter != null) ? operationOption.ContentFormatter : null; var formatterChoiceBase = new[] { options.DefaultFormatter }.Concat(options.SpecifiedFormatters).Where(x => x != null).ToArray(); this.optionFormatters = formatterChoiceBase; this.formatterByExt = formatterChoiceBase.SelectMany(x => (x.Ext ?? "").Split('|'), (fmt, ext) => new { fmt, ext }).ToLookup(x => x.ext, x => x.fmt, StringComparer.OrdinalIgnoreCase); this.formatterByMediaType = formatterChoiceBase.ToLookup(x => x.MediaType, StringComparer.OrdinalIgnoreCase); this.formatterByContentEncoding = formatterChoiceBase.ToLookup(x => x.ContentEncoding, StringComparer.OrdinalIgnoreCase); this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast <Attribute>() .ToLookup(x => x.GetType()); foreach (var argument in this.Arguments) { if (!TypeBinder.IsAllowType(argument.ParameterType)) { throw new InvalidOperationException(string.Format("parameter is not allowed, class:{0} method:{1} paramName:{2} paramType:{3}", classType.Name, methodInfo.Name, argument.Name, argument.ParameterType.FullName)); } } // prepare lambda parameters var envArg = Expression.Parameter(typeof(IDictionary <string, object>), "environment"); var envBind = Expression.Bind(typeof(LightNodeContract).GetProperty("Environment"), envArg); var args = Expression.Parameter(typeof(object[]), "args"); var parameters = methodInfo.GetParameters() .Select((x, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), x.ParameterType)) .ToArray(); // Task or Task<T> if (typeof(Task).IsAssignableFrom(this.ReturnType)) { // (object[] args) => new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda <Func <IDictionary <string, object>, object[], Task> >( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); if (this.ReturnType.IsGenericType && this.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)) { this.handlerBodyType = HandlerBodyType.AsyncFunc; this.methodAsyncFuncBody = lambda.Compile(); lock (taskResultExtractors) { if (!taskResultExtractors.ContainsKey(this.ReturnType)) { // (object task) => (object)((Task<>).Result) var taskParameter = Expression.Parameter(typeof(object), "task"); var resultLambda = Expression.Lambda <Func <object, object> >( Expression.Convert( Expression.Property( Expression.Convert(taskParameter, this.ReturnType), "Result"), typeof(object)), taskParameter); var compiledResultLambda = resultLambda.Compile(); taskResultExtractors[this.ReturnType] = compiledResultLambda; } } } else { this.handlerBodyType = HandlerBodyType.AsyncAction; this.methodAsyncActionBody = lambda.Compile(); } } else if (this.ReturnType == typeof(void)) // of course void { // (object[] args) => { new X().M((T1)args[0], (T2)args[1])... } var lambda = Expression.Lambda <Action <IDictionary <string, object>, object[]> >( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); this.handlerBodyType = HandlerBodyType.Action; this.methodActionBody = lambda.Compile(); } else // return T { // (object[] args) => (object)new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda <Func <IDictionary <string, object>, object[], object> >( Expression.Convert( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters) , typeof(object)), envArg, args); this.handlerBodyType = HandlerBodyType.Func; this.methodFuncBody = lambda.Compile(); } }
public MethodDescriptor(HubDescriptor hub, MethodInfo methodInfo) { var classType = hub.HubType; var opAttr = methodInfo.GetCustomAttributes<OperationAttribute>().FirstOrDefault(); if (opAttr == null) throw new InvalidOperationException($"Method needs OperationAttribute, class:{classType.Name} method:{methodInfo.Name}"); this.Hub = hub; this.OperationCode = opAttr.OperationCode; this.MethodName = methodInfo.Name; this.Arguments = methodInfo.GetParameters() .Select(x => new ParameterInfoSlim(x)) .ToArray(); this.ParameterNames = Arguments.Select(x => x.Name).ToList().AsReadOnly(); this.ReturnType = methodInfo.ReturnType; this.filters = classType.GetCustomAttributes<PhotonWireFilterAttribute>(true) .Concat(methodInfo.GetCustomAttributes<PhotonWireFilterAttribute>(true)) .OrderBy(x => x.Order) .ToArray(); this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast<Attribute>() .ToLookup(x => x.GetType()); // prepare lambda parameters var contextArg = Expression.Parameter(typeof(OperationContext), "context"); var contextBind = Expression.Bind(classType.GetProperty("Context"), contextArg); var args = Expression.Parameter(typeof(object[]), "args"); var parameters = methodInfo.GetParameters() .Select((x, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), x.ParameterType)) .ToArray(); // Task or Task<T> if (typeof(Task).IsAssignableFrom(this.ReturnType)) { // (object[] args) => new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda<Func<OperationContext, object[], Task>>( Expression.Call( Expression.MemberInit(Expression.New(classType), contextBind), methodInfo, parameters), contextArg, args); if (this.ReturnType.IsGenericType && this.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { this.handlerBodyType = HandlerBodyType.AsyncFunc; this.methodAsyncFuncBody = lambda.Compile(); lock (taskResultExtractors) { if (!taskResultExtractors.ContainsKey(this.ReturnType)) { // (object task) => (object)((Task<>).Result) var taskParameter = Expression.Parameter(typeof(object), "task"); var resultLambda = Expression.Lambda<Func<object, object>>( Expression.Convert( Expression.Property( Expression.Convert(taskParameter, this.ReturnType), "Result"), typeof(object)), taskParameter); var compiledResultLambda = resultLambda.Compile(); taskResultExtractors[this.ReturnType] = compiledResultLambda; } } } else { this.handlerBodyType = HandlerBodyType.AsyncAction; this.methodAsyncActionBody = lambda.Compile(); } } else if (this.ReturnType == typeof(void)) // of course void { // (object[] args) => { new X().M((T1)args[0], (T2)args[1])... } var lambda = Expression.Lambda<Action<OperationContext, object[]>>( Expression.Call( Expression.MemberInit(Expression.New(classType), contextBind), methodInfo, parameters), contextArg, args); this.handlerBodyType = HandlerBodyType.Action; this.methodActionBody = lambda.Compile(); } else // return T { // (object[] args) => (object)new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda<Func<OperationContext, object[], object>>( Expression.Convert( Expression.Call( Expression.MemberInit(Expression.New(classType), contextBind), methodInfo, parameters) , typeof(object)), contextArg, args); this.handlerBodyType = HandlerBodyType.Func; this.methodFuncBody = lambda.Compile(); } }
public MethodDescriptor(HubDescriptor hub, MethodInfo methodInfo) { var classType = hub.HubType; var opAttr = methodInfo.GetCustomAttributes <OperationAttribute>().FirstOrDefault(); if (opAttr == null) { throw new InvalidOperationException($"Method needs OperationAttribute, class:{classType.Name} method:{methodInfo.Name}"); } this.Hub = hub; this.OperationCode = opAttr.OperationCode; this.MethodName = methodInfo.Name; this.Arguments = methodInfo.GetParameters() .Select(x => new ParameterInfoSlim(x)) .ToArray(); this.ParameterNames = Arguments.Select(x => x.Name).ToList().AsReadOnly(); this.ReturnType = methodInfo.ReturnType; this.filters = classType.GetCustomAttributes <PhotonWireFilterAttribute>(true) .Concat(methodInfo.GetCustomAttributes <PhotonWireFilterAttribute>(true)) .OrderBy(x => x.Order) .ToArray(); this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast <Attribute>() .ToLookup(x => x.GetType()); // prepare lambda parameters var contextArg = Expression.Parameter(typeof(OperationContext), "context"); var contextBind = Expression.Bind(classType.GetProperty("Context"), contextArg); var args = Expression.Parameter(typeof(object[]), "args"); var parameters = methodInfo.GetParameters() .Select((x, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), x.ParameterType)) .ToArray(); // Task or Task<T> if (typeof(Task).IsAssignableFrom(this.ReturnType)) { // (object[] args) => new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda <Func <OperationContext, object[], Task> >( Expression.Call( Expression.MemberInit(Expression.New(classType), contextBind), methodInfo, parameters), contextArg, args); if (this.ReturnType.IsGenericType && this.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)) { this.handlerBodyType = HandlerBodyType.AsyncFunc; this.methodAsyncFuncBody = lambda.Compile(); lock (taskResultExtractors) { if (!taskResultExtractors.ContainsKey(this.ReturnType)) { // (object task) => (object)((Task<>).Result) var taskParameter = Expression.Parameter(typeof(object), "task"); var resultLambda = Expression.Lambda <Func <object, object> >( Expression.Convert( Expression.Property( Expression.Convert(taskParameter, this.ReturnType), "Result"), typeof(object)), taskParameter); var compiledResultLambda = resultLambda.Compile(); taskResultExtractors[this.ReturnType] = compiledResultLambda; } } } else { this.handlerBodyType = HandlerBodyType.AsyncAction; this.methodAsyncActionBody = lambda.Compile(); } } else if (this.ReturnType == typeof(void)) // of course void { // (object[] args) => { new X().M((T1)args[0], (T2)args[1])... } var lambda = Expression.Lambda <Action <OperationContext, object[]> >( Expression.Call( Expression.MemberInit(Expression.New(classType), contextBind), methodInfo, parameters), contextArg, args); this.handlerBodyType = HandlerBodyType.Action; this.methodActionBody = lambda.Compile(); } else // return T { // (object[] args) => (object)new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda <Func <OperationContext, object[], object> >( Expression.Convert( Expression.Call( Expression.MemberInit(Expression.New(classType), contextBind), methodInfo, parameters) , typeof(object)), contextArg, args); this.handlerBodyType = HandlerBodyType.Func; this.methodFuncBody = lambda.Compile(); } }
public OperationHandler(LightNodeOptions options, Type classType, MethodInfo methodInfo) { this.ClassName = classType.Name; this.MethodName = methodInfo.Name; this.Arguments = methodInfo.GetParameters() .Select(x => new ParameterInfoSlim(x)) .ToArray(); this.ReturnType = methodInfo.ReturnType; this.filters = options.Filters .Concat(classType.GetCustomAttributes <LightNodeFilterAttribute>(true)) .Concat(methodInfo.GetCustomAttributes <LightNodeFilterAttribute>(true)) .OrderBy(x => x.Order) .ToArray(); this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast <Attribute>() .ToLookup(x => x.GetType()); foreach (var argument in this.Arguments) { if (!TypeBinder.IsAllowType(argument.ParameterType)) { throw new InvalidOperationException(string.Format("parameter is not allowed, class:{0} method:{1} paramName:{2} paramType:{3}", classType.Name, methodInfo.Name, argument.Name, argument.ParameterType.FullName)); } } // prepare lambda parameters var envArg = Expression.Parameter(typeof(IDictionary <string, object>), "environment"); var envBind = Expression.Bind(typeof(LightNodeContract).GetProperty("Environment"), envArg); var args = Expression.Parameter(typeof(object[]), "args"); var parameters = methodInfo.GetParameters() .Select((x, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), x.ParameterType)) .ToArray(); // Task or Task<T> if (typeof(Task).IsAssignableFrom(this.ReturnType)) { // (object[] args) => new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda <Func <IDictionary <string, object>, object[], Task> >( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); if (this.ReturnType.IsGenericType && this.ReturnType.GetGenericTypeDefinition() == typeof(Task <>)) { this.handlerBodyType = HandlerBodyType.AsyncFunc; this.methodAsyncFuncBody = lambda.Compile(); lock (taskResultExtractors) { if (!taskResultExtractors.ContainsKey(this.ReturnType)) { // (object task) => (object)((Task<>).Result) var taskParameter = Expression.Parameter(typeof(object), "task"); var resultLambda = Expression.Lambda <Func <object, object> >( Expression.Convert( Expression.Property( Expression.Convert(taskParameter, this.ReturnType), "Result"), typeof(object)), taskParameter); var compiledResultLambda = resultLambda.Compile(); taskResultExtractors[this.ReturnType] = compiledResultLambda; } } } else { this.handlerBodyType = HandlerBodyType.AsyncAction; this.methodAsyncActionBody = lambda.Compile(); } } else if (this.ReturnType == typeof(void)) // of course void { // (object[] args) => { new X().M((T1)args[0], (T2)args[1])... } var lambda = Expression.Lambda <Action <IDictionary <string, object>, object[]> >( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); this.handlerBodyType = HandlerBodyType.Action; this.methodActionBody = lambda.Compile(); } else // return T { // (object[] args) => (object)new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda <Func <IDictionary <string, object>, object[], object> >( Expression.Convert( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters) , typeof(object)), envArg, args); this.handlerBodyType = HandlerBodyType.Func; this.methodFuncBody = lambda.Compile(); } }
public OperationHandler(LightNodeOptions options, Type classType, MethodInfo methodInfo) { this.ClassName = classType.Name; this.MethodName = methodInfo.Name; this.Arguments = methodInfo.GetParameters() .Select(x => new ParameterInfoSlim(x)) .ToArray(); this.ReturnType = methodInfo.ReturnType; this.filters = options.Filters .Concat(classType.GetCustomAttributes<LightNodeFilterAttribute>(true)) .Concat(methodInfo.GetCustomAttributes<LightNodeFilterAttribute>(true)) .OrderBy(x => x.Order) .ToArray(); this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast<Attribute>() .ToLookup(x => x.GetType()); foreach (var argument in this.Arguments) { if (!TypeBinder.IsAllowType(argument.ParameterType)) { throw new InvalidOperationException(string.Format("parameter is not allowed, class:{0} method:{1} paramName:{2} paramType:{3}", classType.Name, methodInfo.Name, argument.Name, argument.ParameterType.FullName)); } } // prepare lambda parameters var envArg = Expression.Parameter(typeof(IDictionary<string, object>), "environment"); var envBind = Expression.Bind(typeof(LightNodeContract).GetProperty("Environment"), envArg); var args = Expression.Parameter(typeof(object[]), "args"); var parameters = methodInfo.GetParameters() .Select((x, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), x.ParameterType)) .ToArray(); // Task or Task<T> if (typeof(Task).IsAssignableFrom(this.ReturnType)) { // (object[] args) => new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda<Func<IDictionary<string, object>, object[], Task>>( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); if (this.ReturnType.IsGenericType && this.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { this.handlerBodyType = HandlerBodyType.AsyncFunc; this.methodAsyncFuncBody = lambda.Compile(); lock (taskResultExtractors) { if (!taskResultExtractors.ContainsKey(this.ReturnType)) { // (object task) => (object)((Task<>).Result) var taskParameter = Expression.Parameter(typeof(object), "task"); var resultLambda = Expression.Lambda<Func<object, object>>( Expression.Convert( Expression.Property( Expression.Convert(taskParameter, this.ReturnType), "Result"), typeof(object)), taskParameter); var compiledResultLambda = resultLambda.Compile(); taskResultExtractors[this.ReturnType] = compiledResultLambda; } } } else { this.handlerBodyType = HandlerBodyType.AsyncAction; this.methodAsyncActionBody = lambda.Compile(); } } else if (this.ReturnType == typeof(void)) // of course void { // (object[] args) => { new X().M((T1)args[0], (T2)args[1])... } var lambda = Expression.Lambda<Action<IDictionary<string, object>, object[]>>( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); this.handlerBodyType = HandlerBodyType.Action; this.methodActionBody = lambda.Compile(); } else // return T { // (object[] args) => (object)new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda<Func<IDictionary<string, object>, object[], object>>( Expression.Convert( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters) , typeof(object)), envArg, args); this.handlerBodyType = HandlerBodyType.Func; this.methodFuncBody = lambda.Compile(); } }
public OperationHandler(Type classType, MethodInfo methodInfo) { this.ClassName = classType.Name; this.MethodName = methodInfo.Name; this.Arguments = methodInfo.GetParameters() .Select(x => new ParameterInfoSlim(x)) .ToArray(); this.ParameterNames = Arguments.Select(x => x.Name).ToList().AsReadOnly(); this.ReturnType = methodInfo.ReturnType; this.AttributeLookup = classType.GetCustomAttributes(true) .Concat(methodInfo.GetCustomAttributes(true)) .Cast<Attribute>() .ToLookup(x => x.GetType()); // prepare lambda parameters var envArg = Expression.Parameter(typeof(IDictionary<string, object>), "environment"); var envBind = Expression.Bind(typeof(IMOwinBehaviorContract).GetProperty("Environment"), envArg); var args = Expression.Parameter(typeof(object[]), "args"); Expression[] parameters = methodInfo.GetParameters() .Select((x, i) => Expression.Convert(Expression.ArrayIndex(args, Expression.Constant(i)), x.ParameterType)) .ToArray(); // Task or Task<T> if (typeof(Task).IsAssignableFrom(this.ReturnType)) { // (object[] args) => new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda<Func<IDictionary<string, object>, object[], Task>>( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); if (this.ReturnType.IsGenericType && this.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { this._handlerBodyType = HandlerBodyType.AsyncFunc; this._methodAsyncFuncBody = lambda.Compile(); lock (TaskResultExtractors) { if (!TaskResultExtractors.ContainsKey(this.ReturnType)) { // (object task) => (object)((Task<>).Result) var taskParameter = Expression.Parameter(typeof(object), "task"); var resultLambda = Expression.Lambda<Func<object, object>>( Expression.Convert( Expression.Property( Expression.Convert(taskParameter, this.ReturnType), "Result"), typeof(object)), taskParameter); var compiledResultLambda = resultLambda.Compile(); TaskResultExtractors[this.ReturnType] = compiledResultLambda; } } } else { this._handlerBodyType = HandlerBodyType.AsyncAction; this._methodAsyncActionBody = lambda.Compile(); } } else if (this.ReturnType == typeof(void)) { // (object[] args) => { new X().M((T1)args[0], (T2)args[1])... } var lambda = Expression.Lambda<Action<IDictionary<string, object>, object[]>>( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); this._handlerBodyType = HandlerBodyType.Action; this._methodActionBody = lambda.Compile(); } else // return T { // (object[] args) => (object)new X().M((T1)args[0], (T2)args[1])... var lambda = Expression.Lambda<Func<IDictionary<string, object>, object[], object>>( Expression.Convert( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters) , typeof(object)), envArg, args); this._handlerBodyType = HandlerBodyType.Func; this._methodFuncBody = lambda.Compile(); } }