为什么在HttpRequest结束后会第二次创建owin中间件

Why is owin middleware created a second time after the HttpRequest ended

question 之后,根据为什么 Asp.Net 中的 ApplicationDbContext 身份会根据请求创建和处理两次,我做了一些研究,为什么会发生这种情况。我发现 ApplicationDbContext 实际上是每个 HttpRequest 创建一次,但是当使用 Owin 管道时,Owin 中间件将在 HttpRequest 结束后第二次创建。

因此,当用户单击一个 link 时,ApplicationDbContext 确实是第二次创建,给人的印象是每个 WebRequest.[=27 创建了两次对象=]

经过大量研究后,我决定在不使用任何身份验证的情况下启动一个普通的 MVC 5 项目。从我创建的 NuGet 添加 Owin 中间件到以下 Owin Middleware 组件后。它基本上检查 HttpContext 字典中是否存在某些假对象,并在不存在时创建一个。输出被写入调试 window 以保持简单。

[assembly: OwinStartupAttribute(typeof(MvcPlain.Startup))]
namespace MvcPlain
{
    public class Startup {
        public static int Counter;
        public static string FakeKeyName;

        public void Configuration(IAppBuilder app) {
            app.Use(async (context, next) =>
            {
                Debug.WriteLine("Owin middleware entered => begin request");

                FakeKeyName = "owinKey" + Counter.ToString();
                var fakeKeyPresent = HttpContext.Current.Items.Contains(FakeKeyName);

                Debug.WriteLine(string.Format("{0} key present in HttpContext?: {1}", 
                                                        FakeKeyName, fakeKeyPresent));

                if (!HttpContext.Current.Items.Contains(FakeKeyName))
                {
                    Counter += 1;
                    HttpContext.Current.Items.Add(FakeKeyName, "someValue");
                }

                await next.Invoke();

                Debug.WriteLine("Owin middleware exited => end request");

                var keyStillPresent = HttpContext.Current.Items.Contains(FakeKeyName);
                Debug.WriteLine(string.Format("{0} still present in HttpContext?: {1}", 
                                                        FakeKeyName, keyStillPresent));
            });
        }
    }
}

然后将此添加到 HomeControllerIndex ActionMethod 以检查创建的对象是否仍然存在。

public ActionResult Index()
{
    Debug.WriteLine("Index actionmethod called");
    var fakeKeyPresent = HttpContext.Items.Contains(Startup.FakeKeyName);

    Debug.WriteLine(string.Format("{0} key present in HttpContext?: {1}",
                                            Startup.FakeKeyName, fakeKeyPresent));

    return View();
}

当 运行 输出 window 显示以下输出(为清楚起见添加注释):

--- home link clicked ---
Owin middleware entered => begin request
owinKey2 key present in HttpContext?: False
Index actionmethod called
owinKey2 key present in HttpContext?: True
Owin middleware exited => end request
owinKey2 key still present in HttpContext?: True
--- end of 'normal' request ---
Owin middleware entered => begin request
owinKey3 key present in HttpContext?: False
Owin middleware exited => end request
owinKey3 key still present in HttpContext?: True

那么为什么在评论end of 'normal' request之后,中间件又被创建并进入了呢?有人有任何想法或解释吗?

重现步骤:

  1. 在没有身份验证的情况下在 VS 2013 中启动一个新的 MVC 5 项目
  2. 在包管理器中使用 Install-Package Microsoft.Owin.Host.SystemWeb 从 NuGet 添加 Owin
  3. 如上所示在项目中添加启动class
  4. 将代码添加到 HomeController
  5. Index ActionMethod
  6. 在调试模式下按 F5
  7. 点击起始页'Home' link
  8. 观察输出中的输出(或立即取决于您的 VS 设置)window

这里最有可能发生的是 实际上有两个 单独的请求正在发生。第一个是针对您的 Home/Index 视图,第二个可能是浏览器发出类似 favicon.ico 的请求。 (浏览器往往会自动执行此操作。)

在中间件的开头,插入一个显示 context.Request.Path 值的调试助手,以查看每次请求 URL 的内容。