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))); } }
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>())); }
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)); } } } }
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); }