在ASP.NET Core中使用扩展方法的中间件配置

时间:2018-02-05 08:10:21

标签: c# asp.net-core asp.net-core-2.0 asp.net-core-middleware

我开发了一块ASP.NET Core中间件。我在这篇文章中简化了中间件,以使问题更加清晰。

中间件在Startup.cs中配置如下:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ...
    app.UseMyMiddleware(42);
    ...
}

整数(42)存储在中间件实例中,一切都很好。

现在我想创建一些辅助方法作为扩展方法:

public static int Add(this int i)
{
    return i + TODO;
}

我希望该方法将i的值添加到发送到中间件的值(42)。

目前我已将42的值保存在中间件内的公共静态var中,并通过我的扩展方法访问它:

public static int Add(this int i)
{
    return i + MyMiddleware.Value;
}

由于种种原因,我不喜欢这种解决方案。任何关于如何以更好的方式解决这个问题的想法都将受到高度赞赏。

2 个答案:

答案 0 :(得分:1)

通常,这不适用于扩展方法。扩展方法是静态的,因此只能访问其他静态成员。但是,ASP.NET Core by design 不使用任何静态,并广泛使用dependency injection来管理对象的生命周期和访问依赖项。

通常,正确的方法是将扩展方法移动到某种非静态辅助对象中,然后可以在需要访问它的地方注入它。当然,这不允许您在任何需要的地方轻松调用它,但需要显式依赖它(这是依赖注入点之一)。

话虽如此,你的明确案例有点不同。正如我在linked pull request中看到的那样,您的扩展方法看起来像这样(注意,我在这里结合了两种方法来说明这一点):

public static async Task ShipAsync(this Exception exception, HttpContext context)
{
    await MessageShipper.ShipAsync(
        ElmahIoMiddleware.ApiKey.AssertApiKeyInMiddleware(),
        ElmahIoMiddleware.LogId.AssertLogIdInMiddleware(),
        exception.Message, context, new ElmahIoSettings(), exception);
}

为什么重要?因为您正在通过HttpContext。 HTTP上下文使我们可以访问依赖注入。所以我们实际上可以从依赖注入容器中解决问题:

public static async Task ShipAsync(this Exception exception, HttpContext context)
{
    var elmahIoConfig = context.RequestServices.GetService<ElmahIoConfiguration>();

    await MessageShipper.ShipAsync(
        elmahIoConfig.ApiKey,
        elmahIoConfig.LogId,
        exception.Message, context, new ElmahIoSettings(), exception);
}

现在,您只需要确保在注册中间件时ElmahIoConfiguration正确填充。请注意,我不是在这里请求中间件实例,因为中间件通常没有注册依赖注入。引入一个单独的对象更有意义,然后可以将其注入中间件并在那里进行初始化。

在您的情况下,您应该将中间件配置真正移动到您的应用程序设置中,并使用IOptions<>模式在ConfigureServices级别配置它。将中间件添加到Configure中的管道中时配置中间件实际上不再是ASP.NET Core 2中的常见模式。

答案 1 :(得分:0)

为什么不使用appsettings.json存储此信息,然后使用内置的DI将其注入中间件?

<强> appsettings.json

{
    "MiddlewareConfiguration":
    {
        "MiddlewareValue":42,
    }
}

<强> Startup.cs

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.Configure<MiddlewareConfiguration>(configuration.GetSection("MiddlewareConfiguration"));
}

<强> MiddlewareConfiguration.cs

public class MiddlewareConfiguration
{
    public int MiddlewareValue { get; set; }
}

然后您可以将其注入中间件,例如:

public async Task Invoke(HttpContext context, IOptions<MiddlewareConfiguration> config)