Beispiel #1
0
        // cache all methods
        public void RegisterHandler(Assembly[] hostAssemblies)
        {
            if (Interlocked.Increment(ref alreadyRegistered) != 0) return;

            var contractTypes = hostAssemblies
                .SelectMany(x =>
                {
                    try
                    {
                        return x.GetTypes();
                    }
                    catch (ReflectionTypeLoadException ex)
                    {
                        return ex.Types.Where(t => t != null);
                    }
                })
                .Where(x => typeof(LightNodeContract).IsAssignableFrom(x))
                .Where(x => !x.IsAbstract);

            Parallel.ForEach(contractTypes, classType =>
            {
                var className = classType.Name;
                if (!classType.GetConstructors().Any(x => x.GetParameters().Length == 0))
                {
                    throw new InvalidOperationException(string.Format("Type needs parameterless constructor, class:{0}", classType.FullName));
                }
                if (classType.GetCustomAttribute<IgnoreOperationAttribute>(true) != null) return; // ignore

                foreach (var methodInfo in classType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_"))) continue; // as property
                    if (methodInfo.GetCustomAttribute<IgnoreOperationAttribute>(true) != null) continue; // ignore

                    var methodName = methodInfo.Name;

                    // ignore default methods
                    if (methodName == "Equals"
                     || methodName == "GetHashCode"
                     || methodName == "GetType"
                     || methodName == "ToString")
                    {
                        continue;
                    }

                    // create handler
                    var handler = new OperationHandler(options, classType, methodInfo);
                    lock (handlers)
                    {
                        // fail duplicate entry
                        var path = new RequestPath(className, methodName);
                        if (handlers.ContainsKey(path))
                        {
                            throw new InvalidOperationException(string.Format("same class and method is not allowed, class:{0} method:{1}", className, methodName));
                        }
                        handlers.Add(path, handler);
                    }
                }
            });
        }
Beispiel #2
0
 internal OperationInfo(OperationHandler handler)
 {
     this.ClassName         = handler.ClassName;
     this.MethodName        = handler.MethodName;
     this.AcceptVerbs       = handler.AcceptVerb;
     this.Parameters        = handler.Arguments;
     this.ReturnType        = handler.ReturnType;
     this.ForceUseFormatter = handler.ForceUseFormatter;
 }
