代码之家  ›  专栏  ›  技术社区  ›  Troopers

分支执行后如何返回到管道根?

  •  2
  • Troopers  · 技术社区  · 6 年前

    app.Use<AuthenticationMiddleware1>();
    app.Map("/branch", (application) => {
        application.Use<AuthenticationMiddleware2>();
    });
    app.UseWebApi(new HttpConfiguration());
    

    http://server/branch 则未配置web api并返回404

    我试着写一本书 MapAndContinueMiddleware :

    public class MapAndContinueMiddleware:OwinMiddleware
    {
        public MapAndContinueMiddleware(OwinMiddleware next, MapOptions options) : base(next)
        {
            this.Options = options;
        }
    
        public MapOptions Options { get; }
    
    
        public async override Task Invoke(IOwinContext context)
        {
            if(context.Request.Path.StartsWithSegments(this.Options.PathMatch))
            {
                await this.Options.Branch(context).ContinueWith((previousTask) =>
                {
                    this.Next.Invoke(context);
                });
            }
            else
            {
                await this.Next.Invoke(context);
            }
        }
    }
    

    使用此扩展名:

    public static IAppBuilder MapAndContinue(this IAppBuilder app, string pathMatch, Action<IAppBuilder> configuration)
    {
        // create branch and assign to options
        IAppBuilder branch = app.New();
        configuration(branch);
    
        MapOptions options = new MapOptions {
            PathMatch = new PathString(pathMatch),
            Branch = (Func<IOwinContext, Task>)branch.Build(typeof(Func<IOwinContext, Task>))
        };
        return MapAndContinue(app, options);
    }
    
    public static IAppBuilder MapAndContinue(this IAppBuilder app, MapOptions options)
    {
        return app.Use<MapAndContinueMiddleware>(options);
    }
    

    但这有一个奇怪的行为:一个webapi请求运行分支两次,却没有返回到客户端。。。!?

    1 回复  |  直到 6 年前
        1
  •  2
  •   Nkosi    6 年前

    你试过继续执行分支后配置的管道吗

    var config = new HttpConfiguration();
    app.Use<AuthenticationMiddleware1>();
    app.Map("/branch", (application) => {
        application.Use<AuthenticationMiddleware2>();
        application.UseWebApi(config);
    });
    app.UseWebApi(config);
    

    回顾 Original MapExtension Source 似乎将中间件添加到管道的顺序很重要

    using AppFunc = Func<IDictionary<string, object>, Task>;
    
    //...
    
    public static class BranchAndMergeExtensions {
    
        public static IAppBuilder MapAndContinue(this IAppBuilder app, string pathMatch, Action<IAppBuilder> configuration) {
            return MapAndContinue(app, new PathString(pathMatch), configuration);
        }
    
        public static IAppBuilder MapAndContinue(this IAppBuilder app, PathString pathMatch, Action<IAppBuilder> configuration) {
            if (app == null) {
                throw new ArgumentNullException("app");
            }
            if (configuration == null) {
                throw new ArgumentNullException("configuration");
            }
            if (pathMatch.HasValue && pathMatch.Value.EndsWith("/", StringComparison.Ordinal)) {
                throw new ArgumentException("Path must not end with slash '/'", "pathMatch");
            }
    
            // put middleware in pipeline before creating branch
            var options = new MapOptions { PathMatch = pathMatch };
            var result = app.Use<MapAndContinueMiddleware>(options);
    
            // create branch and assign to options
            IAppBuilder branch = app.New();
            configuration(branch);
            options.Branch = (AppFunc)branch.Build(typeof(AppFunc));
    
            return result;
        }
    }
    

    这个 original MapMiddleware 还需要重构,以阻止它在分支之后调用根管道,从而使管道短路。

    public class MapAndContinueMiddleware : OwinMiddleware {
        private readonly MapOptions options;
    
        public MapAndContinueMiddleware(OwinMiddleware next, MapOptions options)
            : base(next) {
            this.options = options;
        }
    
        public async override Task Invoke(IOwinContext context) {
            PathString path = context.Request.Path;
            PathString remainingPath;
            if (path.StartsWithSegments(options.PathMatch, out remainingPath)) {
                // Update the path
                PathString pathBase = context.Request.PathBase;
                context.Request.PathBase = pathBase + options.PathMatch;
                context.Request.Path = remainingPath;
    
                //call branch delegate
                await this.options.Branch(context.Environment);
    
                context.Request.PathBase = pathBase;
                context.Request.Path = path;
            }
            // call next delegate
            await this.Next.Invoke(context);
        }
    }
    

    最终导致您原来的安装示例

    var config = new HttpConfiguration();
    app.Use<AuthenticationMiddleware1>();
    app.MapAndContinue("/branch", (application) => {
        application.Use<AuthenticationMiddleware2>();
    });
    app.UseWebApi(config);