ASP.NET Web API HttpContext Response 在 IOwinContext Response



我们在 IIS 中托管的 ASP.NET Web API 2 项目中使用 Owin 中间件。

我目前正在遇到一个奇怪的现象,即 IOwinContext.Response.Body 没有被写入,实际上,即使我在唤醒 Next.Invoke() 后在中间件中设置了一个断点并且它被击中,响应已经发送回服务器,即使我还没有继续。

当我查看IOwinContext上的响应正文时,它是空的。但是,我可以从 HttpContext.Response.Filter 获得响应。当我使用 HttpContext 并命中断点时,在我继续之前不会发回响应。下面是我们的 Startup.cs 类中使用的当前配置方法。

public async void Configuration(IAppBuilder app)
{
try
{
// Global Config
var config = GlobalConfiguration.Configuration;
// configure dependency injection
UnityConfig.RegisterComponents();
// configure log for net
log4net.Config.XmlConfigurator.Configure();
// turn around all requests right here
app.Use(async (context, next) =>
{
if (context.Request.Path.ToString() == "/")
{
string text = "UP";
context.Response.StatusCode = 200;
context.Response.ReasonPhrase = text;
await context.Response.WriteAsync(text);
return;
}
await next.Invoke();
});
// Handle exceptions in the OWIN layer here
app.UseUncaughtExceptionHandler();
// add cors headers
app.Use(async (context, next) => { });
// some UI stuff
app.Use(async (context, next) => { });
// Log Request Metrics
app.UseLogRequestMetrics();
// Evaluate Partner Key
app.MapWhen(context => Regex.IsMatch(context.Request.Uri.PathAndQuery.ToLower(), @"/api"), newApp =>
{
#if !DEBUG
newApp.Use<Middleware1>();
#endif
newApp.Use<Middleware2>();
newApp.Use<Middleware3>(); // On the response path back, the IOwinResponse body is already empty
});
WebApiConfig.Register(config);
app.UseWebApi(config); // It seems like I'm losing the response in here, but I don't really know
config.EnsureInitialized();
// Configure object mapping
AutoMapperConfig.Configure();
}
catch (Exception ex)
{
await LogForNetErrorLogger.LogError(ex);
}
}

我很确定我的中间件搞砸了,但是在等待 Next.Invoke() 之后,响应在回到我的第一个中间件(中间件 3)之前已经消失了。

任何见解或发人深省将不胜感激。另外,如果这还不够,请告诉我。

所以,就像我上面的帖子一样,我认为问题是 HttpResponse 在 IOwinResponse 之前被发回。事实证明,我完全忽略了映射部分:

app.MapWhen(context => Regex.IsMatch(context.Request.Uri.PathAndQuery.ToLower(), @"/api"), newApp =>
{
#if !DEBUG
newApp.Use<Middleware1>();
#endif
newApp.Use<Middleware2>();
newApp.Use<Middleware3>();
});

当您使用app.Map()时,它会分支中间件。因此,如果路径与"/api"匹配,它将分支。但是,它也仍在使用app.UseWebApi()组件,这就是为什么我有两个不同的响应以及为什么我期望的响应没有写入Middleware3组件的IOwinContext。 我通过删除app.MapWhen()方法修复了它,并从中更改它:

app.MapWhen(context => Regex.IsMatch(context.Request.Uri.PathAndQuery.ToLower(), @"/site"), newApp =>
{
#if !DEBUG
newApp.Use<Middleware1>();
#endif
newApp.Use<Middleware2>();
newApp.Use<Middleware3>(); // On the response path back, the IOwinResponse body is already empty
});

对此:

#if !DEBUG
newApp.Use<Middleware1>();
#endif
newApp.Use<Middleware2>();
newApp.Use<Middleware3>();

并将这段代码放在中间件组件的开头Middleware1Middleware2Middleware3

public override async Task Invoke(IOwinContext context)
{
if (!context.Request.Path.ToString().StartsWith("/api/"))
{
await Next.Invoke(context);
return;
}
// stuff I want to run if the above doesn't match
await Next.Invoke(context);
...
}

好吧,至少修复很简单,即使我花了三个星期才找到它。如果你想阅读IAppBuilder.MapWhen扩展方法,这里有一些文档 https://msdn.microsoft.com/en-us/library/owin.mapwhenextensions.mapwhen(v=vs.113).aspx。

最新更新