public override async Task InvokeAsync <TCommand>(
            TCommand command,
            CommandRequestRegistration <TCommand> registration,
            HttpContext context)
        {
            this.logger.LogInformation($"{{LogKey:l}} command request dispatch (name={registration.CommandType.PrettyName()}, id={command.Id}, type=queue)", LogKeys.AppCommand);

            //var wrapper = new CommandWrapper().SetCommand<TCommand>(command);
            var wrapper = new CommandRequestWrapper().SetCommand(command);

            await this.queue.EnqueueAsync(wrapper).AnyContext();

            var metrics = await this.queue.GetMetricsAsync().AnyContext();

            this.logger.LogInformation($"{{LogKey:l}} request command queue (enqueued=#{metrics.Enqueued}, queued=#{metrics.Queued})", LogKeys.AppCommand);
            this.logger.LogInformation($"queued COMMAND: {command.Dump()}");

            await context.Response.Location($"naos/commands/{command.Id}/response").AnyContext();

            await context.Response.Header(CommandRequestHeaders.CommandId, command.Id).AnyContext();

            await this.StoreCommand(wrapper).AnyContext();

            // the extension chain is terminated here
        }
Example #2
0
        public override async Task InvokeAsync <TCommand>(
            TCommand command,
            CommandRequestRegistration <TCommand> registration,
            HttpContext context)
        {
            this.logger.LogInformation($"{{LogKey:l}} request command dispatch (name={registration.CommandType.PrettyName()}, id={command.Id}), type=mediator)", LogKeys.AppCommand);

            var response = await this.mediator.Send(command).AnyContext(); // https://github.com/jbogard/MediatR/issues/385

            if (response != null)
            {
                var jResponse = JObject.FromObject(response);
                if (!jResponse.GetValueByPath <bool>("cancelled"))
                {
                    registration?.OnSuccess?.Invoke(command, context);
                }
                else
                {
                    var cancelledReason = jResponse.GetValueByPath <string>("cancelledReason");
                    await context.Response.BadRequest(cancelledReason.SliceTill(":")).AnyContext();
                }
            }

            await context.Response.Header(CommandRequestHeaders.CommandId, command.Id).AnyContext();

            // the extension chain is terminated here
        }
        public override async Task InvokeAsync <TCommand>(
            TCommand command,
            CommandRequestRegistration <TCommand> registration,
            HttpContext context)
        {
            this.logger.LogInformation($"{{LogKey:l}} command request received (name={registration.CommandType.PrettyName()}, id={command.Id})", LogKeys.AppCommand);

            // continue with next extension
            await base.InvokeAsync(command, registration, context).AnyContext();
        }
Example #4
0
 private static void AddBodyOperation(OpenApiOperation operation, CommandRequestRegistration registration, DocumentProcessorContext context)
 {
     operation.Parameters.Add(new OpenApiParameter
     {
         //Description = "request model",
         Kind   = OpenApiParameterKind.Body,
         Name   = (registration.CommandType ?? typeof(object)).PrettyName(), //"model",
         Type   = JsonObjectType.Object,
         Schema = CreateSchema(registration, context),
         //Example = registration.CommandType != null ? Factory.Create(registration.CommandType) : null //new Commands.Domain.EchoCommand() { Message = "test"},
     });
 }
Example #5
0
        public virtual async Task InvokeAsync <TCommand>(
            TCommand command,
            CommandRequestRegistration <TCommand> registration,
            HttpContext context)
            where TCommand : Command <object>
        {
            if (this.next != null)
            {
                await this.next.InvokeAsync <TCommand>(command, registration, context).AnyContext();
            }

            // chain is terminated here
        }
Example #6
0
 private static void AddResponseHeaders(OpenApiOperation operation, CommandRequestRegistration registration)
 {
     foreach (var response in operation.Responses)
     {
         response.Value.Headers.Add(CommandRequestHeaders.CommandId, new JsonSchema {
             Type = JsonObjectType.String
         });
         if (registration.IsQueued)
         {
             response.Value.Headers.Add("Location", new JsonSchema {
                 Type = JsonObjectType.String
             });
         }
     }
 }
Example #7
0
        public override async Task InvokeAsync <TCommand, TResponse>(
            TCommand command,
            CommandRequestRegistration <TCommand, TResponse> registration,
            HttpContext context)
        {
            using (var scope = this.tracer?.BuildSpan(
                       $"command request {command.GetType().PrettyName()}".ToLowerInvariant(),
                       LogKeys.AppCommand,
                       SpanKind.Consumer).Activate(this.logger))
            {
                // start a whole new SERVER span later, which is the parent for the current 'COMMAND REQUEST' span
                command.Properties.Add(CommandPropertyKeys.TraceId, scope?.Span?.TraceId);        // propagate the span infos
                command.Properties.Add(CommandPropertyKeys.TraceSpanId, scope?.Span?.SpanId);     // propagate the span infos
                command.Properties.Add(CommandPropertyKeys.TraceSampled, scope?.Span?.IsSampled); // propagate the span infos

                // continue with next extension
                await base.InvokeAsync(command, registration, context).AnyContext();
            }
        }
