簡體   English   中英

如何為自定義 .Net Core 中間件注冊服務

[英]How To Register Services For Custom .Net Core Middleware

我目前正在嘗試理解和使用 DotNet Core 中的自定義中間件。

根據微軟文檔:

https://docs.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);
    }
}

在這個版本中,我只是簡單地“更新”依賴項,這意味着我不必將其注冊為服務,這使得更容易封裝到它自己的項目中。
(我不確定這到底有多邪惡,在我看來,由於 Action 需要它作為一種類型,我已經與 FeaturePolicyStringBuilder 緊密耦合,所以為什么不添加更多膠水!)

問題有沒有辦法在不必向服務提供者顯式注冊這些依賴項的情況下仍然遵循顯式依賴項原則? 或者某種方式在中間件組件本身中注冊它們?

謝謝!

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

Configure 方法中的調用是什么樣的

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 方法允許更好地分離關注點,並明確指示中間件實際需要什么來執行其功能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM