小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

讓 .NET 輕松構(gòu)建中間件模式代碼(二)

 路人甲Java 2021-04-04

讓 .NET 輕松構(gòu)建中間件模式代碼(二)--- 支持管道的中斷和分支

Intro

上次實現(xiàn)了一個基本的構(gòu)建中間件模式的中間件構(gòu)建器,現(xiàn)在來豐富一下功能,讓它支持中斷和分支,分別對應(yīng) asp.net core 中的 applicationBuilder.RunapplicationBuilder.MapWhen

實現(xiàn)管道中斷

實現(xiàn)中間件的中斷其實很簡單,通過上一次的分析我們已經(jīng)知道,中間件每一個部分其實是一個上下文和 next 的委托,只需要忽略 next,不執(zhí)行 next 就可以了,就可以中斷后面中間件的執(zhí)行。

定義一個 Run 擴(kuò)展方法來實現(xiàn)方便的實現(xiàn)中間件中斷:

public static IPipelineBuilder<TContext> Run<TContext>(this IPipelineBuilder<TContext> builder, Action<TContext> handler)
{
    return builder.Use(_ => handler);
}

public static IAsyncPipelineBuilder<TContext> Run<TContext>(this IAsyncPipelineBuilder<TContext> builder, Func<TContext, Task> handler)
{
    return builder.Use(_ => handler);
}

實現(xiàn)分支

分支的實現(xiàn)主要是參考 asp.net core 里 applicationBuilder.Map/applicationBuilder.MapWhen 實現(xiàn)分支路由的做法,在 asp.net core 里,MapWhen 是一個擴(kuò)展方法,其實現(xiàn)是一個 MapWhenMiddleware,有興趣可以看 asp.net core 的源碼。

實現(xiàn)原理也挺簡單的,其實就是滿足分支的條件時創(chuàng)建一個全新的中間件管道,當(dāng)滿足條件的時候就就執(zhí)行這個分支中間件管道,否則就跳過這個分支進(jìn)入下一個中間件。

首先在 PipelineBuilder 的接口定義中增加了一個 New 方法用來創(chuàng)建一個全新的中間件管道,定義如下:

public interface IPipelineBuilder<TContext>
{
    IPipelineBuilder<TContext> Use(Func<Action<TContext>, Action<TContext>> middleware);

    Action<TContext> Build();

    IPipelineBuilder<TContext> New();
}

//
public interface IAsyncPipelineBuilder<TContext>
{
    IAsyncPipelineBuilder<TContext> Use(Func<Func<TContext, Task>, Func<TContext, Task>> middleware);

    Func<TContext, Task> Build();

    IAsyncPipelineBuilder<TContext> New();
}

實現(xiàn)就是直接創(chuàng)建了一個新的 PipelineBuilder<TContext> 對象,示例如下:

internal class PipelineBuilder<TContext> : IPipelineBuilder<TContext>
{
    private readonly Action<TContext> _completeFunc;
    private readonly List<Func<Action<TContext>, Action<TContext>>> _pipelines = new List<Func<Action<TContext>, Action<TContext>>>();

    public PipelineBuilder(Action<TContext> completeFunc)
    {
        _completeFunc = completeFunc;
    }

    public IPipelineBuilder<TContext> Use(Func<Action<TContext>, Action<TContext>> middleware)
    {
        _pipelines.Add(middleware);
        return this;
    }

    public Action<TContext> Build()
    {
        var request = _completeFunc;

        for (var i = _pipelines.Count - 1; i >= 0; i--)
        {
            var pipeline = _pipelines[i];
            request = pipeline(request);
        }

        return request;
    }

    public IPipelineBuilder<TContext> New() => new PipelineBuilder<TContext>(_completeFunc);
}

異步的和同步類似,這里就不再贅述,有疑問可以直接看文末的源碼鏈接

接著就可以定義我們的分支擴(kuò)展了

public static IPipelineBuilder<TContext> When<TContext>(this IPipelineBuilder<TContext> builder, Func<TContext, bool> predict, Action<IPipelineBuilder<TContext>> configureAction)
{
    return builder.Use((context, next) =>
    {
        if (predict.Invoke(context))
        {
            var branchPipelineBuilder = builder.New();
            configureAction(branchPipelineBuilder);
            var branchPipeline = branchPipelineBuilder.Build();
            branchPipeline.Invoke(context);
        }
        else
        {
            next();
        }
    });
}

使用示例

我們可以使用分支和中斷來改造一下昨天的示例,改造完的示例如下:

var requestContext = new RequestContext()
{
    RequesterName = "Kangkang",
    Hour = 12,
};

var builder = PipelineBuilder.Create<RequestContext>(context =>
        {
            Console.WriteLine($"{context.RequesterName} {context.Hour}h apply failed");
        })
        .When(context => context.Hour <= 2, pipeline =>
                {
                    pipeline.Use((context, next) =>
                    {
                        Console.WriteLine("This should be invoked");
                        next();
                    });
                    pipeline.Run(context => Console.WriteLine("pass 1"));
                    pipeline.Use((context, next) =>
                    {
                        Console.WriteLine("This should not be invoked");
                        next();
                        Console.WriteLine("will this invoke?");
                    });
                })
        .When(context => context.Hour <= 4, pipeline =>
            {
                pipeline.Run(context => Console.WriteLine("pass 2"));
            })
        .When(context => context.Hour <= 6, pipeline =>
            {
                pipeline.Run(context => Console.WriteLine("pass 3"));
            })

    ;
var requestPipeline = builder.Build();
Console.WriteLine();
foreach (var i in Enumerable.Range(1, 8))
{
    Console.WriteLine($"--------- h:{i} apply Pipeline------------------");
    requestContext.Hour = i;
    requestPipeline.Invoke(requestContext);
    Console.WriteLine("----------------------------");
}

輸出結(jié)果如下:

看輸出結(jié)果我們可以看到 Run 后面注冊的中間件是不會執(zhí)行的,Run 前面注冊的中間件正常執(zhí)行

然后定義的 When 分支也是正確執(zhí)行的~~

Reference

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多