Example #1
0
        public static NaosApplicationContextOptions UseOperationsHealth(
            this NaosApplicationContextOptions naosOptions)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));

            //naosOptions.Context.Application.UseEndpointRouting(); // needed by middleware to get action/controller https://www.stevejgordon.co.uk/asp-net-core-first-look-at-global-routing-dispatcher
            //naosOptions.Context.Application.UseEndpoints(endpoints =>
            //{
            //    endpoints.MapHealthChecks("/health", new HealthCheckOptions
            //    {
            //        ResponseWriter = HealthReportResponseWriter.Write
            //    });
            //});

            // https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks?view=aspnetcore-3.1
            naosOptions.Context.Application.UseHealthChecks("/health", new HealthCheckOptions()
            {
                Predicate      = _ => true,
                ResponseWriter = HealthReportResponseWriter.Write // or use HealthChecks.UI.Client.UIResponseWriter.WriteHealthCheckUIResponse
            });
            naosOptions.Context.Application.UseHealthChecks("/health/ready", new HealthCheckOptions
            {
                Predicate      = _ => true,
                ResponseWriter = HealthReportResponseWriter.Write // or use HealthChecks.UI.Client.UIResponseWriter.WriteHealthCheckUIResponse
            });
            naosOptions.Context.Application.UseHealthChecks("/health/live", new HealthCheckOptions
            {
                Predicate      = r => r.Tags.Contains("live"),
                ResponseWriter = HealthReportResponseWriter.Write // or use HealthChecks.UI.Client.UIResponseWriter.WriteHealthCheckUIResponse
            });

            naosOptions.Context.Messages.Add("naos application builder: operations health added");

            return(naosOptions);
        }
Example #2
0
        /// <summary>
        /// Enables correlation/request ids for the API request/responses.
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static NaosApplicationContextOptions UseNaosExceptionHandling(this NaosApplicationContextOptions naosOptions, ExceptionHandlerMiddlewareOptions options)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));
            EnsureArg.IsNotNull(options, nameof(options));

            naosOptions.Context.Application.UseMiddleware <ExceptionHandlerMiddleware>(Options.Create(options));
            naosOptions.Context.Messages.Add($"{LogKeys.Startup} naos application builder: service exceptions added");
            return(naosOptions);
        }
        /// <summary>
        /// Enables poweredby response headers for the API request.
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static NaosApplicationContextOptions UseNaosServicePoweredBy(this NaosApplicationContextOptions naosOptions, ServicePoweredByMiddlewareOptions options)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));
            EnsureArg.IsNotNull(options, nameof(options));

            naosOptions.Context.Application.UseMiddleware <ServicePoweredByMiddleware>(Options.Create(options));
            naosOptions.Context.Messages.Add($"{LogEventKeys.Startup} naos application builder: powered by added");
            return(naosOptions);
        }
Example #4
0
        /// <summary>
        /// Enables the service discovery router.
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <param name="options"></param>
        public static NaosApplicationContextOptions UseNaosServiceDiscoveryRouter(
            this NaosApplicationContextOptions naosOptions,
            ServiceDiscoveryRouterMiddlewareOptions options)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));
            EnsureArg.IsNotNull(options, nameof(options));

