Example #1
0
        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();
            }
        }
Example #2
0
        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();
            }
        }
Example #3
0
        internal static HubDescriptor CreateIfPossible(Type type)
        {
            HubKind kind;
            if (typeof(IHub).IsAssignableFrom(type))
            {
                kind = HubKind.Client;
            }
            else if (typeof(ServerHub).IsAssignableFrom(type))
            {
                kind = HubKind.Server;
            }
            else if (typeof(ReceiveServerHub).IsAssignableFrom(type))
            {
                kind = HubKind.ReceiveServer;
            }
            else
            {
                return null;
            }

            if (type.IsAbstract) return null;
            if (type.GetCustomAttribute<IgnoreOperationAttribute>(true) != null) return null; // ignore

            var className = type.Name;
            if (!type.GetConstructors().Any(x => x.GetParameters().Length == 0))
            {
                throw new InvalidOperationException(string.Format("Hub needs parameterless constructor, class:{0}", type.FullName));
            }

            var hubAttr = type.GetCustomAttributes<HubAttribute>(false).FirstOrDefault();
            if (hubAttr == null)
            {
                throw new InvalidOperationException(string.Format("Hub needs HubAttribute, class:{0}", type.FullName));
            }
            var clientType = (kind == HubKind.Client)
                ? FindHubClientType(type)
                : typeof(INoClient);

            var tags = new HashSet<string>(type.GetCustomAttributes<HubTag>(true).SelectMany(x => x.Tags));

            var hub = new HubDescriptor()
            {
                HubName = className,
                HubType = type,
                ClientType = clientType,
                HubKind = kind,
                HubId = hubAttr.HubId,
                CanExecute = true,
                HubTags = new ReadOnlyHashSet<string>(tags)
            };

            foreach (var methodInfo in type.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 MethodDescriptor(hub, methodInfo);

                if (hub.Methods.ContainsKey(handler.OperationCode))
                {
                    throw new InvalidOperationException(string.Format("same operationCode is not allowed, class:{0} method:{1} opCode:{2}", className, methodName, handler.OperationCode));
                }
                else
                {
                    hub.Methods.Add(handler.OperationCode, handler);
                }
            }

            return hub;
        }
Example #4
0
 internal OperationContext(HubDescriptor hub, MethodDescriptor method, IPhotonWirePeer peer, OperationRequest operationRequest, SendParameters sendParameters, DateTime timestamp)
     : this(hub.HubId, peer, operationRequest, sendParameters, timestamp)
 {
     this.Hub    = hub;
     this.Method = method;
 }
Example #5
0
 internal HubContext(HubDescriptor hub, SendParameters sendParameters)
 {
     this.Hub            = hub;
     this.SendParameters = sendParameters;
 }
Example #6
0
 internal HubContext(HubDescriptor hub)
 {
     this.Hub            = hub;
     this.SendParameters = default(SendParameters);
 }