Beispiel #3
0
        // cache all methods
        public IReadOnlyCollection <KeyValuePair <string, OperationInfo> > RegisterHandler(Assembly[] hostAssemblies)
        {
            if (Interlocked.Increment(ref alreadyRegistered) != 0)
            {
                return(new KeyValuePair <string, OperationInfo> [0]);
            }

            var contractTypes = hostAssemblies
                                .SelectMany(x =>
            {
                try
                {
                    return(x.GetTypes());
                }
                catch (ReflectionTypeLoadException ex)
                {
                    return(ex.Types.Where(t => t != null));
                }
            })
                                .Where(x => typeof(LightNodeContract).IsAssignableFrom(x))
                                .Where(x => !x.IsAbstract);

            Parallel.ForEach(contractTypes, classType =>
            {
                var className = classType.Name;
                if (!classType.GetConstructors().Any(x => x.GetParameters().Length == 0))
                {
                    throw new InvalidOperationException(string.Format("Type needs parameterless constructor, class:{0}", classType.FullName));
                }
                if (classType.GetCustomAttribute <IgnoreOperationAttribute>(true) != null)
                {
                    return;                                                                       // ignore
                }
                foreach (var methodInfo in classType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_")))
                    {
                        continue;                                                                                                         // as property
                    }
                    if (methodInfo.GetCustomAttribute <IgnoreOperationAttribute>(true) != null)
                    {
                        continue;                                                                        // ignore
                    }
                    var methodName = methodInfo.Name;

                    // ignore default methods
                    if (methodName == "Equals" ||
                        methodName == "GetHashCode" ||
                        methodName == "GetType" ||
                        methodName == "ToString")
                    {
                        continue;
                    }

                    var sw = Stopwatch.StartNew();

                    // create handler
                    var handler = new OperationHandler(options, classType, methodInfo);
                    lock (handlers)
                    {
                        // fail duplicate entry
                        var path = new RequestPath(className, methodName);
                        if (handlers.ContainsKey(path))
                        {
                            throw new InvalidOperationException(string.Format("same class and method is not allowed, class:{0} method:{1}", className, methodName));
                        }
                        handlers.Add(path, handler);
                    }

                    sw.Stop();
                    options.Logger.RegisiterOperation(handler.ClassName, handler.MethodName, sw.Elapsed.TotalMilliseconds);
                }
            });

            // return readonly operation info
            return(handlers.Select(x => new KeyValuePair <string, OperationInfo>(x.Key.ToString(), new OperationInfo(x.Value))).ToList().AsReadOnly());
        }
 internal OperationInfo(OperationHandler handler)
 {
     this.ClassName = handler.ClassName;
     this.MethodName = handler.MethodName;
     this.AcceptVerbs = handler.AcceptVerb;
     this.Parameters = handler.Arguments;
     this.ReturnType = handler.ReturnType;
     this.ForceUseFormatter = handler.ForceUseFormatter;
 }
        public static void RegisterHandler(Assembly[] hostAssemblies)
        {
            if (Interlocked.Increment(ref alreadyRegistered) != 0) return;

            var contractTypes = hostAssemblies
                .SelectMany(x => x.GetTypes())
                .Where(x => typeof(LightNodeContract).IsAssignableFrom(x));

            Parallel.ForEach(contractTypes, classType =>
            {
                var className = classType.Name;
                foreach (var methodInfo in classType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_"))) continue; // as property

                    var methodName = methodInfo.Name;

                    // ignore default methods
                    if (methodName == "Equals"
                     || methodName == "GetHashCode"
                     || methodName == "GetType"
                     || methodName == "ToString")
                    {
                        continue;
                    }

                    var handler = new OperationHandler();

                    handler.MethodName = methodName;
                    handler.Arguments = methodInfo.GetParameters();
                    handler.ReturnType = methodInfo.ReturnType;

                    foreach (var argument in handler.Arguments)
                    {
                        if (!AllowRequestType.IsAllowType(argument.ParameterType))
                        {
                            throw new InvalidOperationException(string.Format("parameter is not allowed, class:{0} method:{1} paramName:{2} paramType:{3}",
                                className, methodName, 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(handler.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 (handler.ReturnType.IsGenericType && handler.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
                        {
                            handler.HandlerBodyType = HandlerBodyType.AsyncFunc;
                            handler.MethodAsyncFuncBody = lambda.Compile();

                            lock (taskResultExtractors)
                            {
                                if (!taskResultExtractors.ContainsKey(handler.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, handler.ReturnType),
                                                "Result"),
                                            typeof(object)),
                                        taskParameter);

                                    var compiledResultLambda = resultLambda.Compile();

                                    taskResultExtractors[handler.ReturnType] = compiledResultLambda;
                                }
                            }
                        }
                        else
                        {
                            handler.HandlerBodyType = HandlerBodyType.AsyncAction;
                            handler.MethodAsyncActionBody = lambda.Compile();
                        }
                    }
                    else if (handler.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);

                        handler.HandlerBodyType = HandlerBodyType.Action;
                        handler.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);

                        handler.HandlerBodyType = HandlerBodyType.Func;
                        handler.MethodFuncBody = lambda.Compile();
                    }

                    lock (handlers)
                    {
                        // fail duplicate entry
                        var path = new RequestPath(className, methodName);
                        if (handlers.ContainsKey(path))
                        {
                            throw new InvalidOperationException(string.Format("same class and method is not allowed, class:{0} method:{1}", className, methodName));
                        }
                        handlers.Add(path, handler);
                    }
                }
            });
        }