#pragma warning disable CS0618 // Type or member is obsolete >> naosOptions.Context.Application.Map("/api/servicediscovery/router/proxy", async proxy => { proxy.UseProxy() } )
            naosOptions.Context.Application.RunProxy("/naos/servicediscovery/router/proxy", async context =>
            {
                var logger         = naosOptions.Context.Application.ApplicationServices.GetRequiredService <ILogger>();
                var registryClient = naosOptions.Context.Application.ApplicationServices.GetRequiredService <RouterContext>().RegistryClient;

                // read headers for service/tag
                var isFoundName = context.Request.Headers.TryGetValue(ServiceDiscoveryRouterHeaders.ServiceName, out var serviceName);
                var isFoundTag  = context.Request.Headers.TryGetValue(ServiceDiscoveryRouterHeaders.ServiceTag, out var serviceTag);

                if (!isFoundName && !isFoundTag)
                {
                    context.Response.StatusCode = 400;
                    throw new NaosException($"Router cannot find a service registration based on the provided information (serviceName={serviceName}, serviceTag={serviceTag})");
                    // = 400 bad request (router headers missing)
                }

                var registrations = await registryClient.RegistrationsAsync(serviceName, serviceTag).AnyContext();
                var registration  = registrations.FirstOrDefault(); // todo: do some kind random/roundrobin

                if (registration == null)
                {
                    context.Response.StatusCode = 502;
                    throw new NaosException($"Router cannot find a service registration based on the provided information (serviceName={serviceName}, serviceTag={serviceTag})");
                    // = 404? 502? https://errorcodespro.com/what-is-http-error-502-bad-gateway/
                }

                // TODO: how is api/registrations NOT forwarded? based on missing router headers?
                // TODO: round robin https://github.com/damianh/ProxyKit/blob/master/src/Recipes/05_RoundRobin.cs
                var upstreamHost = new Uri($"{registration.Address}:{registration.Port}");
                logger.LogInformation($"{{LogKey:l}} router {{Url}} >> {{Host}} (service={{ServiceName}}, tag={serviceTag})", LogKeys.ServiceDiscovery, context.Request.GetUri(), upstreamHost, registration.Name);
                return(await context
                       .ForwardTo(upstreamHost)
                       .Log(logger)
                       .CopyXForwardedHeaders() // copies the headers from the incoming requests
                       .AddXForwardedHeaders()  // adds the current proxy proto/host/for/pathbase to the X-Forwarded headers
                       .Send().AnyContext());
            });
#pragma warning restore CS0618                                                                  // Type or member is obsolete

            naosOptions.Context.Messages.Add("naos application builder: job scheduling added"); // TODO: list available commands/handlers

            //return app.UseMiddleware<ServiceDiscoveryRouterMiddleware>(Options.Create(options));
            return(naosOptions);
        }
Example #5
0
        /// <summary>
        /// Enables correlation/request ids for the API request/responses.
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <param name="options"></param>
        public static NaosApplicationContextOptions UseNaosCorrelation(this NaosApplicationContextOptions naosOptions, RequestCorrelationMiddlewareOptions options)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));
            EnsureArg.IsNotNull(options, nameof(options));

            if (naosOptions.Context.Application.ApplicationServices.GetService(typeof(ICorrelationContextFactory)) == null)
            {
                throw new InvalidOperationException("Unable to find the required services. You must call the AddRequestCorrelation method in ConfigureServices in the application startup code.");
            }

            naosOptions.Context.Application.UseMiddleware <RequestCorrelationMiddleware>(Options.Create(options));
            naosOptions.Context.Messages.Add("naos application builder: request correlation added");
            return(naosOptions);
        }
        /// <summary>
        /// Enables service context (descriptor) for the API request/responses.
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static NaosApplicationContextOptions UseNaosServiceContext(this NaosApplicationContextOptions naosOptions, ServiceContextMiddlewareOptions options)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));
            EnsureArg.IsNotNull(options, nameof(options));

            if (naosOptions.Context.Application.ApplicationServices.GetService(typeof(Naos.Core.Common.ServiceDescriptor)) == null)
            {
                throw new InvalidOperationException("Unable to find the required services. You must call the AddServiceContext method in ConfigureServices in the application startup code.");
            }

            naosOptions.Context.Application.UseMiddleware <ServiceContextMiddleware>(Options.Create(options));
            naosOptions.Context.Messages.Add($"{LogEventKeys.Startup} naos application builder: service context added");
            return(naosOptions);
        }
        /// <summary>
        /// Enables correlation/request ids for the API request/responses
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <param name="requestLoggingMiddlewareOptions"></param>
        /// <param name="requestStorageMiddlewareOptions"></param>
        /// <returns></returns>
        public static NaosApplicationContextOptions UseOperations(this NaosApplicationContextOptions naosOptions,
                                                                  RequestLoggingMiddlewareOptions requestLoggingMiddlewareOptions = null,
                                                                  RequestStorageMiddlewareOptions requestStorageMiddlewareOptions = null)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));

            naosOptions.Context.Application
            .UseMiddleware <RequestLoggingMiddleware>(
                Options.Create(requestLoggingMiddlewareOptions ?? naosOptions.Context.Application.ApplicationServices.GetService <RequestLoggingMiddlewareOptions>() ?? new RequestLoggingMiddlewareOptions()))
            .UseMiddleware <RequestStorageMiddleware>(
                Options.Create(requestStorageMiddlewareOptions ?? naosOptions.Context.Application.ApplicationServices.GetService <RequestStorageMiddlewareOptions>() ?? new RequestStorageMiddlewareOptions()));
            naosOptions.Context.Messages.Add($"{LogEventKeys.Startup} naos application builder: operations added");

            var diagnosticListener = naosOptions.Context.Application.ApplicationServices.GetService <DiagnosticListener>();

            diagnosticListener?.SubscribeWithAdapter(new NaosDiagnosticListener(naosOptions.Context.Application.ApplicationServices.GetService <ILoggerFactory>()));

            return(naosOptions);
        }
