Why is owin middleware created a second time after

2019-05-25 14:54发布

问题:

After a question as per why the ApplicationDbContext from Asp.Net Identity is created and disposed twice per Request I did some research why this would happen. I found that the ApplicationDbContext is actualy created once per HttpRequest but when using the Owin pipeline the Owin Middleware will be created a second time after the HttpRequest has ended.

Because of this the ApplicationDbContext is indeed created for a second time when a user clicks one link giving the impression that the object is created twice per WebRequest.

After a lot of research I decided to start a plain MVC 5 project without using any authentication. After adding the Owin Middleware from NuGet I created to following Owin Middleware component. Which basically checks if some fake object exist in the HttpContext dictionary and creates one when it doesn't. The output is written to the debug window to keep things simple.

[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));
            });
        }
    }
}

Then added this to the Index ActionMethod of the HomeController to check if the created object still exists.

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();
}

When ran the output window shows the following output (added comment for clarity):

--- 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

So why, after the comment end of 'normal' request, is the middleware created and entered again? Anyone has any idea or explanation?

Steps to reproduce:

  1. Start a new MVC 5 project in VS 2013 without authentication
  2. Add Owin from NuGet using Install-Package Microsoft.Owin.Host.SystemWeb in the package manager
  3. Add a startup class to the project as shown above
  4. Add the code to the Index ActionMethod of the HomeController
  5. Hit F5 in debug mode
  6. Click on the 'Home' link on the start page
  7. Watch the output in the output (or immediate depending on your VS setup) window

回答1:

What's most likely happening here is that there are actually two separate requests happening. The first is for your Home/Index view, and the second is probably the browser making a request for something like favicon.ico. (Browsers tend to do that automatically.)

At the beginning of your middleware, insert a debugging helper that reveals the value of context.Request.Path to see what URL is being requested each time.