Installing New Runtime Middleware in ASP.Net Core

When my application starts, I have a bunch of modules (module1, module2 ...). For each of this module, I have a bunch of controller actions:

/myModuleController/module1/action1 /myModuleController/module1/action2 /myModuleController/module2/action1 /myModuleController/module2/action2 โ€ฆ 

Since the user can register himself once for each module, I deploy middleware for authentication on one module, which runs as follows:

 app.UseWhen((context) => context.Request.Path.StartsWithSegments(urlPath), appbuilder => { appbuilder.UseCookieAuthentication(new CookieAuthenticationOptions() { CookieName = cookieName, โ€ฆ }); }); 

So basically, in the path of URL /myModuleController/module1 , I have one middleware plus its cookie, the other for /myModuleController/module2 ... Its a bit unusual, but I think, but its work is fine, I am pleased with the behavior.

Here's the problem: I want to be able to add a new module at run time, which would imply the ability to deploy new middleware with a piece of code, for example app.UseWhen(url, app. UseCookieAuthentication(โ€ฆ)) . I tried naively to inject the IApplicationBuilder app into the controller responsible for adding the module, but Im getting an exception:

System.InvalidOperationException: Cannot resolve service for type "Microsoft.AspNetCore.Builder.IApplicationBuilder" when trying to activate "AdminController"

My question is for you: should it work, and should I make a mistake somewhere? or, is it clear to you that what I'm trying here has no chance of work?

How would you achieve the same requirement? Thanks.

+9
source share
1 answer

First, we need a service to support middleware configurations at runtime.

 public class RuntimeMiddlewareService { private Func<RequestDelegate, RequestDelegate> _middleware; private IApplicationBuilder _appBuilder; internal void Use(IApplicationBuilder app) => _appBuilder = app.Use(next => context => _middleware(next)(context)); public void Configure(Action<IApplicationBuilder> action) { var app = _appBuilder.New(); action(app); _middleware = next => app.Use(_ => next).Build(); } } 

Then add some extension methods to use it with Startup

 public static class RuntimeMiddlewareExtensions { public static IServiceCollection AddRuntimeMiddleware(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton) { services.Add(new ServiceDescriptor(typeof(RuntimeMiddlewareService), typeof(RuntimeMiddlewareService), lifetime)); return services; } public static IApplicationBuilder UseRuntimeMiddleware(this IApplicationBuilder app, Action<IApplicationBuilder> defaultAction = null) { var service = app.ApplicationServices.GetRequiredService<RuntimeMiddlewareService>(); service.Use(app); if (defaultAction != null) { service.Configure(defaultAction); } return app; } } 

Then change your Startup

Add to ConfigureServices :

 services.AddRuntimeMiddleware(/* ServiceLifetime.Scoped could be specified here if needed */); 

Add to where the specified middleware should be inside Configure .

 app.UseRuntimeMiddleware(runtimeApp => { //runtimeApp.Use... //Configurations here could be replaced during the runtime. }); 

Finally, you can reconfigure the runtime middleware from other parts of the application.

 //var runtimeMiddlewareService = serviceProvider.GetRequiredService<RuntimeMiddlewareService>(); //Or resolved via constructor. runtimeMiddlewareService.Configure(runtimeApp => { //runtimeApp.Use... //Configurations here would override the former ones. }); 
+1
source

Source: https://habr.com/ru/post/1264510/


All Articles