Example #8
0
        /// <summary>
        /// Enables correlation/request ids for the API request/responses.
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <param name="options"></param>
        public static NaosApplicationContextOptions UseAuthenticationChallenge(this NaosApplicationContextOptions naosOptions, OidcAuthenticationChallengeMiddlewareOptions options)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));
            EnsureArg.IsNotNull(options, nameof(options));

            var provider = naosOptions.Context.Application.ApplicationServices.GetService <IAuthenticationSchemeProvider>();

            if (provider != null)
            {
                if (provider.GetDefaultChallengeSchemeAsync().Result?.Name == Authentication.OpenIdConnect.OpenIdConnectDefaults.AuthenticationScheme)
                {
                    naosOptions.Context.Application.UseMiddleware <OidcAuthenticationChallengeMiddleware>(Options.Create(options));
                    naosOptions.Context.Messages.Add("naos application builder: authentication challenge");
                }

                // TODO: register other middleware for different authentication schemes (easyauth?)
            }

            return(naosOptions);
        }
Example #9
0
        /// <summary>
        /// Enables correlation/request ids for the API request/responses.
        /// </summary>
        /// <param name="naosOptions"></param>
        public static NaosApplicationContextOptions UseCommandEndpoints(this NaosApplicationContextOptions naosOptions)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));

            var routeMatcher = new RouteMatcher();

            foreach (var registration in naosOptions.Context.Application.ApplicationServices.GetServices <CommandRequestRegistration>().Safe()
                     .Where(r => !r.Route.IsNullOrEmpty()))
            {
                naosOptions.Context.Application.UseMiddleware <CommandRequestMiddleware>(
                    Options.Create(new CommandRequestMiddlewareOptions
                {
                    Registration = registration,
                    RouteMatcher = routeMatcher
                }));
                naosOptions.Context.Messages.Add($"naos application builder: command requests added (route={registration.Route}, method={registration.RequestMethod}, type={registration.CommandType.PrettyName()})");
            }

            return(naosOptions);
        }
Example #10
0
        /// <summary>
        /// Enables tracing for the API request/responses.
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <param name="requestTracingMiddlewareOptions"></param>
        public static NaosApplicationContextOptions UseOperationsTracing(
            this NaosApplicationContextOptions naosOptions,
            RequestTracingMiddlewareOptions requestTracingMiddlewareOptions = null)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));

            using (var scope = naosOptions.Context.Application.ApplicationServices.CreateScope())
            {
                if (scope.ServiceProvider.GetService(typeof(ITracer)) == null) // resolve scoped service
                {
                    throw new InvalidOperationException("Unable to find the required services. You must call the AddTracing method in ConfigureServices in the application startup code.");
                }
            }

            //naosOptions.Context.Application.UseEndpointRouting(); // needed by middleware to get action/controller https://www.stevejgordon.co.uk/asp-net-core-first-look-at-global-routing-dispatcher
            naosOptions.Context.Application.UseMiddleware <RequestTracingMiddleware>(
                Options.Create(requestTracingMiddlewareOptions ?? naosOptions.Context.Application.ApplicationServices.GetService <RequestTracingMiddlewareOptions>() ?? new RequestTracingMiddlewareOptions()));
            naosOptions.Context.Messages.Add("naos application builder: operations request tracing added");

            return(naosOptions);
        }
