views:

67

answers:

2

Using StructureMap, is it possible to have a singleton object for each value of an argument? For example, say I want to maintain a different singleton for each website in a multi-tenancy web app:

For<ISiteSettings>().Singleton().Use<SiteSettings>();

I want to maintain a different singleton object corresponding to each site:

ObjectFactory.With<string>(requestHost).GetInstance<ISiteSettings>();

Currently, it seems to create a new object every time I try to resolve ISiteSettings.

+3  A: 

The Singleton scope really means singleton - there can be only one instance. For your scenario, I would recommend you implement a custom ILifecycle which uses the requestHost (which I assume can be pulled out of HttpContext) to return the appropriate cached instance. Take a look at the StructureMap source code to see how the other ILifecycles are implemented.

When you register For<ISiteSettings>, there is an option to specify your own ILifecycle, instead of using one of the ones built in.

Joshua Flanagan
+1  A: 

Thanks Joshua, I took your advice. Here's the solution I finished up with, which seems to work fine. Any feedback appreciated.

public class TenantLifecycle : ILifecycle
{
    private readonly ConcurrentDictionary<string, MainObjectCache> _tenantCaches =
        new ConcurrentDictionary<string, MainObjectCache>();

    public IObjectCache FindCache()
    {
        var cache = _tenantCaches.GetOrAdd(TenantKey, new MainObjectCache());
        return cache;
    }

    public void EjectAll()
    {
        FindCache().DisposeAndClear();
    }

    public string Scope
    {
        get { return "Tenant"; }
    }

    protected virtual string TenantKey
    {
        get
        {
            var requestHost = HttpContext.Current.Request.Url.Host;
            var normalisedRequestHost = requestHost.ToLowerInvariant();
            return normalisedRequestHost;
        }
    }
}

With StructureMap configuration:

ObjectFactory.Initialize(
    x => x.For<ISiteSettings>()
        .LifecycleIs(new TenantLifecycle())
        .Use<SiteSettings>()
);
cxfx