0

I am trying to create a custom manager which is passed in the controller when it is being called and I am having troubles understanding the current implementation of new MVC5 project in c#.

Here is the default implementation:

public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager )
{
    UserManager = userManager;
    SignInManager = signInManager;
}

above all of that are declarations for them:

public ApplicationSignInManager SignInManager
{
    get
    {
        return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
    }
    private set 
    { 
        _signInManager = value; 
    }
}

public ApplicationUserManager UserManager
{
    get
    {
        return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
    }
    private set
    {
        _userManager = value;
    }
}

Now from my understanding the SignInManager and UserManager get created when application gets created for the first time in Startup.Auth.cs which looks like this:

app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

So now whenever I call UserManager I will get that first instance that was created when project ran for the first time.

I have 2 questions. Question 1 is is anything I said above wrong and Do I have a wrong understanding of how MVC5 works?

Question2: How is UserManager and SignInManager generated and passed in the controller? Where is the code that creates that first instance of the manager and passes it in the controller? I am assuming it is app.CreatePerOwnContext that does it. If so, can I then just create my own Manager and then register it with Owin in the same fashion and reuse throughout the project? Will my code get the latest data from the database if I do this and not cache it?

Bagzli
  • 6,254
  • 17
  • 80
  • 163
  • 1
    [Here is an article](http://tech.trailmax.info/2014/09/aspnet-identity-and-ioc-container-registration/) that shows step-by-step how to remove the service locator pattern if you are instead using Dependency Injection. If you are not using DI, you won't be able to pass the manager to the controller, instead you would have to new it up within the controller. – NightOwl888 Mar 22 '16 at 03:47

1 Answers1

4

The code you're showing is coming from the IMO very ugly MVC5 template, which works out of the box but does some ugly things.

This constructor:

public AccountController(ApplicationUserManager userManager, 
       ApplicationSignInManager signInManager)

makes you think OWIN automagically injects the managers for you. But in fact this is not the case. That is why the template comes with the ugly properties you supplied in the questions. When you do not change anything to the template, the default constructor is called (also present in the template). To try it, just delete, or comment, the default constructor and you'll see the AccountController can't be created anymore.

So what is actually happening there is that both managers are located using the Service Locator anti pattern in the getters of the supplied properties.

So now whenever I call UserManager I will get that first instance that was created when project ran for the first time?

No this is not the case. What this line:

 app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

does, is creating a delegate to the Create method of both managers. The managers are cached within an Owin Request. The next request the delegates are called again and you get a fresh ApplicationUserManager etc.

To be a little bit more verbose this line could be rewritten as:

Func<ApplicationUserManager> userManagerFactory = () => ApplicationUserMangager.Create();
app.CreatePerOwinContext<ApplicationUserManager>(userManagerFactory);

So if you would a breakpoint here:

public ApplicationUserManager UserManager
{
    get
    {
        // place breakpoint here
         return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
    }
// ....

You would see that while stepping through the code, you will hit the line where you created the UserManagerFactory which in his turn will call the Create() method of the ApplicationUserManager.

How is UserManager and SignInManager generated and passed in the controller

It isn't! You would need to use dependency injection for that.

If so, can I then just create my own Manager and then register it with Owin in the same fashion and reuse throughout the project

Yes you can. You can completely refactor the ApplicationUserManager you also got 'for free' in the template. As long as you supply a factory method to the 'CreatePerOwinContext' extension method.

Will my code get the latest data from the database if I do this and not cache it? The instances are cached on per request base. So each request you will get a new one, with a new DbContext etc.

I'm unsure how familiar you are with dependency injection but MVC5 is a pretty easy framework to start with it, IMO.

I once wrote a blogpost how to configure my DI container of choice (Simple Injector) to use with the MVC5 template. I also wrote several answers here on SO regarding this template: specifically this one, should interest you. This one is interesting also!

Community
  • 1
  • 1
Ric .Net
  • 5,540
  • 1
  • 20
  • 39
  • Ok so that first example was definitely one of very confusing parts for me. I understand what DI is. I admit that I do not yet fully understand why it is needed, still need to do research on that but I know Ninject is a very popular way of doing this. I was trying to figure out if OWIN is injecting the two managers in question and by the looks of it, it deluded me that it is. – Bagzli Mar 22 '16 at 14:25
  • You said that owin will cache the delegates within the OWIN request. What is the lifespan of the owin request? Is it every time I recycle my iis? Is it every time a page is loaded or is it per user basis, login session? etc... – Bagzli Mar 22 '16 at 14:27
  • 1
    An OWIN request is as long as a normal HTTP Request before we got OWIN. – Ric .Net Mar 22 '16 at 15:15
  • so essentially every time I load the page I am creating Manager objects? – Bagzli Mar 22 '16 at 15:43
  • 1
    Yep! And thus a new DbContext, which is what you want/need. – Ric .Net Mar 22 '16 at 15:49
  • Thank you Ric, you have been most helpful. I have to admit I still feel lost on a few things. If you have the time to answer, I have written up a new question here that explains in detail my confusion: http://stackoverflow.com/questions/36161207/proper-mvc5-layered-implementation – Bagzli Mar 22 '16 at 17:26
  • Your confusion is solved as you deleted the question? – Ric .Net Mar 22 '16 at 21:19
  • actually no, I was told to move the question to here http://programmers.stackexchange.com/questions/313509/proper-mvc5-layered-implementation Sorry, I forgot to update the link for you. – Bagzli Mar 22 '16 at 21:30