C# ASP.NET核心中间件构造函数中混合依赖注入和手动传递参数
我正在为ASP.NET Core 2.2编写一个自定义中间件。根据关于定制中间件的书面说明: 中间件组件可以通过构造函数参数从依赖项注入(DI)中解析它们的依赖项<代码>使用中间件也可以直接接受其他参数 这似乎很好,但它并没有说明当我混合使用这两种方法时会发生什么,例如在C# ASP.NET核心中间件构造函数中混合依赖注入和手动传递参数,c#,asp.net-core,dependency-injection,asp.net-core-2.2,asp.net-core-middleware,C#,Asp.net Core,Dependency Injection,Asp.net Core 2.2,Asp.net Core Middleware,我正在为ASP.NET Core 2.2编写一个自定义中间件。根据关于定制中间件的书面说明: 中间件组件可以通过构造函数参数从依赖项注入(DI)中解析它们的依赖项使用中间件也可以直接接受其他参数 这似乎很好,但它并没有说明当我混合使用这两种方法时会发生什么,例如在usemidware中使用DI和pass参数。例如,我有以下中间件: public class CustomMiddleware { public CustomMiddleware(RequestDelegate next, I
usemidware
中使用DI和pass参数。例如,我有以下中间件:
public class CustomMiddleware
{
public CustomMiddleware(RequestDelegate next, ILogger<CustomMiddleware> logger, CustomMiddlewareOptions options)
{
...
}
public async Task InvokeAsync(HttpContext context)
{
...
}
我自己对2.2的测试似乎表明,这很好,构造函数中参数的顺序并不重要(我可以将DI参数放在手动传递的参数之前或之后,甚至放在两个手动传递的参数之间)。但我在寻找一些保证,我所做的是好的。如果有人能指出一些支持这种用法的文档或源代码,那就太好了。谢谢
但我在寻找一些保证,我所做的是好的
这是基于意见的。在你的情况下,一切都正常,我相信。但我更喜欢使用ASP.NET核心中引入的
public class CustomMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<CustomMiddleware> _logger;
private readonly CustomMiddlewareOptions _options;
public CustomMiddleware(RequestDelegate next, ILogger<CustomMiddleware> logger, IOptions<CustomMiddlewareOptions> options)
{
_next = next;
_logger = logger;
_options = options.Value;
}
//...
}
在这种情况下,您应该添加不带参数的中间件
app.UseMiddleware<CustomMiddleware>();
app.UseMiddleware();
注意
这也值得一看
public RequestLocalizationMiddleware(RequestDelegate下一步,IOptions选项)
以及框架如何为您提供在中使用中间件的功能
公共静态IApplicationBuilder用户请求本地化(此IApplicationBuilder应用程序)
{
//省略
返回app.useMediddleware();
}
或
public静态IAApplicationBuilder用户请求本地化(此IAApplicationBuilder应用程序,请求本地化选项)
{
//省略
返回app.useMidleware(Options.Create(Options));
}
正如您所看到的,ASP.NET核心
开发人员也更喜欢在中间件构造函数中使用IOptions
,在手动指定附加参数时,他们只需将其包装到选项中
我自己对2.2的测试似乎表明,这很好,构造函数中参数的顺序并不重要(我可以将DI参数放在手动传递的参数之前或之后,甚至放在两个手动传递的参数之间)。但我想得到一些保证
对。在阅读了源代码之后,我会说它很好
工作原理
您的CustomMiddleware
是一个按约定的中间件(不同于基于工厂的中间件),它由以下激活:
var-ctorArgs=新对象[args.Length+1];
ctorArgs[0]=下一个;
Array.Copy(args,0,args,1,args.Length);//
var instance=ActivatorUtilities.CreateInstance(app.ApplicationServices、中间件、参数);
这里的args
(给定参数)是传递到usemidleware(args)
(不带下一个)的参数数组
在准备构造函数参数时,有两个阶段:
将给定的args
与构造参数类型匹配。并在类型匹配时设置值。看
使用ServiceProvider.GetRequiredService()
填充null
元素。请参阅。如果服务实例仍然为null
,则使用默认值
例如,假设:
您有一个by convention中间件,其构造函数具有以下签名:
public CustomMiddleware(RequestDelegate next, A a, B b, C c, D d, E e){ ... }
然后我们在注册中间件时传入两个参数:
app.UseMiddleware(c, a)
其中,c
是c
类型的实例,a
是a
类型的实例。因此givenParameters
数组是[下一步,c,a]
要创建CustomMiddleware
的实例,编译器需要知道完整的构造函数参数值。DI扩展在两个阶段内获取此构造函数参数值数组(\u parameterValues
)。请参阅:
阶段2的工作方式如下所示:
b'= sp.GetService(B);
if b' == null :
b' = default value of B
如上所示,ActivatorUtilities.CreateInstance(sp、mw、args)
API自动处理顺序和缺少的参数
作为补充说明,by convention中间件在启动时激活,并且始终是单例的。如果要使用作用域服务,请参阅
public static IApplicationBuilder UseRequestLocalization(this IApplicationBuilder app)
{
//omitted
return app.UseMiddleware<RequestLocalizationMiddleware>();
}
public static IApplicationBuilder UseRequestLocalization(this IApplicationBuilder app, RequestLocalizationOptions options)
{
//omitted
return app.UseMiddleware<RequestLocalizationMiddleware>(Options.Create(options));
}
public CustomMiddleware(RequestDelegate next, A a, B b, C c, D d, E e){ ... }
app.UseMiddleware(c, a)
b'= sp.GetService(B);
if b' == null :
b' = default value of B