public ServiceDiscoveryRouterMiddleware( RequestDelegate next, ILogger <ServiceDiscoveryRouterMiddleware> logger, IOptions <ServiceDiscoveryRouterMiddlewareOptions> options) { EnsureArg.IsNotNull(next, nameof(next)); EnsureArg.IsNotNull(logger, nameof(logger)); this.next = next; this.logger = logger; this.options = options.Value ?? new ServiceDiscoveryRouterMiddlewareOptions(); }
/// <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); }