private ServiceAndMethodDefinitions Resolve(ServiceId serviceId, MethodId methodId, bool assumeExternal = false) { var result = new ServiceAndMethodDefinitions(); if (_serviceResolver.TryResolve(serviceId, out var serviceRef)) { result.Service = serviceRef.Definition; // NOTE: system services are not unique within a multi-service ecosystem, thus must // use the configuration of the calling (proxy) service without any specific method. // Otherwise, a continuation can be sent to a wrong instance of a system service. if (result.Service.Type == ServiceType.System && !string.IsNullOrEmpty(serviceId.Proxy)) { return(Resolve(new ServiceId { Name = serviceId.Proxy }, null, assumeExternal)); } result.Method = methodId == null ? null : _methodResolver.Resolve(result.Service, methodId).Definition; } else if (assumeExternal) { var externalServiceDefinition = _externalCommunicationModel.GetOrAddService(serviceId); var externalMethodDefinition = methodId == null ? null : externalServiceDefinition.GetOrAddMethod(methodId); result.Service = externalServiceDefinition; result.Method = externalMethodDefinition; } else { throw new ServiceResolveException(serviceId); } return(result); }
public static IServiceReference Resolve(this IServiceResolver resolver, ServiceId serviceId) { if (resolver.TryResolve(serviceId, out var serviceReference)) { return(serviceReference); } throw new ServiceResolveException(serviceId); }
public IEventPublisher GetPublisher(ServiceId serviceId, EventId eventId) { if (_eventingMethods.Count == 0) { throw new CommunicationMethodNotFoundException("There are no communication methods registered."); } IServiceDefinition serviceDefinition; IEventDefinition eventDefinition; if (_serviceResolver.TryResolve(serviceId, out var serviceRef)) { serviceDefinition = serviceRef.Definition; eventDefinition = _eventResolver.Resolve(serviceDefinition, eventId).Definition; } else { throw new ServiceResolveException(serviceId); } lock (_publisherMap) { if (_publisherMap.TryGetValue(eventDefinition, out var cachedCommunicator)) { return(cachedCommunicator); } } var localSettings = _communicationSettingsProvider.GetEventSettings(eventDefinition, external: false); var externalSettings = _communicationSettingsProvider.GetEventSettings(eventDefinition, external: true); var localEventingMethod = GetEventingMethod(localSettings.CommunicationType); var externalEventingMethod = GetEventingMethod(externalSettings.CommunicationType); var localPublisher = localEventingMethod.CreateEventPublisher(GetConfiguration(eventDefinition)); var publisher = localPublisher; if (externalEventingMethod.Type != localEventingMethod.Type) { var externalPublisher = externalEventingMethod.CreateEventPublisher(GetConfiguration(eventDefinition, forceExternal: true)); publisher = new MulticastEventPublisher(localPublisher, externalPublisher); } lock (_publisherMap) { if (_publisherMap.TryGetValue(eventDefinition, out var cachedPublisher)) { (publisher as IDisposable)?.Dispose(); return(cachedPublisher); } _publisherMap.Add(eventDefinition, publisher); return(publisher); } }
private async void InvokeInBackground(MethodInvocationData data, PublishPreferences preferences) { if (!_serviceResolver.TryResolve(data.Service, out var service) || service.Definition.Type == Modeling.ServiceType.External) { var communicator = _communicatorProvider.GetCommunicator(data.Service, data.Method, assumeExternal: true); await communicator.InvokeAsync(data, default); } else if (!preferences.SkipLocalSubscribers) { var message = new HttpCommunicatorMessage { IsRetry = false }; await _localMethodRunner.RunAsync(data, message); } }
private bool IsExternal(EventDescriptor eventDesc) { return(!_serviceResolver.TryResolve(eventDesc.Service, out var serviceReference) || serviceReference.Definition.Type == Modeling.ServiceType.External); }
public Task <IEnumerable <IMessageListener> > StartListeningAsync( IConfiguration configuration, IServiceDefinition serviceDefinition, IDictionary <IEventDefinition, IConfiguration> eventConfigMap, CancellationToken ct) { // TODO: there are many scenarios that are not supported by the following code. // For example, exchange's connection is different from services' queues. var baseConnectionSettings = new ConnectionSettings(); configuration.Bind(baseConnectionSettings); var baseConnection = _connectionManager.GetConnection(baseConnectionSettings); var baseChannel = baseConnection.CreateModel(); foreach (var eventDefinition in serviceDefinition.Events) { if (!eventConfigMap.TryGetValue(eventDefinition, out var eventConfiguration)) { eventConfiguration = configuration; } var listenerSettings = RabbitMQCommunicationMethod.CreateEventsDefaultSettings(); eventConfiguration.Bind(listenerSettings); var exchangeName = listenerSettings.ExchangeName .Replace("{serviceName}", serviceDefinition.Name) .Replace("{eventName}", eventDefinition.Name); // TODO: declare once? what's the penalty? baseChannel.ExchangeDeclare( exchangeName, type: "fanout", durable: true, autoDelete: false, arguments: null); var eventDesc = new EventDescriptor { Service = new ServiceId { Name = serviceDefinition.Name }, Event = _eventIdProvider.GetId(eventDefinition.EventInfo) }; foreach (var subscriber in _eventSubscriber.GetSubscribers(eventDesc)) { if (!_serviceResolver.TryResolve(subscriber.Service, out var subscriberServiceReference)) { continue; } if (!_methodResolver.TryResolve(subscriberServiceReference.Definition, subscriber.Method, out var subscriberMethodReference)) { continue; } var subscriberMethodConfiguration = _communicationModelConfiguration.GetMethodConfiguration(subscriberMethodReference.Definition, "communication"); var subscriberSettings = RabbitMQCommunicationMethod.CreateMethodsDefaultSettings(); subscriberMethodConfiguration.Bind(subscriberSettings); var subscriberQueueName = subscriberSettings.QueueName .Replace("{serviceName}", subscriberServiceReference.Definition.Name) .Replace("{methodName}", subscriberMethodReference.Definition.Name); // TODO: declare once? what's the penalty? baseChannel.QueueBind( queue: subscriberQueueName, exchange: exchangeName, routingKey: "", arguments: null); } } // No direct listeners to RabbitMQ Exchanges, just configure exchange-queue bindings. // TODO: if events (or subscribers) use a different connection, // need to create a queue and a listener in that RabbitMQ instance. return(Task.FromResult <IEnumerable <IMessageListener> >(Array.Empty <IMessageListener>())); }
public async Task StartAsync(CancellationToken ct) { foreach (var serviceDefinition in _communicationModel.Services) { if (serviceDefinition.Type == ServiceType.External) { var serviceConfig = _communicationModelConfiguration.GetEventsConfiguration(serviceDefinition, CommunicationSectionName); var serviceCommunicationType = GetCommunicationType(serviceConfig); var serviceId = new ServiceId { Name = serviceDefinition.Name }; var anySubscriberToAnyEvent = false; var eventOverridesMap = new Dictionary <string, Dictionary <IEventDefinition, IConfiguration> >(StringComparer.OrdinalIgnoreCase); foreach (var eventDefinition in serviceDefinition.Events) { var eventId = _eventIdProvider.GetId(eventDefinition.EventInfo); var eventDesc = new EventDescriptor { Service = serviceId, Event = eventId }; var subscribers = _eventSubscriber.GetSubscribers(eventDesc).ToList(); if (subscribers.Count == 0) { continue; } var anySubscriberToThisEvent = false; foreach (var subscriber in subscribers) { if (_serviceResolver.TryResolve(subscriber.Service, out _)) { anySubscriberToThisEvent = true; anySubscriberToAnyEvent = true; break; } } if (!anySubscriberToThisEvent) { continue; } if (_communicationModelConfiguration .GetEventOverrideLevels(eventDefinition, CommunicationSectionName) .HasFlag(ConfigOverrideLevels.Primitive)) { var eventConfig = _communicationModelConfiguration.GetEventConfiguration(eventDefinition); var eventCommunicationType = GetCommunicationType(eventConfig); if (!eventOverridesMap.TryGetValue(eventCommunicationType, out var configMap)) { configMap = new Dictionary <IEventDefinition, IConfiguration>(); eventOverridesMap.Add(eventCommunicationType, configMap); } configMap.Add(eventDefinition, eventConfig); } } if (anySubscriberToAnyEvent) { if (!eventOverridesMap.TryGetValue(serviceCommunicationType, out var configMap)) { configMap = new Dictionary <IEventDefinition, IConfiguration>(); } await StartListeningEventsAsync(serviceCommunicationType, serviceDefinition, serviceConfig, configMap, ct); var extraCommTypes = eventOverridesMap.Keys.Where(c => !string.Equals(c, serviceCommunicationType, StringComparison.OrdinalIgnoreCase)); foreach (var extraCommType in extraCommTypes) { configMap = eventOverridesMap[extraCommType]; await StartListeningEventsAsync(extraCommType, serviceDefinition, serviceConfig, configMap, ct); } } } else { var methodOverridesMap = new Dictionary <string, Dictionary <IMethodDefinition, IConfiguration> >(StringComparer.OrdinalIgnoreCase); var eventOverridesMap = new Dictionary <string, Dictionary <IEventDefinition, IConfiguration> >(StringComparer.OrdinalIgnoreCase); foreach (var methodDefinition in serviceDefinition.Methods) { if (_communicationModelConfiguration .GetMethodOverrideLevels(methodDefinition, CommunicationSectionName) .HasFlag(ConfigOverrideLevels.Primitive)) { var methodConfig = _communicationModelConfiguration.GetMethodConfiguration(methodDefinition); var methodCommunicationType = GetCommunicationType(methodConfig); if (!methodOverridesMap.TryGetValue(methodCommunicationType, out var configMap)) { configMap = new Dictionary <IMethodDefinition, IConfiguration>(); methodOverridesMap.Add(methodCommunicationType, configMap); } configMap.Add(methodDefinition, methodConfig); } } foreach (var eventDefinition in serviceDefinition.Events) { if (_communicationModelConfiguration .GetEventsOverrideLevels(serviceDefinition, CommunicationSectionName) .HasFlag(ConfigOverrideLevels.Primitive)) { var eventConfig = _communicationModelConfiguration.GetEventConfiguration(eventDefinition); var eventCommunicationType = GetCommunicationType(eventConfig); if (!eventOverridesMap.TryGetValue(eventCommunicationType, out var configMap)) { configMap = new Dictionary <IEventDefinition, IConfiguration>(); eventOverridesMap.Add(eventCommunicationType, configMap); } configMap.Add(eventDefinition, eventConfig); } } var hasQueriesOverride = (_communicationModelConfiguration .GetQueriesOverrideLevels(serviceDefinition, CommunicationSectionName) & (ConfigOverrideLevels.BasePrimitives | ConfigOverrideLevels.ServiceTypePrimitives | ConfigOverrideLevels.ServicePrimitives)) != default; var hasCommandsOverride = (_communicationModelConfiguration .GetCommandsOverrideLevels(serviceDefinition, CommunicationSectionName) & (ConfigOverrideLevels.BasePrimitives | ConfigOverrideLevels.ServiceTypePrimitives | ConfigOverrideLevels.ServicePrimitives)) != default; if (hasQueriesOverride || hasCommandsOverride) { var allQueriesConfig = _communicationModelConfiguration.GetQueriesConfiguration(serviceDefinition, CommunicationSectionName); var allQueriesCommunicationType = GetCommunicationType(allQueriesConfig); if (!methodOverridesMap.TryGetValue(allQueriesCommunicationType, out var methodConfigMap)) { methodConfigMap = new Dictionary <IMethodDefinition, IConfiguration>(); } await StartHadlingMethodsAsync(allQueriesCommunicationType, serviceDefinition, allQueriesConfig, methodConfigMap, ct); var allCommandsConfig = _communicationModelConfiguration.GetCommandsConfiguration(serviceDefinition, CommunicationSectionName); var allCommandsCommunicationType = GetCommunicationType(allCommandsConfig); if (!methodOverridesMap.TryGetValue(allCommandsCommunicationType, out methodConfigMap)) { methodConfigMap = new Dictionary <IMethodDefinition, IConfiguration>(); } await StartHadlingMethodsAsync(allCommandsCommunicationType, serviceDefinition, allCommandsConfig, methodConfigMap, ct); var methodsExtraCommTypes = methodOverridesMap.Keys.Where(c => !string.Equals(c, allQueriesCommunicationType, StringComparison.OrdinalIgnoreCase) && !string.Equals(c, allCommandsCommunicationType, StringComparison.OrdinalIgnoreCase)); foreach (var methodExtraCommType in methodsExtraCommTypes) { methodConfigMap = methodOverridesMap[methodExtraCommType]; var queryConfigMap = new Dictionary <IMethodDefinition, IConfiguration>(); var commandConfigMap = new Dictionary <IMethodDefinition, IConfiguration>(); foreach (var pair in methodConfigMap) { if (pair.Key.IsQuery) { queryConfigMap.Add(pair.Key, pair.Value); } else { commandConfigMap.Add(pair.Key, pair.Value); } } if (queryConfigMap.Count > 0) { await StartHadlingMethodsAsync(methodExtraCommType, serviceDefinition, allQueriesConfig, queryConfigMap, ct); } if (commandConfigMap.Count > 0) { await StartHadlingMethodsAsync(methodExtraCommType, serviceDefinition, allCommandsConfig, commandConfigMap, ct); } } } else { var serviceConfig = _communicationModelConfiguration.GetServiceConfiguration(serviceDefinition, CommunicationSectionName); var serviceCommunicationType = GetCommunicationType(serviceConfig); if (!methodOverridesMap.TryGetValue(serviceCommunicationType, out var methodConfigMap)) { methodConfigMap = new Dictionary <IMethodDefinition, IConfiguration>(); } await StartHadlingMethodsAsync(serviceCommunicationType, serviceDefinition, serviceConfig, methodConfigMap, ct); var methodsExtraCommTypes = methodOverridesMap.Keys.Where(c => !string.Equals(c, serviceCommunicationType, StringComparison.OrdinalIgnoreCase)); foreach (var methodExtraCommType in methodsExtraCommTypes) { methodConfigMap = methodOverridesMap[methodExtraCommType]; await StartHadlingMethodsAsync(methodExtraCommType, serviceDefinition, serviceConfig, methodConfigMap, ct); } } var allEventsConfig = _communicationModelConfiguration.GetEventsConfiguration(serviceDefinition, CommunicationSectionName); var allEventsCommunicationType = GetCommunicationType(allEventsConfig); if (!eventOverridesMap.TryGetValue(allEventsCommunicationType, out var eventConfigMap)) { eventConfigMap = new Dictionary <IEventDefinition, IConfiguration>(); } await StartListeningEventsAsync(allEventsCommunicationType, serviceDefinition, allEventsConfig, eventConfigMap, ct); var eventsExtraCommTypes = eventOverridesMap.Keys.Where(c => !string.Equals(c, allEventsCommunicationType, StringComparison.OrdinalIgnoreCase)); foreach (var eventExtraCommType in eventsExtraCommTypes) { eventConfigMap = eventOverridesMap[eventExtraCommType]; await StartListeningEventsAsync(eventExtraCommType, serviceDefinition, allEventsConfig, eventConfigMap, ct); } } } }
public async Task HandleAsync(PathString basePath, HttpContext context, CancellationToken ct) { var isQueryRequest = context.Request.Method == "GET"; var isCommandRequest = context.Request.Method == "POST"; if (!isQueryRequest && !isCommandRequest) { await ReplyWithTextError(context.Response, 405, "Only GET and POST verbs are allowed"); return; } var headers = context.Response.Headers; headers.Add(DasyncHttpHeaders.PoweredBy, "D-ASYNC"); var basePathSegmentCount = basePath.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Length; var pathSegments = context.Request.Path.Value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Skip(basePathSegmentCount).ToArray(); if (pathSegments.Length == 0) { await ReplyWithTextError(context.Response, 404, "Empty request URL"); return; } var serviceId = new ServiceId { Name = pathSegments[0] }; if (!_serviceResolver.TryResolve(serviceId, out var serviceReference)) { await ReplyWithTextError(context.Response, 404, $"Service '{serviceId.Name}' is not registered"); return; } if (serviceReference.Definition.Type == ServiceType.External) { await ReplyWithTextError(context.Response, 404, $"Cannot invoke external service '{serviceReference.Definition.Name}' on your behalf"); return; } if (pathSegments.Length == 1) { await ReplyWithTextError(context.Response, 404, "The request URL does not contain a service method"); return; } var methodId = new MethodId { Name = pathSegments[1] }; string methodIntentId = null; if (pathSegments.Length == 3) { methodIntentId = pathSegments[2]; if (isQueryRequest) { await HandleResultPoll(context, serviceReference.Id, methodId, methodIntentId); return; } } if (pathSegments.Length > 3) { await ReplyWithTextError(context.Response, 404, "The request URL contains extra segments"); return; } var contentType = context.Request.GetContentType(); ISerializer serializer; try { serializer = GetSerializer(contentType, isQueryRequest); } catch (ArgumentException) { await ReplyWithTextError(context.Response, 406, $"The Content-Type '{contentType.MediaType}' is not supported"); return; } if (!_methodResolver.TryResolve(serviceReference.Definition, methodId, out var methodReference)) { await ReplyWithTextError(context.Response, 404, $"The service '{serviceReference.Definition.Name}' does not have method '{methodId.Name}'"); return; } if (isQueryRequest && !methodReference.Definition.IsQuery) { await ReplyWithTextError(context.Response, 404, $"The method '{methodId.Name}' of service '{serviceReference.Definition.Name}' is a command, but not a query, thus must be invoked with the POST verb"); return; } MethodInvocationData invokeData = null; MethodContinuationData continueData = null; IValueContainer parametersContainer; bool compressResponse = false; bool respondWithEnvelope = false; if (isQueryRequest) { var inputObject = new JObject(); foreach (var kvPair in context.Request.Query) { if (kvPair.Value.Count == 0) { continue; } var parameterName = kvPair.Key; if (kvPair.Value.Count == 1) { var parameterValue = kvPair.Value[0]; inputObject.Add(parameterName, parameterValue); } else { var values = new JArray(); foreach (var value in kvPair.Value) { values.Add(value); } inputObject.Add(parameterName, values); } } var parametersJson = inputObject.ToString(); parametersContainer = new SerializedValueContainer(parametersJson, _jsonSerializer); invokeData = new MethodInvocationData { Service = serviceId, Method = methodId, Parameters = parametersContainer, Caller = GetCaller(context.Request.Headers) }; } else { var payloadStream = context.Request.Body; var encoding = context.Request.GetContentEncoding(); if (!string.IsNullOrEmpty(encoding)) { if ("gzip".Equals(encoding, StringComparison.OrdinalIgnoreCase)) { compressResponse = true; payloadStream = new GZipStream(payloadStream, CompressionMode.Decompress, leaveOpen: true); } else if ("deflate".Equals(encoding, StringComparison.OrdinalIgnoreCase)) { payloadStream = new DeflateStream(payloadStream, CompressionMode.Decompress, leaveOpen: true); } else { await ReplyWithTextError(context.Response, 406, $"The Content-Encoding '{encoding}' is not supported"); return; } } var envelopeType = context.Request.Headers.GetValue(DasyncHttpHeaders.Envelope); if (string.IsNullOrEmpty(envelopeType)) { var payload = await payloadStream.ToBytesAsync(); parametersContainer = new SerializedValueContainer(payload, serializer); if (string.IsNullOrEmpty(methodIntentId)) { invokeData = new MethodInvocationData { Service = serviceId, Method = methodId, Parameters = parametersContainer, Caller = GetCaller(context.Request.Headers) }; } else { continueData = new MethodContinuationData { Service = serviceId, Method = methodId.CopyTo(new PersistedMethodId()), Result = parametersContainer, Caller = GetCaller(context.Request.Headers) }; continueData.Method.IntentId = methodIntentId; // TODO: get ETag from the query string } } else if (envelopeType.Equals("invoke", StringComparison.OrdinalIgnoreCase)) { respondWithEnvelope = true; invokeData = await DeserializeAsync <MethodInvocationData>(serializer, payloadStream); } else if (envelopeType.Equals("continue", StringComparison.OrdinalIgnoreCase)) { respondWithEnvelope = true; continueData = await DeserializeAsync <MethodContinuationData>(serializer, payloadStream); } else { await ReplyWithTextError(context.Response, 406, $"Unknown envelope type '{envelopeType}'"); return; } } var intentId = context.Request.Headers.GetValue(DasyncHttpHeaders.IntentId) ?? _idGenerator.NewId(); var externalRequestId = context.Request.Headers.GetValue(DasyncHttpHeaders.RequestId); var externalCorrelationId = context.Request.Headers.GetValue(DasyncHttpHeaders.CorrelationId); var isRetry = context.Request.Headers.IsRetry(); var rfc7240Preferences = context.Request.Headers.GetRFC7240Preferences(); var isHttpRequestBlockingExecution = !(rfc7240Preferences.RespondAsync == true); var waitTime = rfc7240Preferences.Wait; if (waitTime > MaxLongPollTime) { waitTime = MaxLongPollTime; } var waitForResult = isHttpRequestBlockingExecution || waitTime > TimeSpan.Zero; var communicatorMessage = new HttpCommunicatorMessage { IsRetry = isRetry, RequestId = externalRequestId, WaitForResult = waitForResult }; if (invokeData != null) { if (invokeData.IntentId == null) { invokeData.IntentId = intentId; } var invokeTask = _localTransitionRunner.RunAsync(invokeData, communicatorMessage); if (isHttpRequestBlockingExecution) { var invocationResult = await invokeTask; if (invocationResult.Outcome == InvocationOutcome.Complete) { await RespondWithMethodResult(context.Response, invocationResult.Result, serializer, respondWithEnvelope, compressResponse); return; } if (waitForResult) { var taskResult = await TryWaitForResultAsync( serviceReference.Id, methodId, intentId, waitTime); if (taskResult != null) { await RespondWithMethodResult(context.Response, taskResult, serializer, respondWithEnvelope, compressResponse); return; } } } else { // TODO: continue 'invokeTask' and handle exceptions in background } communicatorMessage.WaitForResult = false; var location = string.Concat(context.Request.Path, "/", intentId); context.Response.Headers.Add("Location", location); context.Response.Headers.Add(DasyncHttpHeaders.IntentId, intentId); context.Response.StatusCode = DasyncHttpCodes.Scheduled; } else if (continueData != null) { if (continueData.IntentId == null) { continueData.IntentId = intentId; } var continueTask = _localTransitionRunner.ContinueAsync(continueData, communicatorMessage); // TODO: continue 'continueTask' in backgraound to handle exceptions context.Response.Headers.Add("Location", context.Request.Path.ToString()); context.Response.Headers.Add(DasyncHttpHeaders.IntentId, continueData.Method.IntentId); context.Response.StatusCode = DasyncHttpCodes.Scheduled; } }
private Dictionary <ConfigurationSectionKey, IConfigurationSection> ReadConfiguration(IConfigurationSection rootSection) { // [base] // ------------------------------------------ // dasync // [base+primitives] // ------------------------------------------ // dasync:commands // dasync:queries // dasync:events // [category] // ------------------------------------------ // dasync:services:_local // dasync:services:_external // [category+primitives] // ------------------------------------------ // dasync:services:_local:commands // dasync:services:_local:queries // dasync:services:_local:events // dasync:services:_external:commands // dasync:services:_external:queries // dasync:services:_external:events // [service] // dasync:services:{name} // [service+primitives] // dasync:services:{name}:commands:_all // dasync:services:{name}:queries:_all // dasync:services:{name}:events:_all // [primitives] // dasync:services:{name}:commands:{name} // dasync:services:{name}:queries:{name} // dasync:services:{name}:events:{name} var map = new Dictionary <ConfigurationSectionKey, IConfigurationSection>(); var baseKey = new ConfigurationSectionKey(); map[baseKey] = rootSection; if (rootSection == null) { return(map); } AddPrimitiveSections(rootSection, baseKey, map); var servicesSection = rootSection.GetSection("services"); foreach (var serviceSection in servicesSection.GetChildren()) { if (serviceSection.Key.Equals("_local", StringComparison.OrdinalIgnoreCase)) { var localServicesKey = new ConfigurationSectionKey { ServiceCategory = ServiceCategory.Local }; map[localServicesKey] = serviceSection; AddPrimitiveSections(serviceSection, localServicesKey, map); } else if (serviceSection.Key.Equals("_external", StringComparison.OrdinalIgnoreCase)) { var externalServicesKey = new ConfigurationSectionKey { ServiceCategory = ServiceCategory.External }; map[externalServicesKey] = serviceSection; AddPrimitiveSections(serviceSection, externalServicesKey, map); } else { var serviceName = serviceSection.Key; if (_serviceResolver.TryResolve(new ServiceId { Name = serviceName }, out var serviceReference)) { serviceName = serviceReference.Definition.Name; } var serviceKey = new ConfigurationSectionKey { ServiceName = serviceName }; map[serviceKey] = serviceSection; foreach (var subSection in serviceSection.GetChildren()) { if (subSection.Key.Equals("commands", StringComparison.OrdinalIgnoreCase)) { EnumerateThroughPrimitiveType(subSection, serviceKey, PrimitiveType.Command, serviceReference?.Definition, map); } else if (subSection.Key.Equals("queries", StringComparison.OrdinalIgnoreCase)) { EnumerateThroughPrimitiveType(subSection, serviceKey, PrimitiveType.Query, serviceReference?.Definition, map); } else if (subSection.Key.Equals("events", StringComparison.OrdinalIgnoreCase)) { EnumerateThroughPrimitiveType(subSection, serviceKey, PrimitiveType.Event, serviceReference?.Definition, map); } } } } return(map); }