Example #8
0
        private static JsonSchema CreateSchema(CommandRequestRegistration registration, DocumentProcessorContext context)
        {
            return(context.SchemaGenerator.Generate(registration.CommandType, context.SchemaResolver));

            //var schema = result.AllOf.FirstOrDefault();
            //if (schema != null)
            //{
            //    // workaround: remove invalid first $ref in allof https://github.com/RicoSuter/NSwag/issues/2119
            //    result.AllOf.Remove(schema);
            //}

            // remove some more $refs
            //foreach(var definition in result.Definitions.Safe())
            //{
            //    var s = definition.Value.AllOf.FirstOrDefault();
            //    if(s != null)
            //    {
            //        definition.Value.AllOf.Remove(s);
            //    }
            //}
        }
Example #9
0
        private static void AddQueryOperation(OpenApiOperation operation, CommandRequestRegistration registration)
        {
            foreach (var property in registration.CommandType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
            {
                // translate commandType properties to many OpenApiParameters
                if (!property.CanWrite || !property.CanRead)
                {
                    continue;
                }

                var type = JsonObjectType.String;
                if (property.PropertyType == typeof(int) || property.PropertyType == typeof(short))
                {
                    type = JsonObjectType.Integer;
                }
                else if (property.PropertyType == typeof(decimal) || property.PropertyType == typeof(float) || property.PropertyType == typeof(long))
                {
                    type = JsonObjectType.Number;
                }
                else if (property.PropertyType == typeof(bool))
                {
                    type = JsonObjectType.Boolean;
                }
                else if (property.PropertyType == typeof(object))
                {
                    type = JsonObjectType.Object; // TODO: does not work for child objects
                }

                operation.Parameters.Add(new OpenApiParameter
                {
                    //Description = "request model",
                    Kind = registration.Route.Contains($"{{{property.Name}", System.StringComparison.OrdinalIgnoreCase)
                        ? OpenApiParameterKind.Path
                        : OpenApiParameterKind.Query,
                    Name = property.Name.Camelize(),
                    Type = type,
                });
            }
        }
Example #10
0
 private async Task HandleCommandWithoutResponse <TCommand>(
     object command,
     CommandRequestRegistration <TCommand> registration,
     HttpContext context)
     where TCommand : Command <object>
 {
     // registration will be resolved to the actual type with proper generic types. var i = typeof(RequestCommandRegistration<TCommand, TResponse>);
     if (command != null)
     {
         var extensions = this.EnsureExtensions(context);
         this.logger.LogDebug($"{{LogKey:l}} command request extensions chain: {extensions.Select(e => e.GetType().PrettyName()).ToString("|")} (name={registration.CommandType.Name})", LogKeys.AppCommand);
         if (extensions.Count > 0) // invoke all chained extensions
         {
             var tCommand = command as TCommand;
             tCommand?.Update(correlationId: context.GetCorrelationId()); // use correlationid from inbound http request
             await extensions[0].InvokeAsync(tCommand, registration, context).AnyContext();
         }
         else
         {
             throw new Exception("Command request not executed, no dispatcher middleware extensions configured");
         }
     }
 }
Example #11
0
        public override async Task InvokeAsync <TCommand>(
            TCommand command,
            CommandRequestRegistration <TCommand> registration,
            HttpContext context)
        {
            if (this.tracer == null)
            {
                // continue with next extension
                await base.InvokeAsync(command, registration, context).AnyContext();
            }
            else
            {
                using (var scope = this.tracer.BuildSpan(
                           $"command request {command.GetType().PrettyName()}".ToLowerInvariant(),
                           LogKeys.AppCommand,
                           SpanKind.Consumer).Activate(this.logger))
                {
                    // start a whole new SERVER span later, which is the parent for the current 'COMMAND REQUEST' span
                    command.Properties.Add(CommandPropertyKeys.TraceId, scope.Span.TraceId);        // propagate the span infos
                    command.Properties.Add(CommandPropertyKeys.TraceSpanId, scope.Span.SpanId);     // propagate the span infos
                    command.Properties.Add(CommandPropertyKeys.TraceSampled, scope.Span.IsSampled); // propagate the span infos

                    if (scope.Span.IsSampled == false)
                    {
                        this.logger.LogDebug($"{{LogKey:l}} span not sampled (id={scope.Span.SpanId})", LogKeys.Tracing);
                    }
                    else
                    {
                        this.logger.LogDebug($"{{LogKey:l}} span sampled (id={scope.Span.SpanId})", LogKeys.Tracing);
                    }

                    // continue with next extension
                    await base.InvokeAsync(command, registration, context).AnyContext();
                }
            }
        }
Example #12
0
 private static void AddOperationParameters(OpenApiOperation operation, string method, CommandRequestRegistration registration, DocumentProcessorContext context)
 {
     if (registration.CommandType != null)
     {
         if (method.SafeEquals("get") || method.SafeEquals("delete"))
         {
             AddQueryOperation(operation, registration);
         }
         else if (method.SafeEquals("post") || method.SafeEquals("put") || method.SafeEquals(string.Empty))
         {
             AddBodyOperation(operation, registration, context);
         }
         else
         {
             // TODO: ignore for now, or throw? +log
         }
     }
 }