分支执行后如何return到管道根?
How to return to pipeline root after branch executing?
在 OWIN 管道中,我使用分支来配置自定义身份验证中间件。分支执行后如何return管道根?
app.Use<AuthenticationMiddleware1>();
app.Map("/branch", (application) => {
application.Use<AuthenticationMiddleware2>();
});
app.UseWebApi(new HttpConfiguration());
当我请求 http://server/branch
时,web api 未配置并且 return 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);
}
但这有一个奇怪的行为:网络 api 两次请求 运行 分支并且不 return 客户端...!?
您是否尝试过在分支后按照配置继续管道
var config = new HttpConfiguration();
app.Use<AuthenticationMiddleware1>();
app.Map("/branch", (application) => {
application.Use<AuthenticationMiddleware2>();
application.UseWebApi(config);
});
app.UseWebApi(config);
这样在分支之后它仍然可以使用 Web API
查看 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);
在 OWIN 管道中,我使用分支来配置自定义身份验证中间件。分支执行后如何return管道根?
app.Use<AuthenticationMiddleware1>();
app.Map("/branch", (application) => {
application.Use<AuthenticationMiddleware2>();
});
app.UseWebApi(new HttpConfiguration());
当我请求 http://server/branch
时,web api 未配置并且 return 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);
}
但这有一个奇怪的行为:网络 api 两次请求 运行 分支并且不 return 客户端...!?
您是否尝试过在分支后按照配置继续管道
var config = new HttpConfiguration();
app.Use<AuthenticationMiddleware1>();
app.Map("/branch", (application) => {
application.Use<AuthenticationMiddleware2>();
application.UseWebApi(config);
});
app.UseWebApi(config);
这样在分支之后它仍然可以使用 Web API
查看 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);