/// <summary> /// The auto setup middleware invoke. /// </summary> /// <param name="httpContext"> /// The http context. /// </param> /// <returns> /// The <see cref="Task"/>. /// </returns> public async Task InvokeAsync(HttpContext httpContext) { if (_setupOptions != null && _shellSettings.State == TenantState.Uninitialized) { // Try to acquire a lock before starting installation, it guaranties an atomic setup in multi instances environment. (var locker, var locked) = await _distributedLock.TryAcquireAutoSetupLockAsync(_lockOptions); if (!locked) { throw new TimeoutException($"Fails to acquire an auto setup lock for the tenant: {_setupOptions.ShellName}"); } await using var acquiredLock = locker; if (_shellSettings.State == TenantState.Uninitialized) { var pathBase = httpContext.Request.PathBase; if (!pathBase.HasValue) { pathBase = "/"; } // Check if the tenant was installed by another instance. var settings = await _shellSettingsManager.LoadSettingsAsync(_shellSettings.Name); if (settings.State != TenantState.Uninitialized) { await _shellHost.ReloadShellContextAsync(_shellSettings, eventSource : false); httpContext.Response.Redirect(pathBase); return; } var setupService = httpContext.RequestServices.GetRequiredService <ISetupService>(); if (await SetupTenantAsync(setupService, _setupOptions, _shellSettings)) { if (_setupOptions.IsDefault) { // Create the rest of the shells for further on demand setup. foreach (var setupOptions in _options.Tenants) { if (_setupOptions != setupOptions) { await CreateTenantSettingsAsync(setupOptions); } } } httpContext.Response.Redirect(pathBase); return; } } } await _next.Invoke(httpContext); }