public async Task <AuthorizationPolicyInfo> FetchPolicy( Guid policyId, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); return(await _queries.Fetch(_tenantProvider.GetTenantId(), policyId).ConfigureAwait(false)); }
public Task ValidateAccessToEntityAsync( ITenantEntity entity, EntityAction desiredAction) { if (null == entity) { return(Task.CompletedTask); } var userTenantId = _tenantIdProvider.GetTenantId(); if (TenantSpec.BelongsToSite(userTenantId)) { // simplistic access rules for prototype phase: // 'site user' can access any tenant // for the purposes of administration return(Task.CompletedTask); } // non-'site user' if (userTenantId != entity.TenantId) { string message = BuildAccessDeniedMessage(entity, desiredAction); throw new UnauthorizedAccessException(message); } // 'tenant user' can perform any modification read its own tenant information if (desiredAction != EntityAction.Read) { string message = BuildAccessDeniedMessage(entity, desiredAction); throw new UnauthorizedAccessException(message); } return(Task.CompletedTask); }
public void Get_All_With_Site_User_Should_Return_All_Entities() { // Given _tenantIdProvider.GetTenantId().Returns(Guid.Empty); SetupRepositoryAndService(); // When var entities = _service.GetAllAsync(null, null).Result; // Then Assert.That(entities.Count(), Is.EqualTo(3)); _repository.Received().Query(); }
public Task ValidateAccessToEntityAsync( ITenantEntity entity, EntityAction desiredAction) { if (null == entity) { return(Task.CompletedTask); } // this call may throw exception if the user doesn't have // the validated TenantId claim var _userTenantId = _tenantIdProvider.GetTenantId(); if (TenantSpec.BelongsToSite(_userTenantId)) { // simple tenant access (no permissions) // 'site user' can access entities within any tenant // for the purposes of administration return(Task.CompletedTask); } if (_userTenantId != entity.TenantId) { var message = $"User belonging to tenant {_userTenantId} has been denied access " + $"to entity '{entity.GetType().Name}' belonging to tenant {entity.TenantId}"; throw new UnauthorizedAccessException(message); } return(Task.CompletedTask); }
public async Task <IActionResult> Post([FromBody] BranchOfficeDto value) { if (value == null) { return(InvalidRequestBodyJson(nameof(BranchOfficeDto))); } if (!ModelState.IsValid) { return(BadRequest(ModelState)); } if (!CheckTimeZoneCode(value.TimeZoneId)) { AddErrors(new [] { $"Unknown time zone code specified: {value.TimeZoneId}" }); } var newBranchOffice = Mapper.Map <BranchOffice>(value); newBranchOffice.TenantId = _tenantIdProvider.GetTenantId(); await _branchOfficeService.AddAsync(newBranchOffice); return(Created(nameof(GetBranchOffice), new CreatedWithGuidDto { Id = newBranchOffice.Id })); }
public WorkplaceCredentialsDto CreateCredentials(WorkplaceDescriptorDto descriptor) { var userTenant = _tenantIdProvider.GetTenantId().ToString(); if (userTenant != descriptor.TenantId) { throw new BadRequestException("Bad tenant id specified"); } var clientId = descriptor.WorkplaceType + GetRandomStringInBase52Alphabeth(16); var clientSecret = CreateSecret(); return(new WorkplaceCredentialsDto { ClientId = clientId, ClientSecret = clientSecret }); }
public override async Task <(bool success, string[] errors)> CreateUserAsync(ApplicationUser newUser, IEnumerable <Guid> roles, string password) { if (TenantSpec.BelongsToTenant(_tenantIdProvider.GetTenantId())) { // the call is from a 'Tenant User'... if (newUser.TenantId == TenantSpec.EntireSiteTenantId) { // ...and the new user model is not assigned a TenantId // 'Tenant User' can only create users in their own tenant newUser.TenantId = _tenantIdProvider.GetTenantId(); } // Note that 'Site User' (see TenantSpec.IsSiteUser(...)) // should be able to create new Users in any tenant // in order to create a 'tenant admin' user in a new tenant } return(await base.CreateUserAsync(newUser, roles, password)); }
public IQueryable <T> AddScopeFilter <T>(IQueryable <T> entityQuery) where T : class, ITenantEntity { var tenantId = _tenantIdProvider.GetTenantId(); if (tenantId != Guid.Empty) { return(entityQuery.Where(e => e.TenantId == tenantId)); } return(entityQuery); }
public void Setup() { LogHelper.ConfigureConsoleLogger(); _newId = Guid.NewGuid(); _tenantMockId = Guid.NewGuid(); _roleService = Substitute.For <IRestrictedRoleService>(); _tenantIdProvider = Substitute.For <ITenantIdProvider>(); _tenantIdProvider.GetTenantId().Returns(_tenantMockId); }
public void Setup() { LogHelper.ConfigureConsoleLogger(); StaticStartup.Startup(); _newId = Guid.NewGuid(); _tenantId = Guid.NewGuid(); _testService = Substitute.For <ITestService>(); _tenantIdProvider = Substitute.For <ITenantIdProvider>(); _tenantIdProvider.GetTenantId().Returns(_tenantId); }
public async Task DeleteBlobs(IEnumerable <string> blobNames) { // Basic check if (blobNames == null) { throw new ArgumentNullException(nameof(blobNames)); } var blobNamesString = string.Join(',', blobNames); int tenantId = _tenantIdProvider.GetTenantId().Value; await _db.Database.ExecuteSqlCommandAsync($"DELETE FROM [dbo].[Blobs] WHERE Id IN (SELECT VALUE FROM STRING_SPLIT({blobNamesString}, ',')) AND TenantId = {tenantId}"); }
public PsaReportService( IPsaSummaryService summaryService, IOrgStructureReference orgStructReference, //IPsaReportRepository reportRepository, ITenantEntityAccessChecker tenantEntityAccessChecker, ITenantIdProvider tenantIdProvider, ITimeService timeService ) { _summaryService = summaryService; // _reportRepository = reportRepository; _orgStructReference = orgStructReference; _tenantEntityAccessChecker = tenantEntityAccessChecker; _tenantId = tenantIdProvider.GetTenantId(); _timeService = timeService; }
public void Setup() { LogHelper.ConfigureConsoleLogger(); StaticStartup.Startup(); _newId = Guid.NewGuid(); _tenantId = Guid.NewGuid(); _branchOfficeService = Substitute.For <IService <BranchOffice> >(); _tenantIdProvider = Substitute.For <ITenantIdProvider>(); _logger = Substitute.For <ILogger <BranchOfficeController> >(); _timeService = Substitute.For <ITimeService>(); _credentialsService = Substitute.For <IWorkplaceCredentialsService>(); _tenantIdProvider.GetTenantId().Returns(_tenantId); _timeService.CheckTimeZoneId(Arg.Any <string>()).Returns(true); }
public void Setup() { LogHelper.ConfigureConsoleLogger(); StaticStartup.Startup(); _newId = Guid.NewGuid(); _tenantId = Guid.NewGuid(); _inspectionService = Substitute.For <IInspectionService>(); _inspectionService.When(s => s.BeginInspectionAsync(Arg.Any <Inspection>())) .Do(v => ((Inspection)v[0]).Id = _newId); _inspectionService.BeginInspectionAsync(Arg.Any <Inspection>()).ReturnsForAnyArgs(_newId); _tenantIdProvider = Substitute.For <ITenantIdProvider>(); _tenantIdProvider.GetTenantId().Returns(_tenantId); _incompleteInspection = new Inspection() { }; }
public async Task <IActionResult> Post([FromBody] PositionDto value) { if (value == null) { return(InvalidRequestBodyJson(nameof(PositionDto))); } if (!ModelState.IsValid) { return(BadRequest(ModelState)); } var newPosition = Mapper.Map <Position>(value); newPosition.TenantId = _tenantIdProvider.GetTenantId(); await _positionService.AddAsync(newPosition); return(Created(nameof(GetPosition), new CreatedWithGuidDto { Id = newPosition.Id })); }
public async Task <IActionResult> PostTest([FromBody] TestPostDto testDto) { if (null == testDto) { return(InvalidRequestBodyJson(nameof(TestDto))); } if (!ModelState.IsValid) { return(BadRequest(ModelState)); } var newTest = Mapper.Map <Test>(testDto); newTest.TenantId = _tenantIdProvider.GetTenantId(); await _testService.AddAsync(newTest); return(Created(nameof(GetTest), new CreatedWithGuidDto { Id = newTest.Id })); }
public async Task <IActionResult> Post([FromBody] EmployeeDto value) { if (value == null) { return(InvalidRequestBodyJson(nameof(EmployeeDto))); } if (!ModelState.IsValid) { return(BadRequest(ModelState)); } var newEmployee = Mapper.Map <Employee>(value); newEmployee.TenantId = _tenantIdProvider.GetTenantId(); await _employeeService.AddAsync(newEmployee); return(Created(nameof(GetEmployee), new CreatedWithGuidDto { Id = newEmployee.Id })); }
public async Task <IActionResult> Post([FromBody] DepartmentDto newDepartmentDto) { if (newDepartmentDto == null) { return(InvalidRequestBodyJson(nameof(DepartmentDto))); } if (!ModelState.IsValid) { return(BadRequest(ModelState)); } var newDepartment = Mapper.Map <Department>(newDepartmentDto); newDepartment.TenantId = _tenantIdProvider.GetTenantId(); await _departmentService.AddAsync(newDepartment); var depCreatedDto = new CreatedWithGuidDto { Id = newDepartment.Id }; _logger.LogInformation($"Successfully created department '{newDepartment.Name}' (id={newDepartment.Id})."); return(Created(nameof(GetDepartment), depCreatedDto)); }
public async Task <IActionResult> CreateRole([FromBody] RoleDto role) { if (!ModelState.IsValid) { return(BadRequest(ModelState)); } if (role == null) { return(InvalidRequestBodyJson(nameof(RoleDto))); } ApplicationRole appRole = _mapper.Map <ApplicationRole>(role); // This will throw if tenant Id is not available, // which means there is a bug in authentication code appRole.TenantId = _tenantIdProvider.GetTenantId(); await _roleService.CreateRoleAsync(appRole, role.Permissions?.Select(p => p.Value).ToArray()); RoleDto roleVM = await GetRoleViewModelHelper(appRole.Id); return(CreatedAtAction(GetRoleByIdActionName, new { id = roleVM.Id }, roleVM)); }
public async Task <IActionResult> PostInspection([FromBody] InspectionPostDto inspectionDto) { if (inspectionDto == null) { return(InvalidRequestBodyJson(nameof(InspectionDto))); } if (!ModelState.IsValid) { return(BadRequest(ModelState)); } var newInspection = Mapper.Map <Inspection>(inspectionDto); newInspection.TenantId = _tenantIdProvider.GetTenantId(); try { var newId = await _inspectionService.BeginInspectionAsync(newInspection); return(Created(nameof(GetInspection), new CreatedWithGuidDto { Id = newId })); } catch (ItemAlreadyExistsException ex) { if (ex.Id.HasValue) { // should yield 'found' response status code return(RedirectToAction(nameof(GetInspection), new CreatedWithGuidDto { Id = ex.Id.Value })); } throw new Exception( $"Exception of type {nameof(ItemAlreadyExistsException)} should have Id defined" ); } }
public string GetShardConnectionString() { // When applying the migrations in Program.cs while running the // solution in development, it is convenient to have a default // connection string that doesn't depend on tenant Id if (!_tenantIdProvider.HasTenantId()) { return(_config.GetConnectionString(Constants.AdminConnection)); } string shardConnString = null; int tenantId = _tenantIdProvider.GetTenantId().Value; // Step (1) retrieve the conn string from the cache inside a READ lock _shardingLock.EnterReadLock(); try { _cache.TryGetValue(CacheKey(tenantId), out shardConnString); } finally { _shardingLock.ExitReadLock(); } // Step (2) if step (1) was a miss, enter inside a WRITE lock, retrieve the conn string from the source and update the cache if (shardConnString == null) { _shardingLock.EnterWriteLock(); try { // To avoid a race-condition causing multiple threads to populate the cache in parallel immediately after they all // have a cache miss inside the previous READ lock, here we check the cache again inside the WRITE lock _cache.TryGetValue(CacheKey(tenantId), out shardConnString); if (shardConnString == null) { using (var scope = _serviceProvider.CreateScope()) { var ctx = scope.ServiceProvider.GetRequiredService <AdminContext>(); shardConnString = ctx.Tenants.Include(e => e.Shard) .FirstOrDefault(e => e.Id == tenantId)?.Shard?.ConnectionString; } // This is a catastrophic error, should not happen in theory if (string.IsNullOrWhiteSpace(shardConnString)) { throw new InvalidOperationException($"The sharding route for tenant Id {tenantId} is missing"); } // There is always one built-in shard that resides in the same DB as the shard manager, the // purpose behind it is to make it easier to do development and also to set-up small instances that do not require sharding else if (shardConnString == SHARD_MANAGER_PLACEHOLDER) { shardConnString = _config.GetConnectionString(Constants.AdminConnection); } // ELSE: this is a normal shard else { // For improved security, allow more secure modes of storing shard passwords, other than in the shard manager DB itself // - Mode 1: in a "Passwords" section in a secure configuration provider, and then they are referenced in the conn string by their names // - Mode 2: as being the same password as the shard manager's connection string, which is also stored safely in a configuration provider var shardConnBuilder = new SqlConnectionStringBuilder(shardConnString); if (!string.IsNullOrWhiteSpace(shardConnBuilder.Password)) { // If the shard password is specified, and it matches a valid key in the "Passwords" configuration section, use that configuration value instead string configPassword = _config[$"{PASSWORDS_CONFIG_SECTION}:{shardConnBuilder.Password}"]; if (!string.IsNullOrWhiteSpace(configPassword)) { shardConnBuilder.Password = configPassword; shardConnString = shardConnBuilder.ConnectionString; } // ELSE we hope that this is a valid password, or else the connection to the shard will sadly fail. } else { // If the password of the shard is not set but the password of the shard manager is, use the shard manager's string shardManagerConnection = _config.GetConnectionString(Constants.AdminConnection); var shardManagerConnBuilder = new SqlConnectionStringBuilder(shardManagerConnection); if (!string.IsNullOrWhiteSpace(shardManagerConnBuilder.Password)) { shardConnBuilder.Password = shardManagerConnBuilder.Password; shardConnString = shardConnBuilder.ConnectionString; } // ELSE we hope that this is windows authentication, or else the connection to the shard will sadly fail. } } // Set the cache, with an expiry var expiryTime = DateTimeOffset.Now.AddMinutes(GetCacheExpirationInMinutes()); _cache.Set(CacheKey(tenantId), shardConnString, expiryTime); // NOTE: Sharding routes is a type of data that is very frequently read, yet very rarely if never updated // so we have decided to rely only on cache expiry to keep the cache fresh (2h by default), so if you move a tenant // across shards, you need to wait those 2 hours before all caches are updated. This is the best compromise } } finally { _shardingLock.ExitWriteLock(); } } return(shardConnString); }
private Task <Summary> TryGetSummaryEntityForInspectionAsync(Guid inspectionId) { return(_psaSummaryRepository.GetSingleOrDefaultAsync( s => s.TenantId == _tenantIdProvider.GetTenantId() && s.InspectionId == inspectionId)); }
public static bool HasTenantId(this ITenantIdProvider tenantIdProvider) { return(tenantIdProvider.GetTenantId() != null); }
private async Task <ActionResult <EntitiesResponse <LocalUser> > > ActivateDeactivate([FromBody] List <int> ids, bool returnEntities, string expand, bool isActive) { await CheckActionPermissions(ids.Cast <int?>()); var isActiveParam = new SqlParameter("@IsActive", isActive); DataTable idsTable = DataTable(ids.Select(id => new { Id = id }), addIndex: false); var idsTvp = new SqlParameter("@Ids", idsTable) { TypeName = $"dbo.IdList", SqlDbType = SqlDbType.Structured }; string sql = @" SET NOCOUNT ON; DECLARE @Now DATETIMEOFFSET(7) = SYSDATETIMEOFFSET(); DECLARE @UserId INT = CONVERT(INT, SESSION_CONTEXT(N'UserId')); DECLARE @Emails [dbo].[CodeList]; INSERT INTO @Emails([Code]) SELECT x.[Email] FROM ( MERGE INTO [dbo].[LocalUsers] AS t USING ( SELECT [Id] FROM @Ids ) AS s ON (t.Id = s.Id) WHEN MATCHED AND (t.IsActive <> @IsActive) THEN UPDATE SET t.[IsActive] = @IsActive, t.[ModifiedAt] = @Now, t.[ModifiedById]= @UserId OUTPUT inserted.[Email] ) As x; SELECT [Code] AS [Value] FROM @Emails; "; // Tenant Id var tenantId = new SqlParameter("TenantId", _tenantIdProvider.GetTenantId()); using (var trxApp = await _db.Database.BeginTransactionAsync()) { try { // Update the entities and retrieve the emails of the entities that were updated List <string> emails = await _db.Strings.FromSql(sql, idsTvp, isActiveParam).Select(e => e.Value).ToListAsync(); // Prepare the TVP of emails to update from the manager DataTable emailsTable = DataTable(emails.Select(e => new { Code = e }), addIndex: false); var emailsTvp = new SqlParameter("Emails", emailsTable) { TypeName = $"dbo.CodeList", SqlDbType = SqlDbType.Structured }; using (var trxAdmin = await _adminDb.Database.BeginTransactionAsync()) { try { if (isActive) { // Insert efficiently with a SQL query await _adminDb.Database.ExecuteSqlCommandAsync($@" INSERT INTO dbo.[TenantMemberships] SELECT Id, @TenantId FROM [dbo].[GlobalUsers] WHERE Email IN (SELECT Code from @Emails); ", emailsTvp, tenantId); } else { // Delete efficiently with a SQL query await _adminDb.Database.ExecuteSqlCommandAsync($@" DELETE FROM dbo.[TenantMemberships] WHERE TenantId = @TenantId AND UserId IN ( SELECT Id FROM [dbo].[GlobalUsers] WHERE Email IN (SELECT Code from @Emails) ); ", emailsTvp, tenantId); } // Commit both trxAdmin.Commit(); trxApp.Commit(); } catch (Exception ex) { trxApp.Rollback(); trxAdmin.Rollback(); throw ex; } } } catch (Exception ex) { trxApp.Rollback(); throw ex; } } // Determine whether entities should be returned if (!returnEntities) { // IF no returned items are expected, simply return 200 OK return(Ok()); } else { // Load the entities using their Ids var affectedDbEntitiesQ = _db.LocalUsers.Where(e => ids.Contains(e.Id)); // _db.LocalUsers.FromSql("SELECT * FROM [dbo].[LocalUsers] WHERE Id IN (SELECT Id FROM @Ids)", idsTvp); var affectedDbEntitiesExpandedQ = Expand(affectedDbEntitiesQ, expand); var affectedDbEntities = await affectedDbEntitiesExpandedQ.ToListAsync(); var affectedEntities = _mapper.Map <List <LocalUser> >(affectedDbEntities); // sort the entities the way their Ids came, as a good practice LocalUser[] sortedAffectedEntities = new LocalUser[ids.Count]; Dictionary <int, LocalUser> affectedEntitiesDic = affectedEntities.ToDictionary(e => e.Id.Value); for (int i = 0; i < ids.Count; i++) { var id = ids[i]; LocalUser entity = null; if (affectedEntitiesDic.ContainsKey(id)) { entity = affectedEntitiesDic[id]; } sortedAffectedEntities[i] = entity; } // Prepare a proper response var response = new EntitiesResponse <LocalUser> { Data = sortedAffectedEntities, CollectionName = GetCollectionName(typeof(LocalUser)) }; // Commit and return return(Ok(response)); } }
public TenantUserInfo GetCurrentInfo() { return(GetInfo(_tenantIdProvider.GetTenantId().Value)); }
/// <summary> /// This trick makes it possible to injected the ApplicationContext into other components via DI as usual /// but it automatically configures itself with the correct options. Inspired from this Microsoft sample: https://bit.ly/2TIEFMA /// </summary> /// <param name="shardResolver">The service that resolves the shard connection string</param> /// <param name="tenantIdProvider">The service that retrieves tenants Ids from the headers</param> /// <returns></returns> private static DbContextOptions <ApplicationContext> CreateDbContextOptions( IShardResolver shardResolver, ITenantIdProvider tenantIdProvider, IUserProvider userService, ITenantUserInfoAccessor accessor) { // Prepare the options based on the connection created with the shard manager var optionsBuilder = new DbContextOptionsBuilder <ApplicationContext>(); string connectionString = shardResolver.GetShardConnectionString(); if (tenantIdProvider is DesignTimeTenantIdProvider) { // Only for design time when running "ef migrations" command from the CLI optionsBuilder = optionsBuilder.UseSqlServer(connectionString); } else { int tenantId = tenantIdProvider.GetTenantId() ?? throw new Controllers.Misc.BadRequestException("Tenant Id was not supplied"); // Unless this is a fake design time resolver, apply row level security and pass context info SqlConnection sqlConnection = new SqlConnection(connectionString); SqlCommand cmd = sqlConnection.CreateCommand(); cmd.CommandText = @" -- Set the global values of the session context EXEC sp_set_session_context @key=N'TenantId', @value=@TenantId; EXEC sp_set_session_context @key=N'Culture', @value=@Culture; EXEC sp_set_session_context @key=N'NeutralCulture', @value=@NeutralCulture; -- Get the User Id DECLARE @UserId INT, @ExternalId NVARCHAR(450), @Email NVARCHAR(255), @SettingsVersion UNIQUEIDENTIFIER, @PermissionsVersion UNIQUEIDENTIFIER, @ViewsAndSpecsVersion UNIQUEIDENTIFIER, @UserSettingsVersion UNIQUEIDENTIFIER, @PrimaryLanguageId NVARCHAR(255), @PrimaryLanguageSymbol NVARCHAR(255), @SecondaryLanguageId NVARCHAR(255), @SecondaryLanguageSymbol NVARCHAR(255) ; SELECT @UserId = Id, @ExternalId = ExternalId, @Email = Email, @PermissionsVersion = PermissionsVersion, @UserSettingsVersion = UserSettingsVersion FROM [dbo].[LocalUsers] WHERE TenantId = @TenantId AND IsActive = 1 AND (ExternalId = @ExternalUserId OR Email = @UserEmail); -- Set LastAccess (Works only if @UserId IS NOT NULL) UPDATE [dbo].[LocalUsers] SET LastAccess = SYSDATETIMEOFFSET() WHERE Id = @UserId; -- Get hashes SELECT @SettingsVersion = SettingsVersion, @ViewsAndSpecsVersion = ViewsAndSpecsVersion, @PrimaryLanguageId = PrimaryLanguageId, @PrimaryLanguageSymbol = PrimaryLanguageSymbol, @SecondaryLanguageId = SecondaryLanguageId, @SecondaryLanguageSymbol = SecondaryLanguageSymbol FROM [dbo].[Settings] WHERE TenantId = @TenantId -- Set the User Id EXEC sp_set_session_context @key=N'UserId', @value=@UserId; -- Return the user information SELECT @UserId AS userId, @ExternalId AS ExternalId, @Email AS Email, @SettingsVersion AS SettingsVersion, @PermissionsVersion AS PermissionsVersion, @UserSettingsVersion AS UserSettingsVersion, @ViewsAndSpecsVersion AS ViewsAndSpecsVersion, @PrimaryLanguageId AS PrimaryLanguageId, @PrimaryLanguageSymbol AS PrimaryLanguageSymbol, @SecondaryLanguageId AS SecondaryLanguageId, @SecondaryLanguageSymbol AS SecondaryLanguageSymbol; "; cmd.Parameters.AddWithValue("@TenantId", tenantId); cmd.Parameters.AddWithValue("@ExternalUserId", userService.GetUserId()); cmd.Parameters.AddWithValue("@UserEmail", userService.GetUserEmail()); cmd.Parameters.AddWithValue("@Culture", CultureInfo.CurrentUICulture.Name); cmd.Parameters.AddWithValue("@NeutralCulture", CultureInfo.CurrentUICulture.IsNeutralCulture ? CultureInfo.CurrentUICulture.Name : CultureInfo.CurrentUICulture.Parent.Name); sqlConnection.Open(); using (var reader = cmd.ExecuteReader()) { if (reader.Read()) { int i = 0; var info = new TenantUserInfo { UserId = reader.IsDBNull(i) ? (int?)null : reader.GetInt32(i++), ExternalId = reader.IsDBNull(i) ? null : reader.GetString(i++), Email = reader.IsDBNull(i) ? null : reader.GetString(i++), SettingsVersion = reader.IsDBNull(i) ? null : reader.GetGuid(i++).ToString(), PermissionsVersion = reader.IsDBNull(i) ? null : reader.GetGuid(i++).ToString(), UserSettingsVersion = reader.IsDBNull(i) ? null : reader.GetGuid(i++).ToString(), ViewsAndSpecsVersion = reader.IsDBNull(i) ? null : reader.GetGuid(i++).ToString(), PrimaryLanguageId = reader.IsDBNull(i) ? null : reader.GetString(i++), PrimaryLanguageSymbol = reader.IsDBNull(i) ? null : reader.GetString(i++), SecondaryLanguageId = reader.IsDBNull(i) ? null : reader.GetString(i++), SecondaryLanguageSymbol = reader.IsDBNull(i) ? null : reader.GetString(i++), }; // Provide the user throughout the current session accessor.SetInfo(tenantId, info); } else { throw new Controllers.Misc.BadRequestException("Something went wrong while querying the user ID from the Database"); } } // Prepare the options based on the connection created with the shard manager optionsBuilder = optionsBuilder.UseSqlServer(sqlConnection); } return(optionsBuilder .ReplaceService <IMigrationsSqlGenerator, CustomSqlServerMigrationsSqlGenerator>() .Options); }