简体   繁体   English

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

[英]Using middleware config from extension methods in ASP.NET Core

I've developed a piece of ASP.NET Core middleware. 我已经开发了一个ASP.NET Core中间件。 I've simplified the middleware in this post, to make the problem clearer. 为了简化问题,我在本文中简化了中间件。

The middleware is configured in Startup.cs like this: 中间件在Startup.cs配置如下:

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

The integer ( 42 ) is stored in the middleware instance and everything is fine. 整数( 42 )存储在中间件实例中,一切都很好。

Now I want to create some helper methods as extension methods: 现在,我想创建一些辅助方法作为扩展方法:

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

I would like the method to add the value of i to the value ( 42 ) sent to the middleware. 我想要将i的值添加到发送到中间件的值( 42 )的方法。

Currently I've saved the value of 42 in a public static var inside the middleware and access this from my extension method: 目前,我已经将值42保存在中间件内部的公共static var中,并通过我的扩展方法进行访问:

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

I don't like this solution for various reasons. 由于种种原因,我不喜欢这种解决方案。 Any ideas to how this can be solved in a better way would be highly appreciated. 如何更好地解决此问题的任何想法将受到高度赞赏。

In general, this won't work with extension methods. 通常,这不适用于扩展方法。 Extension methods are static and as such can only access other static members. 扩展方法是静态的,因此只能访问其他静态成员。 ASP.NET Core however is by design not using any statics and extensively uses dependency injection to manage the lifetime of objects and to access dependencies. 但是 ASP.NET Core 在设计上不使用任何静态变量,并且广泛使用依赖项注入来管理对象的生存期和访问依赖项。

So usually, the proper way would be to move your extension method into some kind of non-static helper object which you can then inject where you need to access it. 因此,通常,正确的方法是将扩展方法移到某种非静态帮助器对象中,然后可以将其插入需要访问它的位置。 Of course, this will not allow you to easily call it wherever you need it but requires you to explicitly depend on it (which is one of the points of dependency injection). 当然,这将不允许您在需要的地方轻松调用它,而需要您明确依赖它(这是依赖注入的要点之一)。

That being said, your explicit case is a bit different. 话虽如此,您的明确情况有些不同。 As I could see from your linked pull request , your extension method looks like this (note, I combined two methods here to make it clear): 链接的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);
}

Why does that matter? 为什么这么重要? Because you are passing HttpContext . 因为您正在传递HttpContext And the HTTP context gives us access to dependency injection. HTTP上下文使我们可以访问依赖项注入。 So we can actually resolve things from the dependency injection container: 因此,我们实际上可以从依赖项注入容器中解决问题:

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

Now, you just need to make sure that ElmahIoConfiguration gets filled properly when you register the middleware. 现在,您只需要确保注册中间件时就可以正确填充ElmahIoConfiguration Note that I am not requesting the middleware instance here because middlewares are usually not registered with dependency injection. 请注意,在这里我不要求中间件实例,因为中间件通常不向依赖项注入注册。 It makes more sense to introduce a separate object which you can then inject into the middleware and initialize there. 引入一个单独的对象更有意义,然后您可以将该对象注入中间件并在那里进行初始化。

In your case, you should really move the middleware configuration into your application settings and use the IOptions<> pattern to configure it at ConfigureServices level. 在您的情况下,您实际上应该将中间件配置移到应用程序设置中,并使用IOptions<>模式在ConfigureServices级别对其进行ConfigureServices Configuring middleware as you add it to the pipeline in Configure is not really a common pattern in ASP.NET Core 2 anymore. 在ASP.NET Core 2中将中间件添加到“ Configure的管道时进行Configure实际上不再是一种常见的模式。

Why don't you use the appsettings.json to store this information and then use the built-in DI to inject it into your middleware? 您为什么不使用appsettings.json来存储此信息,然后使用内置的DI将其注入到中间件中?

appsettings.json appsettings.json

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

Startup.cs Startup.cs

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

MiddlewareConfiguration.cs MiddlewareConfiguration.cs

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

You can then inject it into your middleware, eg: 然后可以将其注入到中间件中,例如:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM