【问题标题】:Using middleware config from extension methods in ASP.NET Core在 ASP.NET Core 中使用扩展方法中的中间件配置
【发布时间】:2018-07-15 01:10:24
【问题描述】:

我开发了一个 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 的值保存在中间件内的公共静态变量中,并通过我的扩展方法访问它:

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

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

【问题讨论】:

  • 您可以将中间件类实例添加到 IoC 容器中,并在需要时使用注入来获取对它的引用。
  • 这样的扩展方法不会有太大的成功。你不能用它解决任何非静态的东西,而且 ASP.NET Core 按设计 避免了静态。正确的方法是创建某种需要通过依赖注入来解决的帮助程序。 ——话虽如此,这究竟是一种什么样的价值?这是一个特定于请求的值(那么静态无论如何都是错误的方法)还是真的只是构造一次?它是在您的代码中固定的常量,还是来自配置?
  • @poke 每个应用程序的值确实是静态的,并且只创建一次。能够在 config 中指定值并将其注入到各个地方(如其他推荐和答案中所建议的那样)肯定会改进代码。但它不会使扩展方法中的值可用。
  • @poke 如果你想看一些真实的代码,这是我做的一个 PR,实现了静态变量(我不喜欢):github.com/elmahio/Elmah.Io.AspNetCore/pull/2

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


【解决方案1】:

一般来说,这不适用于扩展方法。扩展方法是静态的,因此只能访问其他静态成员。然而,ASP.NET Core 按设计不使用任何静态,并广泛使用 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&lt;&gt; 模式在ConfigureServices 级别对其进行配置。在将中间件添加到 Configure 中的管道时配置中间件不再是 ASP.NET Core 2 中的常见模式。

【讨论】:

  • 哇。不知道HttpContext 上的RequestServices 属性。现在唯一缺少的是,我的Use 方法需要注册ElmahIoConfiguration 对象。你知道这是否可能吗?我似乎无法通过应用生成器找到对服务集合的引用。
  • 在考虑它时,添加一个新的AddElmahIo-方法(它需要所有配置)可能更漂亮。然后要求客户端通过ConfigureServices-方法调用它。 AddElmahIo-方法将向服务集合添加一个单例对象。然后UseElmahIo-方法将通过app.ApplicationServices.GetService 拉取配置对象,扩展方法将通过HttpContext (RequestServices.GetService) 拉取配置。你怎么看?
  • 是的,您可以在Configure 中创建一个services.AddElmahIo,在其中设置和配置您的组件,然后您将只使用Configure 中的中间件,然后注入必要的依赖项和配置本身。 – 不需要UseElmahIo 从 DI 中提取任何内容,中间件对象本身应该这样做。 UseElmahIo 应该等同于 app.UseMiddleware&lt;ElmahIoMiddleware&gt;()
  • (顺便说一句。如果您最终为此创建了一个新的拉取请求,请随时 ping 我,我会查看它:))
  • 你不会用以下方法拉取配置:public static IApplicationBuilder UseElmahIo(this IApplicationBuilder app)。或者您会将其延迟到中间件类本身? Invoke-方法将 HttpContext 作为参数,因此解析配置可能晚于 Invoke-方法。
【解决方案2】:

为什么不使用 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)

【讨论】:

  • 将值移动到 appsettings.json 并添加到 DI 不会使其可用于扩展方法。我同意,指定这样的设置将是一个很好的解决方案,但我需要的是能够基本上从静态方法访问它们。
  • 对不起,我一定是误会了问题,为什么需要通过静态方法访问它?
  • 通常我不需要从静态方法访问它。但在这种情况下,我希望能够手动触发中间件内部的逻辑。这是一个异常记录中间件。在这种情况下,我希望能够通过在 Exception 类上创建日志扩展方法来手动记录异常:catch(Exception e) e.LogThis()
猜你喜欢
  • 2022-11-09
  • 2022-01-10
  • 1970-01-01
  • 2020-01-29
  • 2019-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多