public static IApplicationBuilder MapReverseProxyWithQueueDelegation(this IApplicationBuilder app)
        {
            IServerDelegationFeature delegationFeature = app.ServerFeatures.Get <IServerDelegationFeature>();

            if (delegationFeature == null)
            {
                throw new NotSupportedException($"The {nameof(IServerDelegationFeature)} is not supported by the current OS.");
            }

            var delegationRuleProvider = new QueueDelegationRuleProvider(
                delegationFeature,
                app.ApplicationServices.GetRequiredService <IProxyConfigProvider>(),
                app.ApplicationServices.GetRequiredService <ILogger <QueueDelegationRuleProvider> >());

            app.ApplicationServices.GetRequiredService <IHostApplicationLifetime>().ApplicationStopped.Register(() => delegationRuleProvider.Dispose());

            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapReverseProxy(proxyPipeline =>
                {
                    proxyPipeline.UseMiddleware <QueueDelegationMiddleware>(delegationRuleProvider);
                });
            });

            return(app);
        }
        public QueueDelegationRuleProvider(
            IServerDelegationFeature delegationFeature,
            IProxyConfigProvider proxyConfigProvider,
            ILogger <QueueDelegationRuleProvider> logger)
        {
            this.delegationFeature   = delegationFeature;
            this.proxyConfigProvider = proxyConfigProvider;
            this.logger = logger;
            this.rules  = new Dictionary <string, DelegationRule>();

            this.UpdateRules();
        }
Esempio n. 3
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostApplicationLifetime lifetime, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            ILogger <Startup>        logger    = app.ApplicationServices.GetRequiredService <ILogger <Startup> >();
            IServerDelegationFeature delegator = app.ServerFeatures.Get <IServerDelegationFeature>();

            if (delegator == null)
            {
                throw new NotSupportedException($"The {nameof(IServerDelegationFeature)} is not supported by the current OS.");
            }

            DelegationRule[] rules = app.ApplicationServices.GetRequiredService <IOptions <DelegationConfig> >().Value.Rules
                                     .Where(ruleConfig => ruleConfig.Enabled)
                                     .Select(ruleConfig =>
            {
                var rule = delegator.CreateDelegationRule(ruleConfig.QueueName, ruleConfig.Uri);
                lifetime.ApplicationStopped.Register(() =>
                {
                    try
                    {
                        // Note that dispose doesn't properly cleanup everything.
                        // This is only an issue if you want to create the same rule again in the same process.
                        // Shutdown of the process properly cleans up everything.
                        // https://github.com/dotnet/aspnetcore/issues/27126
                        rule.Dispose();
                    }
                    catch (ArgumentNullException ex)
                    {
                        // There is a bug in rule cleanup that causes a failure
                        // https://github.com/dotnet/aspnetcore/issues/26989
                        // This failure then causes a null ref bug to get hit
                        // https://github.com/dotnet/aspnetcore/issues/26982
                        logger.LogWarning(ex, "Known issue with disposing delegation rules");
                    }
                });

                logger.LogInformation($"Added delegation rule: {ruleConfig.QueueName} - {ruleConfig.Uri}");

                return(rule);
            })
                                     .ToArray();

            uint ruleIndex = uint.MaxValue;

            app.Run(context =>
            {
                int index           = (int)(Interlocked.Increment(ref ruleIndex) % rules.Length);
                DelegationRule rule = rules[index];

                IHttpSysRequestDelegationFeature transferFeature = context.Features.Get <IHttpSysRequestDelegationFeature>();
                transferFeature.DelegateRequest(rule);

                logger.LogDebug($"Request '{context.Request.GetDisplayUrl()}' transfered to: {rule.QueueName} - {rule.UrlPrefix}");

                return(Task.CompletedTask);
            });
        }