Reputation: 41902
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.
Upvotes: 4
Views: 467
Reputation: 41902
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>()
);
Upvotes: 6
Reputation: 8557
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.
Upvotes: 4