c# - 在 ASP.NET Core 中间件构造函数中混合依赖注入和手动传递的参数
问题描述
我正在为 ASP.NET Core 2.2 编写一个自定义中间件。根据Microsoft Docs on writing custom middlewares:
中间件组件可以通过构造函数参数从依赖注入 (DI) 中解析它们的依赖关系。
UseMiddleware<T>
也可以直接接受附加参数。
这似乎一切都很好,但它并没有说明当我混合这两种方式时会发生什么,例如使用 DI 并在UseMiddleware<T>
. 例如,我有以下中间件:
public class CustomMiddleware
{
public CustomMiddleware(RequestDelegate next, ILogger<CustomMiddleware> logger, CustomMiddlewareOptions options)
{
...
}
public async Task InvokeAsync(HttpContext context)
{
...
}
wherelogger
由 DIoptions
提供,如下所示:
app.UseMiddleware<CustomMiddleware>(new CustomMiddlewareOptions());
我自己对 2.2 的测试似乎表明这很好用,并且构造函数中参数的顺序无关紧要(我可以将 DI 参数放在手动传递的参数之前或之后,甚至可以放在两个手动传递的参数之间) . 但我正在寻找一些保证,即我正在做的事情是好的。如果有人能指出一些支持这种用法的文档或源代码,那就太好了。谢谢!
解决方案
我自己对 2.2 的测试似乎表明这很好用,并且构造函数中参数的顺序无关紧要(我可以将 DI 参数放在手动传递的参数之前或之后,甚至可以放在两个手动传递的参数之间) . 但我正在寻找一些保证
是的。看完源代码,我会说没问题。
这个怎么运作
YourCustomMiddleware
是一个约定俗成的中间件(不同于基于工厂的中间件),由ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs) 激活:
var ctorArgs = new object[args.Length + 1];
ctorArgs[0] = next;
Array.Copy(args, 0, ctorArgs, 1, args.Length); //
var instance = ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs);
这里的args
(Given Arguments) 是您传递给UseMiddleware<CustomMiddleware>(args)
(不带next
) 的参数数组。
准备构造函数参数时有两个阶段:
- 匹配给定
args
的构造参数类型。并在类型匹配时设置值。在此处查看源代码 - 使用填充
null
元素。请参阅ServiceProvider.GetRequiredService<SomeService>()
此处的源代码。如果服务实例仍然是null
,则使用该default
值。
例如,假设:
- 您有一个约定俗成的中间件,其构造函数具有以下签名:
public CustomMiddleware(RequestDelegate next, A a, B b, C c, D d, E e){ ... }
然后我们在注册中间件时传入两个参数:
app.UseMiddleware(c, a)
其中
c
是 Type 的一个实例C
,并且a
是 Type 的一个实例A
。所以givenParameters
数组是[next,c, a]
要创建 的实例CustomMiddleware
,编译器需要知道完整的构造函数参数值。DI 扩展_parameterValues
在两个阶段内获取此构造函数参数值数组 ()。请参阅:
stage2 的工作方式如下:
b'= sp.GetService(B);
if b' == null :
b' = default value of B
正如您在上面看到的,ActivatorUtilities.CreateInstance(sp,mw,args)
API 会自动处理顺序和缺失的参数。
作为旁注,按惯例中间件在启动时激活,并且始终是单例的。如果您想使用范围服务,请参阅此线程
推荐阅读
- docker - 是否可以为不同的服务使用不同的 .env?
- c# - Anaconda 3 中的 Pythonnet 导入错误 Visbrain
- ruby - puts 的 Ruby 文档中的“ios”是什么?
- .net-core - .net core 2.1 上的 Kestrel 网络传输速度非常慢
- python - 用python合并iqy文件
- mysql - 创建 SUM 表的触发器并插入另一个表
- c# - XmlWriter 不会正确生成我需要的命名空间
- python - SQL Alchemy:嵌套复合列类型和自定义类型
- java - How to determine if Couchbase Server version supports the Extended Attributes (xattrs) feature?
- internationalization - Bahasa / 印度尼西亚和他加禄语 / 菲律宾的语言环境是什么?是 id_ID 和 tl_PH 吗?