public Task <TenantShell <TTenant> > Get(TenantIdentifier identifier)
 {
     return(Task.Run(() =>
     {
         return _factory(identifier);
     }));
 }
        public async Task <TenantShell <TTenant> > ResolveTenantShell(TenantIdentifier identifier, ITenantShellFactory <TTenant> tenantFactory)
        {
            if (_cache.TryGetValue(identifier, out TenantShell <TTenant> result))
            {
                return(result);
            }

            try
            {
                await _semaphore.WaitAsync();

                // Double locking - check cache again incase another thread just put it there.
                if (_cache.TryGetValue(identifier, out result))
                {
                    return(result);
                }

                // initialise tenant shell for tenant identifier.
                var tenantResult = await tenantFactory.Get(identifier);

                if (tenantResult == null)
                {
                    // don't cache / associate null tenant shells with tenant identifiers. This means future requests for a tenant who currenlty has a null shell will contiue to flow throw to the factory
                    // until it returns a tenant shell result.

                    // This is better flow if you are creating new tenants dynamically and a request is recieved on the new tenants URL before the tenants has been set up in the source.
                    // It means the request will resolve to a null tenant shell for a while, (factory may keep returning null), and eventually when a tenant is actually returned from the factory, a new tenant shell will then be created and added to
                    // the cache, at which point the factory will stop being used for subsequent requests.
                    return(null);
                }

                // We got a new shell, so add it to the cache under its identifier, and any additional identifiers.
                _cache.AddOrUpdate(identifier, tenantResult, (a, b) => { return(tenantResult); });

                bool distinguisherFound = false;
                foreach (var item in tenantResult.Identifiers)
                {
                    if (item.Equals(identifier))
                    {
                        distinguisherFound = true;
                        continue;
                    }
                    _cache.AddOrUpdate(item, tenantResult, (a, b) => { return(tenantResult); });
                }

                if (!distinguisherFound)
                {
                    tenantResult.Identifiers.Add(identifier);
                }

                return(tenantResult);
            }
            finally
            {
                _semaphore.Release();
            }
        }
Esempio n. 3
0
        public virtual Task <TenantIdentifier> IdentifyTenant()
        {
            TenantIdentifier identity = null;
            var context = HttpContextAccessor.GetCurrent();

            if (HttpContextAccessor != null)
            {
                identity = GetTenantDistinguisher(context);
            }
            return(Task.FromResult(identity));
        }
        public async Task <IDisposable> RemoveTenantShell(TenantIdentifier identifier)
        {
            TenantShell <TTenant> removed = null;

            if (!_cache.TryGetValue(identifier, out TenantShell <TTenant> result))
            {
                // tenant hasn't yet been initialised.. so nothing to do..
                return(null);
            }

            try
            {
                await _semaphore.WaitAsync(); // block restarting if a tenant intiialise in process or another restart in prcess.

                // tenant may have just been restarted on another thread and removed from cache, so check again.
                //Todo: make this more robust if TryRemove returns false for example..
                var isRemoved = _cache.TryRemove(identifier, out removed);
                if (isRemoved)
                {
                    foreach (var item in removed.Identifiers)
                    {
                        if (item.Equals(identifier))
                        {
                            continue;
                        }
                        isRemoved = _cache.TryRemove(item, out TenantShell <TTenant> itemRemoved);
                    }
                }

                // dispose after small delay to allow respoinse to be returned flowing back through the same pipeline.
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                return(removed);

                //Task.Delay(new TimeSpan(0, 0, 2)).ContinueWith((t) =>
                //{
                //    removed?.Dispose();
                //});
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            }
            finally
            {
                _semaphore.Release();
            }
        }
Esempio n. 5
0
 public bool TryRemove(TenantIdentifier key, out TenantShell <TTenant> value)
 {
     return(_mappings.TryRemove(key, out value));
 }
Esempio n. 6
0
 public TenantShell <TTenant> AddOrUpdate(TenantIdentifier key,
                                          TenantShell <TTenant> addValue,
                                          Func <TenantIdentifier, TenantShell <TTenant>, TenantShell <TTenant> > updateValueFactory)
 {
     return(_mappings.AddOrUpdate(key, addValue, updateValueFactory));
 }