首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么要写到HttpContext.Response“短路”MVC管道?

为什么要写到HttpContext.Response“短路”MVC管道?
EN

Stack Overflow用户
提问于 2022-07-15 14:47:54
回答 3查看 53关注 0票数 1

以下是代码:

代码语言:javascript
运行
复制
public class Startup
{
   // ...
   public void Configure(IApplicationBuilder app)
   {
      app.UseRouting();

      app.Use(async (context, next) =>
      {
         await context.Response.WriteAsync("write sth first\n");
         await next();
      });

      app.UseEndpoints(endpoints =>
      {
         endpoints.MapControllers();
      });

   }
}

我只得到了“先写东西”的回复,控制器的动作方法生成的内容没有附加到响应中。但是,我把调试器放在控制器的动作方法上,调试器命中了,这意味着MVC管道还在运行(这并不是真正的短路),那么为什么动作方法的响应不在响应中呢?

更让我困惑的是,如果我将代码更改为:

代码语言:javascript
运行
复制
public class Startup
{
   // ...
   public void Configure(IApplicationBuilder app)
   {
      app.UseRouting();

      app.Use(async (context, next) =>
      {
         await context.Response.WriteAsync("write sth first\n");
         await next();
      });

      app.UseEndpoints(endpoints =>
      {
         endpoints.MapGet("/", async context => {   
            await context.Response.WriteAsync("Hello World!");
         });
      });

   }
}

然后我得到了一个响应,即“首先写某物\n你好世界!”,那么为什么这次来自端点的响应被附加到响应中呢?

endpoints.MapControllers()中是否有检查HttpContext.Response的地方,比如是否有内容,然后中止剩余的进程?这个部分的源代码在哪里?

EN

回答 3

Stack Overflow用户

发布于 2022-07-15 16:17:17

这是我尝试的错误

System.InvalidOperationException: Headers are read-only, response has already started.

因此,它与中间件或MVC管道无关。控制器需要写入HTTP头,但它不能写入,因为响应已经启动。

票数 1
EN

Stack Overflow用户

发布于 2022-07-15 16:45:46

考虑到其他中间件也可能需要写入Response,您不应该自己开始编写它。您可以尝试将其附加到OnStarting事件。这样,您就不会自己启动响应(从内存中伪代码):

代码语言:javascript
运行
复制
app.Use(async (context, next) =>
{
    context.Response.OnStarting(async () =>
    {
        await context.Response.WriteAsync("write sth first\n");
    });

    await next();
}

为什么这一次来自端点的响应被附加到响应

这是因为端点中间件是在定制中间件之后调用的。因此,它首先调用您的中间件,然后调用端点中间件。中间件订单很重要。

票数 0
EN

Stack Overflow用户

发布于 2022-07-18 19:24:50

基于tia的回答,我试图替换默认的响应体,并且Response.HasStarted属性为false,您可以看到页面是用启动时间和结束时间呈现的,context.Response.WriteAsync不会短路管道:

代码语言:javascript
运行
复制
app.Use(async (context, next) =>
            {
                var response = context.Response;
                var responseOriginalBody = response.Body;
                using var memStream = new MemoryStream();
                response.Body = memStream;

                await context.Response.WriteAsync(string.Format("<a>starttime:{0}</a>", DateTime.Now.ToString("yyyy/MM/dd/HH:mm:ss.fff")));
                var start = context.Response.HasStarted;                
                await next.Invoke();
                await context.Response.WriteAsync(string.Format("<a>endtime:{0}</a>", DateTime.UtcNow.ToString("yyyy/MM/dd/HH:mm:ss.fff")));
                
                memStream.Position = 0;
                await memStream.CopyToAsync(responseOriginalBody);
                response.Body = responseOriginalBody;
            });

结果:

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72995789

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档