Exemplo n.º 1
0
        private void BuildKnownServiceTypesDictionary()
        {
            Dictionary <string, List <Type> > knownServices = new Dictionary <string, List <Type> >();

            foreach (var serviceType in this.KnownServiceTypes)
            {
                var interfaceServices = RpcBuilderUtil.GetAllServices(serviceType, RpcServiceDefinitionSide.Client, false);
                foreach (var serviceInfo in interfaceServices)
                {
                    if (knownServices.TryGetValue(serviceInfo.FullName, out var services))
                    {
                        if (services.Find(s => s.Equals(serviceInfo.Type)) == null)
                        {
                            services.Add(serviceInfo.Type);
                        }
                    }
                    else
                    {
                        services = new List <Type>
                        {
                            serviceInfo.Type
                        };
                        knownServices.Add(serviceInfo.FullName, services);
                    }
                }
            }

            this.KnownServiceTypesDictionary = ImmutableDictionary.CreateRange(knownServices
                                                                               .Select(p => new KeyValuePair <string, ImmutableArray <Type> >(p.Key, p.Value.ToImmutableArray())));
        }
        public IOwned <RpcObjectRef <TService> > PublishInstance <TService>(IOwned <TService> serviceInstance)
            where TService : class
        {
            if (serviceInstance is null)
            {
                throw new ArgumentNullException(nameof(serviceInstance));
            }
            var allServices = RpcBuilderUtil.GetAllServices(serviceInstance.Value.GetType(), true);

            this.TryRegisterServiceDefinitions(allServices, null);

            var connectionInfo = this.RetrieveConnectionInfo();

            lock (this.syncRoot)
            {
                var serviceInstanceId = RpcObjectId.NewId();

                var publishedServices = this.PublishInstanceCore_Locked(allServices, serviceInstance, serviceInstanceId, false);

                Func <ValueTask> disposeAction = () => this.UnpublishInstanceAsync(serviceInstanceId);

                return(OwnedObject.Create(new RpcObjectRef <TService>(
                                              connectionInfo, serviceInstanceId, publishedServices.ToArray()), disposeAction));
            }
        }
        private static void RpcServiceCollectionExtensions_ServiceRegistered(object?sender, ServiceRegistrationEventArgs e)
        {
            List <RpcServiceInfo> allServices = RpcBuilderUtil.GetAllServices(e.ServiceType, RpcServiceDefinitionSide.Server, true);

            foreach (var rpcService in allServices)
            {
                e.Services.TryAddEnumerable(ServiceDescriptor.Singleton(
                                                typeof(IConfigureOptions <>).MakeGenericType(typeof(GrpcServiceOptions <>).MakeGenericType(typeof(NetGrpcServiceActivator <>).MakeGenericType(rpcService.Type))),
                                                typeof(NetGrpcServiceActivatorConfig <>).MakeGenericType(rpcService.Type)));
            }
        }
