This project is read-only.

PerSiteLifestyle

Dec 11, 2014 at 8:57 PM
Edited Dec 11, 2014 at 10:33 PM
Has anyone ever tried setting up a "per site" lifestyle?

A little clarification on the question;

Imagine two IIS websites pointing to the same wwwroot, in the same application pool or not, and both of them requiring their own set of singleton objects. The objects could be as simple as custom "SiteIdentity" entities returning their own SiteId (taken using HostingEnvironment.ApplicationHost.GetSiteID)

What I have done so far, and seems to be working but not quite sure if it is the right way of doing the things - since I am new to Simple Injector - is below.
            var perHostLifestyle = Lifestyle.CreateCustom(
                name: "Per Host Lifestyle",
                lifestyleApplierFactory: instanceCreator =>
                {
                    Dictionary<string, object> instances = new Dictionary<string, object>();

                    string siteId = HostingEnvironment.ApplicationHost.GetSiteID();

                    return () =>
                    {
                        if (!instances.ContainsKey(siteId))
                        {
                            instances.Add(siteId, instanceCreator.Invoke());
                        }

                        return instances[siteId];
                    };
                }
            );
I am aware of missing a synclock, I just removed it in order to keep the sample as simple as possible.

I would also love to hear your comments on how a "per site" object should be disposed, when and where as I cannot imagine the right answer.

Thank you guys in advance.

//P.S.: I am aware of having separate IIS application pools solves the issue since any singleton registration will resolve the site's instance accordingly (separate IIS application pool = separate worker processes). However, it is kind of a small framework I do develop here and some clients prefer having a "single IIS application pool" for several websites. That is the issue I am trying to resolve.
Dec 12, 2014 at 12:49 PM
Perhaps I'm completely misunderstanding, but as far as I see, when you have two web sites pointing, each website will get its own AppDomain. This means that they both get their own isolated block of memory and don't share any static instances you create.

But even if those websites share the same app domain (please check this), after reading your requirements its seems very clear that each website needs to run in its own isolated bubble (one AppDomain each, which might live in the same process, so AFAIK you don't need multiple application pools to get this isolation), because you're saying that each site has its own set of singletons. In other words you want each site to run in isolation from the other, and there is nothing you want share between them. With or without using a DI library, letting those websites run in isolation from each other will make your life much easier, and makes it much easier to reason about correctness.

And when you do this, there is no reason to implement such 'per site' lifestyle. In this case you can simply use the singleton lifestyle. But even if those websites would run in the same app domain, you don't need to implemen t this custom lifestyle if each site gets its own container instance. The Singleton lifestyle ensures one single instance per container instance. So if you have multiple container instances in one app domain, all get their own singleton.

Now about disposal. Simple Injector out of the box only disposes scoped instances. It doesn't dispose singletons. The reasoning is that you will normally create one single container instance per application and it will live for the duration of the application. That means that each created singleton will live for the duration of the application as well. When a app domain dies in .NET, the runtime will try to make sure that all finalizers of not finalized objects are run. This makes sure that references to unmanaged resources are cleared before de App Domain is completely unloaded. In most cases where your container lives for the duration of the App Domain, it doesn't matter that singletons aren't disposed, and the same holds for your 'per site' lifestyle, because it behaves much like a singleton. Besides, not many singletons would need to be disposed anyway. Most of the components that need disposal, need to have a scoped / request lifetime anyway.

If disposing is needed, you will have to do this manually. This holds for singletons and for your custom lifestyle as well. If it gets too complicated to manually track all singletons and dispose them when the application ends, you can use the code that is shown here. You can easily extend this code to work with your custom lifestyle as well.

But again, I see no real need to use this custom lifestyle. Do note though that (besides the obvious missing lock) the custom lifestyle is implemented correctly.
Marked as answer by dot_NET_Junkie on 12/13/2014 at 2:52 AM
Dec 12, 2014 at 1:21 PM
Hi Steven,

That answers all of my questions in one shot!

Thank you for your time and attention.