Example #1
0
        private async Task HandleEventReactionAsync(IServiceDefinition serviceDefinitionFilter, HttpContext context, CancellationToken ct)
        {
            if (context.Request.Method != "PUT" && context.Request.Method != "POST")
            {
                context.Response.StatusCode  = 405; // Method Not Allowed
                context.Response.ContentType = "text/plain";
                await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("To invoke a reaction to an event, use one of these HTTP verbs: GET, POST, PUT"));

                return;
            }

            var eventName = (context.Request.Query.TryGetValue("event", out var eventValues) && eventValues.Count == 1) ? eventValues[0] : null;

            if (string.IsNullOrWhiteSpace(eventName))
            {
                context.Response.StatusCode  = 404;
                context.Response.ContentType = "text/plain";
                await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("Missing 'event=xxx' in the URL query."));

                return;
            }

            var serviceName = (context.Request.Query.TryGetValue("service", out var serviceValues) && serviceValues.Count == 1) ? serviceValues[0] : null;

            if (string.IsNullOrWhiteSpace(serviceName))
            {
                context.Response.StatusCode  = 404;
                context.Response.ContentType = "text/plain";
                await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("Missing 'service=xxx' in the URL query."));

                return;
            }

            var eventDesc = new EventDescriptor
            {
                EventId = new EventId {
                    EventName = eventName
                },
                ServiceId = new ServiceId {
                    ServiceName = serviceName
                }
            };

            var eventHandlers = _eventDispatcher.GetEventHandlers(eventDesc);

            if ((eventHandlers?.Count ?? 0) == 0)
            {
                context.Response.StatusCode = DasyncHttpCodes.Succeeded;
                return;
            }

            var contentType         = context.Request.GetContentType();
            var isJsonRequest       = string.Equals(contentType.MediaType, "application/json", StringComparison.OrdinalIgnoreCase);
            var isDasyncJsonRequest = string.Equals(contentType.MediaType, "application/dasync+json", StringComparison.OrdinalIgnoreCase);

            if (!isJsonRequest && !isDasyncJsonRequest)
            {
                context.Response.StatusCode  = 406; // Not Acceptable
                context.Response.ContentType = "text/plain";
                await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("The request content type is either not specified or not supported"));

                return;
            }

            string parametersJson = null;

            if (isJsonRequest)
            {
                parametersJson = await context.Request.ReadBodyAsStringAsync(contentType);
            }
            else if (isDasyncJsonRequest)
            {
                var envelopeJson = await context.Request.ReadBodyAsStringAsync(contentType);

                var envelope = JsonConvert.DeserializeObject <EventEnvelope>(envelopeJson, JsonSettings);
                parametersJson = envelope.Parameters;
            }

            var results = new List <RaiseEventResult>();

            _transitionUserContext.Current = GetUserContext(context);

            foreach (var subscriber in eventHandlers)
            {
                if (serviceDefinitionFilter != null && !string.Equals(subscriber.ServiceId.ServiceName, serviceDefinitionFilter.Name, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                var subscriberServiceDefinition = _communicationModelProvider.Model.FindServiceByName(subscriber.ServiceId.ServiceName);

#warning Use model for method resolution instead
                var eventHandlerRoutineMethodId = new RoutineMethodId
                {
                    MethodName = subscriber.MethodId.MethodName
                };
                MethodInfo routineMethod = _routineMethodResolver.Resolve(subscriberServiceDefinition, eventHandlerRoutineMethodId);

                var methodInvoker      = _methodInvokerFactory.Create(routineMethod);
                var parameterContainer = methodInvoker.CreateParametersContainer();

                if (!string.IsNullOrWhiteSpace(parametersJson))
                {
                    if (isDasyncJsonRequest)
                    {
                        _dasyncJsonSerializer.Populate(parametersJson, parameterContainer);
                    }
                    else
                    {
                        JsonConvert.PopulateObject(parametersJson, parameterContainer, JsonSettings);
                    }
                }

                var intentId = _idGenerator.NewId();

                _intentPreprocessor.PrepareContext(context);
                if (await _intentPreprocessor.PreprocessAsync(context, subscriberServiceDefinition, subscriber.MethodId, parameterContainer).ConfigureAwait(false))
                {
                    return;
                }

                foreach (var postAction in _transitionActions)
                {
                    await postAction.OnRoutineStartAsync(subscriberServiceDefinition, subscriber.ServiceId, subscriber.MethodId, intentId);
                }

                var  serviceInstance = _domainServiceProvider.GetService(subscriberServiceDefinition.Implementation);
                Task task;
                try
                {
                    task = methodInvoker.Invoke(serviceInstance, parameterContainer);
                    if (routineMethod.ReturnType != typeof(void))
                    {
                        try { await task; } catch { }
                    }
                }
                catch (Exception ex)
                {
                    if (ex is TargetInvocationException)
                    {
                        ex = ex.InnerException;
                    }
                    task = Task.FromException(ex);
                }
                var taskResult = task?.ToTaskResult() ?? new TaskResult();

                foreach (var postAction in _transitionActions)
                {
                    await postAction.OnRoutineCompleteAsync(subscriberServiceDefinition, subscriber.ServiceId, subscriber.MethodId, intentId, taskResult);
                }

                results.Add(new RaiseEventResult
                {
                    ServiceName = subscriber.ServiceId.ServiceName,
                    MethodName  = subscriber.MethodId.MethodName,
                    Result      = taskResult
                });
            }

            context.Response.StatusCode = DasyncHttpCodes.Succeeded;

            if (isJsonRequest)
            {
                context.Response.ContentType = "application/json";
                await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(results, JsonSettings)));
            }
            else if (isDasyncJsonRequest)
            {
                context.Response.ContentType = "application/dasync+json";
                _dasyncJsonSerializer.Serialize(context.Response.Body, results);
            }
        }