在ASP.Net Core

时间:2017-02-21 11:13:10

标签: c# authentication dependency-injection asp.net-core

当我的应用程序启动时,我有一堆模块(module1,module2 ......)。对于每个模块,我都有一堆控制器操作:

/myModuleController/module1/action1
/myModuleController/module1/action2
/myModuleController/module2/action1
/myModuleController/module2/action2
…

由于用户可以为每个模块记录一次,因此我为每个模块部署了一个身份验证中间件,只需这样做:

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

所以基本上,在url路径/myModuleController/module1上我有一个中间件加上它的cookie,另一个用于/myModuleController/module2 ...我觉得这有点不寻常但是它工作正常,我对这种行为感到满意。

问题出现了:我希望能够在运行时添加一个新模块,这意味着能够使用像app.UseWhen(url, app. UseCookieAuthentication(…))这样的代码部署新的中间件。我天真地尝试在负责添加模块的控制器中注入IApplicationBuilder app,但我得到了一个例外:

  

System.InvalidOperationException:无法解析类型' Microsoft.AspNetCore.Builder.IApplicationBuilder'的服务。在尝试激活' AdminController'

我的问题是:它应该有效吗?我一定是在某个地方弄错了?或者,你是否清楚我在这里尝试的东西没有机会工作?

您如何达到同样的要求? 感谢。

1 个答案:

答案 0 :(得分:1)

首先,我们需要一项服务来保留运行时中间件配置

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();
    }
}

然后添加一些扩展方法以在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;
    }
}

然后修改您的Startup

添加到ConfigureServices

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

添加到运行时指定的中间件应位于Configure内部的位置。

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

最后,您可以从应用程序的其他部分重新配置运行时中间件

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