private IReadOnlyList <RpcPublishedSingleton> GetPublishedSingletonsList(IServiceProvider?serviceProvider)
        {
            // TODO: This method is not particularily fast. Maybe add some caching? Or retrieve information from service stubs.
            var publishedSingletons = new List <RpcPublishedSingleton>();

            foreach (var type in this.server.ServiceActivator.GetPublishedSingletons())
            {
                var serviceInfo = RpcBuilderUtil.TryGetServiceInfoFromType(type);
                if (serviceInfo != null)
                {
                    IOptions <RpcServerOptions>?options = null;

                    if (serviceProvider != null)
                    {
                        options = (IOptions <RpcServerOptions>?)serviceProvider.GetService(
                            typeof(IOptions <>).MakeGenericType(
                                typeof(RpcServiceOptions <>).MakeGenericType(type)));
                    }

                    var registeredOptions = this.server.ServiceDefinitionsProvider.GetServiceOptions(type);
                    if (options?.Value?.AllowDiscovery ?? registeredOptions?.AllowDiscovery ?? true)
                    {
                        publishedSingletons.Add(new RpcPublishedSingleton
                        {
                            Name = serviceInfo.FullName
                        });
                    }
                }
            }

            return(publishedSingletons);
        }
Example #2
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));
            }
        }
Example #4
0
        public RpcServiceInfo?GetRegisteredServiceInfo(Type serviceType)
        {
            if (this.registeredServiceTypes.TryGetValue(serviceType, out var registration))
            {
                return(RpcBuilderUtil.GetServiceInfoFromType(serviceType, registration.ImplementationType));
            }

            return(null);
        }
        public IReadOnlyList <object> GenerateMethodStubs <TService>(IRpcServerCore rpcServer) where TService : class
        {
            var builder = new GrpcServiceStubBuilder <TService>(RpcBuilderUtil.GetServiceInfoFromType(typeof(TService)), null);

            var binder = new TestGrpcMethodBinder();

            builder.GenerateOperationHandlers(rpcServer, binder);

            return(binder.stubs);
        }
Example #6
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);
        }
        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)));
            }
        }
        /// <summary>
        /// Adds service specific options to an <see cref="IRpcServerBuilder"/>.
        /// </summary>
        /// <typeparam name="TService">The service type to configure.</typeparam>
        /// <param name="rpcBuilder">The <see cref="IRpcServerBuilder"/>.</param>
        /// <param name="configure">A callback to configure the service options.</param>
        /// <returns>The same instance of the <see cref="IRpcServerBuilder"/> for chaining.</returns>
        public static IRpcServerBuilder AddServiceOptions <TService>(this IRpcServerBuilder rpcBuilder,
                                                                     Action <RpcServiceOptions <TService> > configure) where TService : class
        {
            if (rpcBuilder == null)
            {
                throw new ArgumentNullException(nameof(rpcBuilder));
            }

            // GetServiceInfoFromType will throw if TService is not an RPC service (replace with an IsRpcService method)
            RpcBuilderUtil.GetServiceInfoFromType(typeof(TService));

            rpcBuilder.Services.Configure(configure);

            Rpc.ServiceCollectionExtensions.NotifyServiceRegistered <TService>(rpcBuilder.Services);
            return(rpcBuilder);
        }
Example #9
0
        /// <summary>
        /// Generates the RPC method definitions and stub handlers and adds them to the provided methodBinder.
        /// </summary>
        /// <returns></returns>
        public RpcStub <TService> GenerateOperationHandlers(IRpcServerCore server, TMethodBinder methodBinder)
        {
            this.serviceStub = this.CreateServiceStub(server);

            foreach (var memberInfo in RpcBuilderUtil.EnumOperationHandlers(this.ServiceInfo, true))
            {
                if (memberInfo is RpcEventInfo eventInfo)
                {
                    this.AddEventHandler(this.serviceStub, eventInfo, methodBinder);
                }
                else if (memberInfo is RpcOperationInfo opInfo)
                {
                    switch (opInfo.MethodType)
                    {
                    case RpcMethodType.Unary:
                        this.CheckMethod(opInfo);
                        this.AddUnaryMethod(this.serviceStub, opInfo, methodBinder);
                        break;

                    case RpcMethodType.ServerStreaming:
                        this.CheckMethod(opInfo);
                        if (opInfo.CallbackParameterIndex == null)
                        {
                            // No callback. Implement using IAsyncEnumerable
                            this.AddServerStreamingMethod(this.serviceStub, opInfo, methodBinder);
                        }
                        else
                        {
                            // Implement using callback
                            this.AddCallbackMethod(this.serviceStub, opInfo, methodBinder);
                        }
                        break;

                    default:
                        throw new NotImplementedException();
                    }
                }
                else
                {
                    throw new NotImplementedException();
                }
            }

            return(this.serviceStub);
        }
        private void WriteProto(Assembly assembly, TextWriter output)
        {
            var dynamicModuleBuilder = CreateModuleBuilder("RequestResponseTypes", "RequestResponseTypes.dll", false);

            StringBuilder serviceBuilder = new StringBuilder();

            RuntimeTypeModel typeModel = RuntimeTypeModel.Create();

            foreach (var exportedType in assembly.GetExportedTypes())
            {
                var serviceInfo = RpcBuilderUtil.TryGetServiceInfoFromType(exportedType);
                if (serviceInfo != null && serviceInfo.DefinitionSide != RpcServiceDefinitionSide.Client)
                {
                    serviceBuilder.AppendLine();
                    serviceBuilder.AppendLine($"service {serviceInfo.Name} {{");

                    foreach (var rpcMemberInfo in RpcBuilderUtil.EnumOperationHandlers(serviceInfo, true))
                    {
                        if (rpcMemberInfo is RpcOperationInfo rpcOpInfo)
                        {
                            var namedRequestType  = this.CreateRequestType(dynamicModuleBuilder, rpcOpInfo);
                            var namedResponseType = this.CreateResponseType(dynamicModuleBuilder, rpcOpInfo);
                            if (namedRequestType == null || namedResponseType == null)
                            {
                                continue;   // Should probably stop generator.
                            }

                            typeModel.Add(namedRequestType, true);
                            typeModel.Add(namedResponseType, true);

                            serviceBuilder.AppendLine(
                                $"\trpc {rpcOpInfo.Name} ({namedRequestType.Name}) returns ({namedResponseType.Name});");
                        }
                    }

                    serviceBuilder.AppendLine("}");
                }
            }

            string schema = typeModel.GetSchema(null, ProtoSyntax.Proto3);

            output.WriteLine(schema);
            output.WriteLine(serviceBuilder.ToString());
        }
        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>()));
        }
Example #16
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));
                    }
                }
            }
        }
Example #17
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);
        }
        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);
        }
Example #19
0
 public GrpcServiceStubBuilder(RpcServiceOptions <TService>?options) :
     this(RpcBuilderUtil.GetServiceInfoFromType(typeof(TService)), options)
 {
 }
Example #20
0
 public RpcFaultAttribute(Type faultType)
 {
     this.FaultType = faultType;
     this.FaultCode = RpcBuilderUtil.RetrieveFaultCode(faultType);
 }