Exemplo n.º 4
0
        public IRpcServiceDefinitionsBuilder RegisterImplementation(Type implementationType, IRpcServerOptions?options = null)
        {
            var allServices = RpcBuilderUtil.GetAllServices(implementationType, true);

            foreach (var serviceInfo in allServices)
            {
                this.RegisterService(serviceInfo.Type, implementationType, options);
            }

            return(this);
        }
        public IOwned <RpcObjectRef <TService> > PublishInstance <TService>(Func <IServiceProvider?, RpcObjectId, IOwned <TService> > factory)
            where TService : class
        {
            var allServices = RpcBuilderUtil.GetAllServices(typeof(TService), RpcServiceDefinitionSide.Server, true);

            this.TryRegisterServiceDefinitions(allServices, null);

            var connectionInfo = this.RetrieveConnectionInfo();

            lock (this.syncRoot)
            {
                var objectId = RpcObjectId.NewId();

                var publishedServices = this.PublishInstanceFactoryCore_Locked(allServices, objectId, factory);

                return(OwnedObject.Create(new RpcObjectRef <TService>(
                                              connectionInfo, objectId, publishedServices.ToArray()),
                                          () => this.UnpublishInstanceAsync(objectId)));
            }
        }
        public RpcObjectRef <TService> GetOrPublishInstance <TService>(TService serviceInstance) where TService : class
        {
            if (serviceInstance is null)
            {
                throw new ArgumentNullException(nameof(serviceInstance));
            }

            InstanceKey key;

            lock (this.syncRoot)
            {
                key = new InstanceKey(serviceInstance);
                if (this.serviceImplToId.TryGetValue(key, out var instanceId))
                {
                    return(new RpcObjectRef <TService>(this.connectionInfo, instanceId, this.GetPublishedServices(instanceId).ToArray()));
                }
            }

            // Not published, so we try to register the serviceInstance's service definitions
            // and then publish it.

            var allServices = RpcBuilderUtil.GetAllServices(serviceInstance.GetType(), true);

            this.TryRegisterServiceDefinitions(allServices, null);

            var connectionInfo = this.RetrieveConnectionInfo();

            lock (this.syncRoot)
            {
                // Let's try again.
                if (this.serviceImplToId.TryGetValue(key, out var instanceId))
                {
                    // Somebody beat us to it.
                    return(new RpcObjectRef <TService>(this.connectionInfo, instanceId, this.GetPublishedServices(instanceId).ToArray()));
                }

                var objectId             = RpcObjectId.NewId();
                var newPublishedServices = this.PublishInstanceCore_Locked(allServices, OwnedObject.CreateUnowned(serviceInstance), objectId, true);
                return(new RpcObjectRef <TService>(connectionInfo, objectId, newPublishedServices.ToArray()));
            }
        }
        private void RegisterKnownService(Type serviceType)
        {
            var interfaceServices = RpcBuilderUtil.GetAllServices(serviceType, RpcServiceDefinitionSide.Client, false);

            foreach (var serviceInfo in interfaceServices)
            {
                if (this.knownServices.TryGetValue(serviceInfo.FullName, out var services))
                {
                    if (services.Find(s => s.Equals(serviceInfo.Type)) == null)
                    {
                        services.Add(serviceInfo.Type);
                    }
                }
                else
                {
                    services = new List <Type>();
                    services.Add(serviceInfo.Type);
                    this.knownServices.Add(serviceInfo.FullName, services);
                }
            }
        }
        /// <summary>
        /// Gets all services that should be implemented by the proxy, based on information about the requested <typeparamref name="TService"/>,
        /// the implemented services on the server side, and registered proxy types.
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <param name="implementedServices"></param>
        /// <returns></returns>
        private static List <RpcServiceInfo> GetAllServices <TService>(
            IReadOnlyCollection <string>?implementedServices,
            IReadOnlyDictionary <string, ImmutableArray <Type> >?knownServiceTypes)
        {
            var interfaceServices = RpcBuilderUtil.GetAllServices(typeof(TService), RpcServiceDefinitionSide.Client, false);

            if (implementedServices?.Count > 0)
            {
                // We have information about implemented services on the server side.
                // Make sure that the interfaceServices are actually implemented
                foreach (var interfaceService in interfaceServices)
                {
                    if (!implementedServices.Any(s => s == interfaceService.FullName))
                    {
                        throw new RpcServiceUnavailableException($"Service '{interfaceService.FullName}' is not implemented.");
                    }
                }

                // And add all known service interfaces.
                if (knownServiceTypes != null)
                {
                    foreach (var implementedService in implementedServices)
                    {
                        if (knownServiceTypes.TryGetValue(implementedService, out var knownTypes))
                        {
                            foreach (var serviceType in knownTypes)
                            {
                                if (interfaceServices.Find(s => s.Type.Equals(serviceType)) == null)
                                {
                                    var serviceInfo = RpcBuilderUtil.GetServiceInfoFromType(serviceType);
                                    interfaceServices.Add(serviceInfo);    // serviceInfo is not null when throwOnError is true.
                                }
                            }
                        }
                    }
                }
            }

            return(interfaceServices);
        }
        public IOwned <RpcSingletonRef <TService> > PublishSingleton <TService>(IOwned <TService> singletonService) where TService : class
        {
            if (singletonService == null)
            {
                throw new ArgumentNullException(nameof(singletonService));
            }

            var allServices = RpcBuilderUtil.GetAllServices(typeof(TService), false);

            this.TryRegisterServiceDefinitions(allServices, null);

            var publishedServices = this.VerifyPublishedServices(allServices);

            var connectionInfo = this.RetrieveConnectionInfo();

            lock (this.syncRoot)
            {
                var instanceKey = new InstanceKey(singletonService.Value);

                foreach (var serviceType in publishedServices.ServiceTypes)
                {
                    if (this.singletonServiceTypeToServiceImpl.ContainsKey(serviceType) || this.singletonServiceTypeToFactory.ContainsKey(serviceType))
                    {
                        throw new RpcDefinitionException($"A singleton for the type '{serviceType}' has already been published.");
                    }
                }

                this.singletonTypeToPublishedServices.Add(typeof(TService), publishedServices);
                var publishedInstance = new PublishedInstance(singletonService);
                foreach (var serviceType in publishedServices.ServiceTypes)
                {
                    this.singletonServiceTypeToServiceImpl.Add(serviceType, publishedInstance);
                }
            }

            return(OwnedObject.Create(new RpcSingletonRef <TService>(
                                          connectionInfo),
                                      () => this.UnpublishSingletonAsync <TService>()));
        }
