如何为自定义 .Net 核心中间件注册服务



我目前正在尝试理解和使用DotNet Core中的自定义中间件。

根据Microsoft文档:

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/write?view=aspnetcore-3.1

中间件应遵循显式依赖原则,在其构造函数中公开其依赖关系。

因此,如果我遵循这个原则,我最终会得到这样的东西

显式依赖项版本

public static class ApplicationBuilderFeatureHeaderExtension
{
public static IApplicationBuilder UseFeatureHeaders(this IApplicationBuilder app, Action<FeaturePolicyStringBuilder> builder)
{
return app.UseMiddleware<FeaturePolicyHeaderMiddleware>(builder);
}
}

public class FeaturePolicyHeaderMiddleware
{
private RequestDelegate _next;
private Action<FeaturePolicyStringBuilder> _builder;
private FeaturePolicyStringBuilder _builderInstance;
public FeaturePolicyHeaderMiddleware(RequestDelegate next, Action<FeaturePolicyStringBuilder> builder, FeaturePolicyStringBuilder builderInstance)
{
_next = next;
_builderInstance = builderInstance;
_builder = builder;
_builder(_builderInstance);
}
public async Task Invoke(HttpContext context)
{
var header = _builderInstance.CreateFeaturePolicyHeader();
if (!context.Response.Headers.ContainsKey(header.Key))
{
context.Response.Headers.Add(_builderInstance.CreateFeaturePolicyHeader());
}
await _next.Invoke(context);
}
}

在这里,FeaturePolicyStringBuilder作为服务提供,并已在启动文件中注册。


其他版本(使用新版本(

public class FeaturePolicyHeaderMiddleware
{
private RequestDelegate _next;
private Action<FeaturePolicyStringBuilder> _builder;
private FeaturePolicyStringBuilder _builderInstance;
public FeaturePolicyHeaderMiddleware(RequestDelegate next, Action<FeaturePolicyStringBuilder> builder)
{
_next = next;
_builderInstance = new FeaturePolicyStringBuilder();
_builder = builder;
_builder(_builderInstance);
}
public async Task Invoke(HttpContext context)
{
var header = _builderInstance.CreateFeaturePolicyHeader();
if (!context.Response.Headers.ContainsKey(header.Key))
{
context.Response.Headers.Add(_builderInstance.CreateFeaturePolicyHeader());
}
await _next.Invoke(context);
}
}

在这个版本中,我只是"更新"依赖项,这意味着我不必将其注册为服务,这使得它更容易封装到它自己的项目中。
(我不确定这到底有多邪恶,在我看来,由于操作需要它作为一种类型,我已经与 FeaturePolicyStringBuilder 紧密耦合,所以为什么不更多的胶水!

问题有没有办法仍然遵循显式依赖关系原则,而不必向服务提供商显式注册这些依赖关系? 或者某种方法可以在 middlware 组件本身中注册它们?

谢谢!

PS:我在下面添加了构建器代码,以便代码的目的更加明确:根据gerry.inc的评论

public class FeaturePolicyStringBuilder
{
private string _featurePolicyString;
public KeyValuePair<string, StringValues> CreateFeaturePolicyHeader()
{
return new KeyValuePair<string, StringValues>("feature-policy", _featurePolicyString);
}
private void CreateDirective(string directiveName, Action<SourceBuilder> builder)
{
var builderObj = new SourceBuilder();
builder(builderObj);
_featurePolicyString += $"{directiveName} '{builderObj.GetPrefix()}' {builderObj.GetSources()};";
}
public FeaturePolicyStringBuilder Camera(Action<SourceBuilder> builder)
{
CreateDirective("camera", builder);
return this;
}
public FeaturePolicyStringBuilder Accelerometer(Action<SourceBuilder> builder)
{
CreateDirective("accelerometer", builder);
return this;
}
public FeaturePolicyStringBuilder Battery(Action<SourceBuilder> builder)
{
CreateDirective("battery", builder);
return this;
}
}

配置方法中的调用如下所示

app.UseFeatureHeaders(x => 
x.Camera(b =>
b.AddPrefix(HeaderPrefixEnum.HeaderPrefix.Self)
.AddSource("Test"))
.Accelerometer(b => 
b.AddPrefix(HeaderPrefixEnum.HeaderPrefix.Self)
.AddSource("Test")
.AddSource("Test")
.AddPrefix(HeaderPrefixEnum.HeaderPrefix.None)
.AddPrefix(HeaderPrefixEnum.HeaderPrefix.Src)));

给定构建器的配置方式,则应在添加中间件之前调用构建器和配置操作

public static class ApplicationBuilderFeatureHeaderExtension {
public static IApplicationBuilder UseFeatureHeaders(this IApplicationBuilder app, Action<FeaturePolicyStringBuilder> configureBuilder) {
FeaturePolicyStringBuilder builder = new FeaturePolicyStringBuilder();
configureBuilder?.Invoke(builder);
var header = builder.CreateFeaturePolicyHeader();
return app.UseMiddleware<FeaturePolicyHeaderMiddleware>(header);
}
}

并且中间件相应地重构

public class FeaturePolicyHeaderMiddleware {
private RequestDelegate _next;
private KeyValuePair<string, StringValues> header;
public FeaturePolicyHeaderMiddleware(RequestDelegate next, KeyValuePair<string, StringValues> header) {
_next = next;
this.header = header;
}
public async Task Invoke(HttpContext context) {
if (!context.Response.Headers.ContainsKey(header.Key)) {
context.Response.Headers.Add(header);
}
await _next.Invoke(context);
}
}

这种 DRY 方法允许更好地分离关注点,并明确指示中间件实际需要什么来执行其功能。

最新更新