Example #11
0
        /// <summary>
        /// Enables correlation/request ids for the API request/responses.
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <param name="requestLoggingMiddlewareOptions"></param>
        /// <param name="requestStorageMiddlewareOptions"></param>
        public static NaosApplicationContextOptions UseOperationsLogging(
            this NaosApplicationContextOptions naosOptions,
            RequestLoggingMiddlewareOptions requestLoggingMiddlewareOptions = null,
            RequestStorageMiddlewareOptions requestStorageMiddlewareOptions = null)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));

            //naosOptions.Context.Application.UseEndpointRouting(); // needed by middleware to get action/controller https://www.stevejgordon.co.uk/asp-net-core-first-look-at-global-routing-dispatcher
            naosOptions.Context.Application
            .UseMiddleware <RequestLoggingMiddleware>(
                Options.Create(requestLoggingMiddlewareOptions ?? naosOptions.Context.Application.ApplicationServices.GetService <RequestLoggingMiddlewareOptions>() ?? new RequestLoggingMiddlewareOptions()))
            .UseMiddleware <RequestStorageMiddleware>(
                Options.Create(requestStorageMiddlewareOptions ?? naosOptions.Context.Application.ApplicationServices.GetService <RequestStorageMiddlewareOptions>() ?? new RequestStorageMiddlewareOptions()));
            naosOptions.Context.Messages.Add("naos application builder: operations request logging added");

            var diagnosticListener = naosOptions.Context.Application.ApplicationServices.GetService <DiagnosticListener>();

            diagnosticListener?.SubscribeWithAdapter(new NaosDiagnosticListener(naosOptions.Context.Application.ApplicationServices.GetService <ILoggerFactory>()));

            return(naosOptions);
        }
Example #12
0
        /// <summary>
        /// Force authentication for all endpoints (mvc + custom middleware)
        /// </summary>
        /// <param name="naosOptions"></param>
        public static NaosApplicationContextOptions UseAuthenticationChallenge(this NaosApplicationContextOptions naosOptions)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));

            return(naosOptions.UseAuthenticationChallenge(new OidcAuthenticationChallengeMiddlewareOptions()));
        }
Example #13
0
        /// <summary>
        /// Enables correlation/request ids for the API request/responses.
        /// </summary>
        /// <param name="naosOptions"></param>
        public static NaosApplicationContextOptions UseRequestCorrelation(this NaosApplicationContextOptions naosOptions)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));

            return(naosOptions.UseNaosCorrelation(new RequestCorrelationMiddlewareOptions()));
        }
Example #14
0
        public static NaosApplicationContextOptions UseServiceExceptions(this NaosApplicationContextOptions naosOptions)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));

            return(naosOptions.UseNaosExceptionHandling(new ExceptionHandlerMiddlewareOptions()));
        }
Example #15
0
        /// <summary>
        /// Enables the service discovery router
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <returns></returns>
        public static NaosApplicationContextOptions UseServiceDiscoveryRouter(this NaosApplicationContextOptions naosOptions)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));

            return(naosOptions.UseNaosServiceDiscoveryRouter(new ServiceDiscoveryRouterMiddlewareOptions()));
        }
        /// <summary>
        /// Enables poweredby response headers for the API request.
        /// </summary>
        /// <param name="naosOptions"></param>
        /// <returns></returns>
        public static NaosApplicationContextOptions UseServicePoweredBy(this NaosApplicationContextOptions naosOptions)
        {
            EnsureArg.IsNotNull(naosOptions, nameof(naosOptions));

            return(naosOptions.UseNaosServicePoweredBy(new ServicePoweredByMiddlewareOptions()));
        }