Last active
August 10, 2016 18:59
-
-
Save Tornhoof/0cebeeecfe4c4f942e68abae04ef8ddd to your computer and use it in GitHub Desktop.
MultiTenantSimpleInject
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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