Ejemplo n.º 1
0
        public static MagicOnionServiceDefinition BuildServerServiceDefinition(IEnumerable <Type> targetTypes, MagicOnionOptions option)
        {
            option.RegisterOptionToServiceLocator();

            var builder              = ServerServiceDefinition.CreateBuilder();
            var handlers             = new HashSet <MethodHandler>();
            var streamingHubHandlers = new List <StreamingHubHandler>();

            var types = targetTypes
                        .Where(x => typeof(IServiceMarker).IsAssignableFrom(x))
                        .Where(x => !x.GetTypeInfo().IsAbstract)
                        .Where(x => x.GetCustomAttribute <IgnoreAttribute>(false) == null)
                        .Concat(SupplyEmbeddedServices(option))
                        .ToArray();

            option.MagicOnionLogger.BeginBuildServiceDefinition();
            var sw = Stopwatch.StartNew();

            try
            {
                Parallel.ForEach(types, /* new ParallelOptions { MaxDegreeOfParallelism = 1 }, */ 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));
                    }

                    var isStreamingHub = typeof(IStreamingHubMarker).IsAssignableFrom(classType);
                    HashSet <StreamingHubHandler> tempStreamingHubHandlers = null;
                    if (isStreamingHub)
                    {
                        tempStreamingHubHandlers = new HashSet <StreamingHubHandler>();
                    }

                    var inheritInterface = classType.GetInterfaces()
                                           .First(x => x.IsGenericType && x.GetGenericTypeDefinition() == (isStreamingHub ? typeof(IStreamingHub <,>) : typeof(IService <>)))
                                           .GenericTypeArguments[0];
                    var interfaceMap = classType.GetInterfaceMap(inheritInterface);

                    for (int i = 0; i < interfaceMap.TargetMethods.Length; ++i)
                    {
                        var methodInfo = interfaceMap.TargetMethods[i];
                        var methodName = interfaceMap.InterfaceMethods[i].Name;

                        if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_")))
                        {
                            continue;
                        }
                        if (methodInfo.GetCustomAttribute <IgnoreAttribute>(false) != null)
                        {
                            continue;                                                                // ignore
                        }
                        // ignore default methods
                        if (methodName == "Equals" ||
                            methodName == "GetHashCode" ||
                            methodName == "GetType" ||
                            methodName == "ToString" ||
                            methodName == "WithOptions" ||
                            methodName == "WithHeaders" ||
                            methodName == "WithDeadline" ||
                            methodName == "WithCancellationToken" ||
                            methodName == "WithHost"
                            )
                        {
                            continue;
                        }

                        // register for StreamingHub
                        if (isStreamingHub && methodName != "Connect")
                        {
                            var streamingHandler = new StreamingHubHandler(option, classType, methodInfo);
                            if (!tempStreamingHubHandlers.Add(streamingHandler))
                            {
                                throw new InvalidOperationException($"Method does not allow overload, {className}.{methodName}");
                            }
                            continue;
                        }
                        else
                        {
                            // create handler
                            var handler = new MethodHandler(option, classType, methodInfo, methodName);
                            lock (builder)
                            {
                                if (!handlers.Add(handler))
                                {
                                    throw new InvalidOperationException($"Method does not allow overload, {className}.{methodName}");
                                }
                                handler.RegisterHandler(builder);
                            }
                        }
                    }

                    if (isStreamingHub)
                    {
                        var connectHandler = new MethodHandler(option, classType, classType.GetMethod("Connect"), "Connect");
                        lock (builder)
                        {
                            if (!handlers.Add(connectHandler))
                            {
                                throw new InvalidOperationException($"Method does not allow overload, {className}.Connect");
                            }
                            connectHandler.RegisterHandler(builder);
                        }

                        lock (streamingHubHandlers)
                        {
                            streamingHubHandlers.AddRange(tempStreamingHubHandlers);
                            StreamingHubHandlerRepository.RegisterHandler(connectHandler, tempStreamingHubHandlers.ToArray());
                            IGroupRepositoryFactory factory;
                            var attr = classType.GetCustomAttribute <GroupConfigurationAttribute>(true);
                            if (attr != null)
                            {
                                factory = attr.Create();
                            }
                            else
                            {
                                factory = option.DefaultGroupRepositoryFactory;
                            }
                            StreamingHubHandlerRepository.AddGroupRepository(connectHandler, factory.CreateRepository(option.ServiceLocator));
                        }
                    }
                });
            }
            catch (AggregateException agex)
            {
                ExceptionDispatchInfo.Capture(agex.InnerExceptions[0]).Throw();
            }

            var result = new MagicOnionServiceDefinition(builder.Build(), handlers.ToArray(), streamingHubHandlers.ToArray());

            sw.Stop();
            option.MagicOnionLogger.EndBuildServiceDefinition(sw.Elapsed.TotalMilliseconds);

            return(result);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Search MagicOnion service from target types.
        /// </summary>
        /// <param name="serviceProvider">The service provider is used to resolve dependencies</param>
        /// <param name="targetTypes">The types to be search for services</param>
        /// <param name="options">The options for MagicOnion server</param>
        public static MagicOnionServiceDefinition BuildServerServiceDefinition(IServiceProvider serviceProvider, IEnumerable <Type> targetTypes, MagicOnionOptions options)
        {
            var handlers             = new HashSet <MethodHandler>();
            var streamingHubHandlers = new List <StreamingHubHandler>();

            var types = targetTypes
                        .Where(x => typeof(IServiceMarker).IsAssignableFrom(x))
                        .Where(x => !x.GetTypeInfo().IsAbstract)
                        .Where(x => x.GetCustomAttribute <IgnoreAttribute>(false) == null)
                        .ToArray();

            var logger = serviceProvider.GetRequiredService <IMagicOnionLogger>();

            logger.BeginBuildServiceDefinition();
            var sw = Stopwatch.StartNew();

            try
            {
                foreach (var classType in types)
                {
                    var className = classType.Name;
                    if (!classType.GetConstructors().Any(x => x.GetParameters().Length == 0))
                    {
                        // supports paramaterless constructor after v2.1(DI support).
                        // throw new InvalidOperationException(string.Format("Type needs parameterless constructor, class:{0}", classType.FullName));
                    }

                    var isStreamingHub = typeof(IStreamingHubMarker).IsAssignableFrom(classType);
                    HashSet <StreamingHubHandler>?tempStreamingHubHandlers = null;
                    if (isStreamingHub)
                    {
                        tempStreamingHubHandlers = new HashSet <StreamingHubHandler>();
                    }

                    var inheritInterface = classType.GetInterfaces()
                                           .First(x => x.IsGenericType && x.GetGenericTypeDefinition() == (isStreamingHub ? typeof(IStreamingHub <,>) : typeof(IService <>)))
                                           .GenericTypeArguments[0];

                    if (!inheritInterface.IsAssignableFrom(classType))
                    {
                        throw new NotImplementedException($"Type '{classType.FullName}' has no implementation of interface '{inheritInterface.FullName}'.");
                    }

                    var interfaceMap = classType.GetInterfaceMap(inheritInterface);

                    for (int i = 0; i < interfaceMap.TargetMethods.Length; ++i)
                    {
                        var methodInfo = interfaceMap.TargetMethods[i];
                        var methodName = interfaceMap.InterfaceMethods[i].Name;

                        if (methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("set_") || methodInfo.Name.StartsWith("get_")))
                        {
                            continue;
                        }
                        if (methodInfo.GetCustomAttribute <IgnoreAttribute>(false) != null)
                        {
                            continue;                                                                // ignore
                        }
                        // ignore default methods
                        if (methodName == "Equals" ||
                            methodName == "GetHashCode" ||
                            methodName == "GetType" ||
                            methodName == "ToString" ||
                            methodName == "WithOptions" ||
                            methodName == "WithHeaders" ||
                            methodName == "WithDeadline" ||
                            methodName == "WithCancellationToken" ||
                            methodName == "WithHost"
                            )
                        {
                            continue;
                        }

                        // register for StreamingHub
                        if (isStreamingHub && methodName != "Connect")
                        {
                            var streamingHandler = new StreamingHubHandler(classType, methodInfo, new StreamingHubHandlerOptions(options), serviceProvider);
                            if (!tempStreamingHubHandlers !.Add(streamingHandler))
                            {
                                throw new InvalidOperationException($"Method does not allow overload, {className}.{methodName}");
                            }
                            continue;
                        }
                        else
                        {
                            // create handler
                            var handler = new MethodHandler(classType, methodInfo, methodName, new MethodHandlerOptions(options), serviceProvider);
                            if (!handlers.Add(handler))
                            {
                                throw new InvalidOperationException($"Method does not allow overload, {className}.{methodName}");
                            }
                        }
                    }

                    if (isStreamingHub)
                    {
                        var connectHandler = new MethodHandler(classType, classType.GetMethod("Connect") !, "Connect", new MethodHandlerOptions(options), serviceProvider);
                        if (!handlers.Add(connectHandler))
                        {
                            throw new InvalidOperationException($"Method does not allow overload, {className}.Connect");
                        }

                        streamingHubHandlers.AddRange(tempStreamingHubHandlers !);
                        StreamingHubHandlerRepository.RegisterHandler(connectHandler, tempStreamingHubHandlers.ToArray());
                        IGroupRepositoryFactory factory;
                        var attr = classType.GetCustomAttribute <GroupConfigurationAttribute>(true);
                        if (attr != null)
                        {
                            factory = attr.Create();
                        }
                        else
                        {
                            factory = serviceProvider.GetRequiredService <IGroupRepositoryFactory>();
                        }
                        StreamingHubHandlerRepository.AddGroupRepository(connectHandler, factory.CreateRepository(options.SerializerOptions, logger));
                    }
                }
            }
            catch (AggregateException agex)
            {
                ExceptionDispatchInfo.Capture(agex.InnerExceptions[0]).Throw();
            }

            var result = new MagicOnionServiceDefinition(handlers.ToArray(), streamingHubHandlers.ToArray());

            sw.Stop();
            logger.EndBuildServiceDefinition(sw.Elapsed.TotalMilliseconds);

            return(result);
        }