Exemplo n.º 10
0
        private static void AddServiceRegistration(IServiceCollection services, IRpcServiceRegistration registration, Action <RpcServerOptions>?configureOptions)
        {
            // Could have been added as transient, since it's only used once during initialization. However,
            // that would cause a factory delegate to be kept in memory, which probably consumes as much memory as
            // the RpcServiceRegistration instance.
            services.AddSingleton(registration);

            // Avoid getting service types unless someone is interested in the registered services
            // Enumerating services may be slow.
            if (configureOptions != null)
            {
                foreach (var registeredType in registration.GetServiceTypes(RpcServiceDefinitionSide.Server))
                {
                    List <RpcServiceInfo> allServices = RpcBuilderUtil.GetAllServices(registeredType.ServiceType, RpcServiceDefinitionSide.Server, true);
                    foreach (var rpcService in allServices)
                    {
                        var configOptionsMethod = ConfigureOptionsMethod.MakeGenericMethod(rpcService.Type);
                        configOptionsMethod.Invoke(null, new object[] { services, configureOptions });

                        ServiceRegistered?.Invoke(null, new ServiceRegistrationEventArgs(services, rpcService.Type));
                    }
                }
            }
        }
Exemplo n.º 11
0
        public IRpcServiceDefinitionsBuilder RegisterService(Type serviceType, Type?implementationType = null, IRpcServerOptions?options = null)
        {
            if (serviceType is null)
            {
                throw new ArgumentNullException(nameof(serviceType));
            }
            if (implementationType != null && !serviceType.IsAssignableFrom(implementationType))
            {
                throw new ArgumentException("Implementation type must implement service type.", nameof(implementationType));
            }


            this.CheckFrozen();

            List <RpcServiceInfo> allServices = RpcBuilderUtil.GetAllServices(serviceType, implementationType, RpcServiceDefinitionSide.Server, false);

            var newServices = new List <RpcServiceInfo>();

            Type[]? newServiceTypes = null;
            lock (this.syncRoot)
            {
                foreach (var service in allServices)
                {
                    if (!this.registeredServiceTypes.TryGetValue(service.Type, out var currRegistration))
                    {
                        this.registeredServiceTypes.Add(service.Type, new RegisteredServiceType(implementationType, options));

                        if (this.registeredServices.TryGetValue(service.FullName, out var existingServiceType))
                        {
                            if (!service.Type.Equals(existingServiceType))
                            {
                                // TODO: This should be allowed, as long as the service operations and options don't collide.
                                throw new RpcDefinitionException($"Service '{service.FullName}' already registered using the interface '{existingServiceType}'");
                            }

                            // TODO: This will no longer happen, since registeredServiceTypes check will prevent it from getting here.
                            continue;
                        }
                        else
                        {
                            newServices.Add(service);
                        }
                    }
                    else
                    {
                        if (currRegistration.ImplementationType != implementationType)
                        {
                            throw new RpcDefinitionException($"Service '{serviceType}' already registered with a different implementation type.");
                        }

                        // Type already registered, but let's update the service options if provided.
                        if (options != null)
                        {
                            this.registeredServiceTypes[service.Type] = new RegisteredServiceType(implementationType, options);
                        }

                        continue;
                    }
                }

                if (newServices.Count > 0)
                {
                    newServiceTypes = new Type[newServices.Count];
                    int di = 0;
                    foreach (var service in newServices)
                    {
                        newServiceTypes[di++] = service.Type;
                        this.registeredServices.Add(service.FullName, service.Type);
                    }
                }
            }

            if (newServiceTypes != null && newServiceTypes.Length > 0)
            {
                this.ServicesRegistered?.Invoke(this, new RpcServicesEventArgs(newServiceTypes));
            }

            return(this);
        }
Exemplo n.º 12
0
        private (TService, Mock <TestCallInvoker>) CreateServiceInstance <TService>() where TService : class
        {
            var(moduleBuilder, definedTypes) = this.CreateModuleBuilder();
            var proxyBuilder = new RpcServiceProxyBuilder <GrpcProxyBase, GrpcProxyMethod>(RpcBuilderUtil.GetAllServices <TService>(true), moduleBuilder, definedTypes);

            var(proxyType, proxyMethods) = proxyBuilder.BuildObjectProxyType(new Type[] { typeof(GrpcProxyArgs), typeof(GrpcProxyMethod[]) });

            ValidateProxyType <TService>(proxyType);

            var factory = RpcServiceProxyBuilder <GrpcProxyBase, GrpcProxyMethod> .CreateObjectProxyFactory <GrpcProxyArgs>(proxyType);

            var callInvokerMock = new Mock <TestCallInvoker>(MockBehavior.Strict);
            var connectionMock  = new Mock <IRpcConnection>(MockBehavior.Strict);

            connectionMock.Setup(m => m.Options).Returns(ImmutableRpcClientOptions.Empty);
            var serializer = new ProtobufRpcSerializer();

            var args = new GrpcProxyArgs
                       (
                objectId: RpcObjectId.NewId(),
                connection: connectionMock.Object,
                callInvoker: callInvokerMock.Object,
                serializer: serializer,
                methodsCache: new GrpcMethodsCache(serializer),
                implementedServices: null,
                syncContext: null
                       );

            var serviceInstance = factory(args, proxyMethods);

            return((TService)(object)serviceInstance, callInvokerMock);
        }