1

I'm working on a Web App where I instantiated my a Singleton class below in Startup.cs in order to be reused (more like making a programmable session):

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

But I'm encountering a problem, as soon as UserA logs in on the app, the information inside XYZManager class gets overwritten when UserB enters and vice versa when they perform some action.

The problem I think is, they're sharing the same application pool, how can this be resolve, any hack?

An meanwhile the whole essence of this approach, I want to be able to call any getter / setter of method inside XYZManager for the current logged user for example:

HttpContext.GetOwinContext().Get<XYZManager>().GetFullDetails();

But sometimes throw details for another logged on user based on operations.

 public class XYZManager : IDisposable
 {
     private static XYZManager instance  { get; set; }
     public static  XYZManager Create()
     {
        var xyzManager = instance ?? (instance = new XYZManager());
        xyzManager.ApplicationDbContext = new ApplicationDbContext();
        return xyzManager;
     }
     public string GetFullDetails () {
        return "blah blah";
     }
 }
  • I cannot see any singleton, I only see an instance created *per request* (an owin context is created on every request). Your issue is certainly caused by your `XYZManager` class design. – Federico Dipuma Nov 08 '17 at 13:10
  • Thanks @FedericoDipuma I will update my questions with the XYZManager Singleton – Emmanuel Osinnowo Nov 08 '17 at 13:14
  • @FedericoDipuma see my updated post, what could be wrong? – Emmanuel Osinnowo Nov 08 '17 at 13:25
  • Afaik CreatePerOwinContext, will try to create a separate singleton instance each time user logs in with your provided method (Create), but instead of creating a new one it returns the old instance. I think you shouldn't use a singleton here. – Ernis Nov 08 '17 at 13:25
  • @Ernis, what should I use? – Emmanuel Osinnowo Nov 08 '17 at 13:26
  • Why your `Create` method returns the same instance in the first place? Having your `XYZManager` as a singleton just means that **any** thread/request will share its internal parameters. It's not clear at all what you want to achieve, but clearly a singleton instance for your purpose is the wrong choice. – Federico Dipuma Nov 08 '17 at 13:27
  • Just return a new instance, not a singleton, and HttpContext.GetOwinContext().Get() will return that same created instance – Ernis Nov 08 '17 at 13:27
  • @Ernis, another question I kept on asking myself why is HttpContext.GetOwinContext().GetUserManager() not returning another logged on user's UserManager? – Emmanuel Osinnowo Nov 08 '17 at 13:29
  • @Ernis, I tried that but still same result, I will try again anyway...Thanks – Emmanuel Osinnowo Nov 08 '17 at 13:30
  • @FedericoDipuma, I knew somebody would ask me this question. But the sorrow thing is...even without wiring-up my XYZManager with Owin, the result was still the same, I was formally using it without Owin where each users shares resources and overwrites their information on the fly – Emmanuel Osinnowo Nov 08 '17 at 13:33
  • You need to create a new instance **per request** and dispose of the instance at the end of each request. There are plenty of tutorials out there on how to do this but really you should be using a DI pattern where you inject any dependencies you need into your ApiController instance(s). You should not have to create factories to create your dependencies. – Igor Nov 08 '17 at 13:45
  • BTW: If you want to set this up using an IoC container I wrote an answer a while back that uses NInject but you can substitute another framework like AutoFac. See https://stackoverflow.com/a/36296270/1260204 – Igor Nov 08 '17 at 14:14
  • @Igor, this is not about Dependency Injection, every design pattern has their own solution to a problem. Why I'm trying to use this, is to have a in-memory programmable session if I may explain. I know DI, and I uses Unity / SimpleInjector. – Emmanuel Osinnowo Nov 08 '17 at 14:20
  • DI would solve the problem assuming you register the type as new instance per request. You are creating a singleton where there should not be one (`static XYZManager instance`). It *might* be ok if this was a windows application where the application instance was serving only a single user. For a web application though this will cause multiple run time bugs like the one you are experiencing now. You want a new instance per request, a DI framework can easily provide that for you. So I encourage you to use Unity or SimpleInjector (pick your favorite) and register the manager type that way. – Igor Nov 08 '17 at 14:25
  • *continued* ^^^------- See the previous answer https://stackoverflow.com/a/36296270/1260204 for specifics on how to register the owin types. – Igor Nov 08 '17 at 14:25
  • @Igor I think you're making more sense, but let me give a try and get back to you on that...thanks so much. – Emmanuel Osinnowo Nov 08 '17 at 14:30
  • _The problem I think is, they're sharing the same application pool_ Yes, not only are all your users sharing the same application pool. Multiple web sites may share a single application pool. Each application pool executes in a Windows process. However, every ASP.NET website in an application pool (process) will be in a separate appdomains to keep them isolated. Trying to provide a separate application pool for every user does not make any sense. – Martin Liversage Nov 08 '17 at 14:44
  • @Martin Liversage, please don't quote me wrong...I'm not trying to create separate application pool, I just want a hack to this problem, in such a way, single instance of class should be apply for one application (current session) for the current user. – Emmanuel Osinnowo Nov 08 '17 at 14:48
  • @EmmanuelOsinnowo: My quote from your answer is exactly what you have written so I fail to see how it is wrong. I am just trying to provide some insight into the concept af application pools. Hacking with the application pool will not solve your problem. That is basically what I am trying to say (with some bonus information). – Martin Liversage Nov 08 '17 at 15:02
  • 1
    @MartinLiversage Thanks so much, really appreciate – Emmanuel Osinnowo Nov 26 '17 at 07:15

1 Answers1

1

As described in msdn, the CreatePerOwinContext method will accept a factory method to create an instance of your class (in this cas XYZManager), and it will keep it for all same context requests with.

HttpContext.GetOwinContext().Get<XYZManager>()

So each time a new Owin Context is created (a new http request received) XYZManager.Create will be invoked. In your case this method returns the same instance, so all contexts will share that instance.

Depending if you want to share that instance for all contexts or not you should return new or the same instances. Also note, that for singleton shared instances there is a different Owin extension method that will keep the singleton for you.

Check out this answer as it explains what is the purpose of the CreatePerOwinContext method, as well as provide some examples how to create a inter context shared instance.

This is how you create Context shared service

public class XYZManager : IDisposable
{
     public static  XYZManager Create()
     {
         return  new XYZManager(new ApplicationDbContext());
     }
     private readonly ApplicationDbContext DbContext;

     public XYZManager(ApplicationDbContext dbContext)
     {
         DbContext = dbContext;
     }
     public string SomeInfo {get;set;}
     public string GetFullDetails () 
     {
         return dbContext.getFullDetails();
     }
     // dispose
 }

Note: Since you will be creating instances each time a new owin context is creates it is advisable, to make sure any unmanaged objects are disposed.

Ernis
  • 645
  • 11
  • 22