Skip to content

Instantly share code, notes, and snippets.

@Tornhoof
Last active August 10, 2016 18:59
Show Gist options
  • Save Tornhoof/0cebeeecfe4c4f942e68abae04ef8ddd to your computer and use it in GitHub Desktop.
Save Tornhoof/0cebeeecfe4c4f942e68abae04ef8ddd to your computer and use it in GitHub Desktop.
MultiTenantSimpleInject
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using SimpleInjector;
namespace MultiTenantSimpleInject
{
class Program
{
static void Main(string[] args)
{
var container = new Container();
var dictionary = new ConcurrentDictionary<Guid, Lazy<IService>>();
for(var i = 0;i<10;i++) // these are actually stored in the database
{
var guid = Guid.NewGuid();
// need to make this lazy otherwise the container is already locked as soon as I call GetInstance()
var instance = new Lazy<IService>(() => Lifestyle.Singleton.CreateProducer<IService>(() => new ServiceImplementation(), container).GetInstance());
dictionary.TryAdd(guid, instance);
}
container.RegisterSingleton<IService>(new ServiceDispatcher(dictionary));
container.Verify();
var identity = new ClaimsIdentity(new[] {new Claim("TenantId", dictionary.Keys.First().ToString())});
Thread.CurrentPrincipal = new ClaimsPrincipal(identity);
var service = container.GetInstance<IService>();
service.Save("No Path at all");
}
}
// Multiple Services, one dispatcher for each service, maybe codegen
public class ServiceDispatcher : IService
{
private readonly ConcurrentDictionary<Guid, Lazy<IService>> _dictionary;
public ServiceDispatcher(ConcurrentDictionary<Guid, Lazy<IService>> dictionary)
{
_dictionary = dictionary;
}
public void Save(string path)
{
_dictionary[GetCurrentId()].Value.Save(path);
}
public byte[] Load(string path)
{
return _dictionary[GetCurrentId()].Value.Load(path);
}
private Guid GetCurrentId()
{
var currentIdentity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
return new Guid(currentIdentity.Claims.Single(t => t.Type == "TenantId").Value);
}
}
public interface IService
{
void Save(string path);
byte[] Load(string path);
}
// Implementation of the service
// most if not all services are by tenant because they store tenant specific data which is reused over the course of multiple requests
public class ServiceImplementation : IService
{
// e.g. caching of data for a specific customer, used more than just per request.
private readonly ConcurrentDictionary<string, byte[]> m_CheapCache = new ConcurrentDictionary<string, byte[]>();
public void Save(string path)
{
Console.WriteLine(path);
}
public byte[] Load(string path)
{
byte[] cached;
if (m_CheapCache.TryGetValue(path, out cached))
{
return cached;
}
throw new NotImplementedException();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment