Skip to content

Instantly share code, notes, and snippets.

@ebicoglu
Last active April 17, 2018 07:19
Show Gist options
  • Save ebicoglu/6fe14f65a21713f673ba5b55e94bb682 to your computer and use it in GitHub Desktop.
Save ebicoglu/6fe14f65a21713f673ba5b55e94bb682 to your computer and use it in GitHub Desktop.
[AspNet Zero] Drop tenant database when a tenant is deleted (for db for tenant usage)
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Abp;
using Abp.Application.Features;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.Data;
using Abp.Domain.Uow;
using Abp.EntityFrameworkCore;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.MultiTenancy;
using Abp.Runtime.Security;
using Microsoft.EntityFrameworkCore;
using MyCompanyName.AbpZeroTemplate.Authorization;
using MyCompanyName.AbpZeroTemplate.Editions.Dto;
using MyCompanyName.AbpZeroTemplate.EntityFrameworkCore;
using MyCompanyName.AbpZeroTemplate.MultiTenancy.Dto;
using MyCompanyName.AbpZeroTemplate.Url;
namespace MyCompanyName.AbpZeroTemplate.MultiTenancy
{
[AbpAuthorize(AppPermissions.Pages_Tenants)]
public class TenantAppService : AbpZeroTemplateAppServiceBase, ITenantAppService
{
public IAppUrlService AppUrlService { get; set; }
private readonly IDbContextResolver _dbContextResolver;
private readonly IDbPerTenantConnectionStringResolver _connectionStringResolver;
public TenantAppService(IDbContextResolver dbContextResolver,
IDbPerTenantConnectionStringResolver connectionStringResolver)
{
_dbContextResolver = dbContextResolver;
_connectionStringResolver = connectionStringResolver;
AppUrlService = NullAppUrlService.Instance;
}
public async Task<PagedResultDto<TenantListDto>> GetTenants(GetTenantsInput input)
{
var query = TenantManager.Tenants
.Include(t => t.Edition)
.WhereIf(!input.Filter.IsNullOrWhiteSpace(), t => t.Name.Contains(input.Filter) || t.TenancyName.Contains(input.Filter))
.WhereIf(input.CreationDateStart.HasValue, t => t.CreationTime >= input.CreationDateStart.Value)
.WhereIf(input.CreationDateEnd.HasValue, t => t.CreationTime <= input.CreationDateEnd.Value)
.WhereIf(input.SubscriptionEndDateStart.HasValue, t => t.SubscriptionEndDateUtc >= input.SubscriptionEndDateStart.Value.ToUniversalTime())
.WhereIf(input.SubscriptionEndDateEnd.HasValue, t => t.SubscriptionEndDateUtc <= input.SubscriptionEndDateEnd.Value.ToUniversalTime())
.WhereIf(input.EditionIdSpecified, t => t.EditionId == input.EditionId);
var tenantCount = await query.CountAsync();
var tenants = await query.OrderBy(input.Sorting).PageBy(input).ToListAsync();
return new PagedResultDto<TenantListDto>(
tenantCount,
ObjectMapper.Map<List<TenantListDto>>(tenants)
);
}
[AbpAuthorize(AppPermissions.Pages_Tenants_Create)]
[UnitOfWork(IsDisabled = true)]
public async Task CreateTenant(CreateTenantInput input)
{
await TenantManager.CreateWithAdminUserAsync(input.TenancyName,
input.Name,
input.AdminPassword,
input.AdminEmailAddress,
input.ConnectionString,
input.IsActive,
input.EditionId,
input.ShouldChangePasswordOnNextLogin,
input.SendActivationEmail,
input.SubscriptionEndDateUtc?.ToUniversalTime(),
input.IsInTrialPeriod,
AppUrlService.CreateEmailActivationUrlFormat(input.TenancyName)
);
}
[AbpAuthorize(AppPermissions.Pages_Tenants_Edit)]
public async Task<TenantEditDto> GetTenantForEdit(EntityDto input)
{
var tenantEditDto = ObjectMapper.Map<TenantEditDto>(await TenantManager.GetByIdAsync(input.Id));
tenantEditDto.ConnectionString = SimpleStringCipher.Instance.Decrypt(tenantEditDto.ConnectionString);
return tenantEditDto;
}
[AbpAuthorize(AppPermissions.Pages_Tenants_Edit)]
public async Task UpdateTenant(TenantEditDto input)
{
await TenantManager.CheckEditionAsync(input.EditionId, input.IsInTrialPeriod);
input.ConnectionString = SimpleStringCipher.Instance.Encrypt(input.ConnectionString);
var tenant = await TenantManager.GetByIdAsync(input.Id);
ObjectMapper.Map(input, tenant);
tenant.SubscriptionEndDateUtc = tenant.SubscriptionEndDateUtc?.ToUniversalTime();
await TenantManager.UpdateAsync(tenant);
}
[AbpAuthorize(AppPermissions.Pages_Tenants_Delete)]
public async Task DeleteTenant(EntityDto input)
{
var tenant = await TenantManager.GetByIdAsync(input.Id);
await TenantManager.DeleteAsync(tenant);
await DropTenantDatabase(tenant);
}
private async Task DropTenantDatabase(AbpTenantBase tenant)
{
var args = new DbPerTenantConnectionStringResolveArgs(tenant.Id, MultiTenancySides.Tenant)
{
["DbContextType"] = typeof(AbpZeroTemplateDbContext),
["DbContextConcreteType"] = typeof(AbpZeroTemplateDbContext)
};
var connectionString = ConnectionStringHelper.GetConnectionString(
_connectionStringResolver.GetNameOrConnectionString(args)
);
using (var dbContext = _dbContextResolver.Resolve<AbpZeroTemplateDbContext>(connectionString, null))
{
await dbContext.Database.EnsureDeletedAsync();
}
}
[AbpAuthorize(AppPermissions.Pages_Tenants_ChangeFeatures)]
public async Task<GetTenantFeaturesEditOutput> GetTenantFeaturesForEdit(EntityDto input)
{
var features = FeatureManager.GetAll()
.Where(f => f.Scope.HasFlag(FeatureScopes.Tenant));
var featureValues = await TenantManager.GetFeatureValuesAsync(input.Id);
return new GetTenantFeaturesEditOutput
{
Features = ObjectMapper.Map<List<FlatFeatureDto>>(features).OrderBy(f => f.DisplayName).ToList(),
FeatureValues = featureValues.Select(fv => new NameValueDto(fv)).ToList()
};
}
[AbpAuthorize(AppPermissions.Pages_Tenants_ChangeFeatures)]
public async Task UpdateTenantFeatures(UpdateTenantFeaturesInput input)
{
await TenantManager.SetFeatureValuesAsync(input.Id, input.FeatureValues.Select(fv => new NameValue(fv.Name, fv.Value)).ToArray());
}
[AbpAuthorize(AppPermissions.Pages_Tenants_ChangeFeatures)]
public async Task ResetTenantSpecificFeatures(EntityDto input)
{
await TenantManager.ResetAllFeaturesAsync(input.Id);
}
public async Task UnlockTenantAdmin(EntityDto input)
{
using (CurrentUnitOfWork.SetTenantId(input.Id))
{
var tenantAdmin = await UserManager.FindByNameAsync(AbpUserBase.AdminUserName);
if (tenantAdmin != null)
{
tenantAdmin.Unlock();
}
}
}
}
}
@ebicoglu
Copy link
Author

Drop the database right after the tenant is being deleted in TenantAppService.cs > DeleteTenant() method.

@ebicoglu
Copy link
Author

ebicoglu commented Apr 17, 2018

This is the code that's deleting a database in Entity Framework


 private async Task DropTenantDatabase(AbpTenantBase tenant)
 {
	var args = new DbPerTenantConnectionStringResolveArgs(tenant.Id, MultiTenancySides.Tenant)
	{
		["DbContextType"] = typeof(AbpZeroTemplateDbContext),
		["DbContextConcreteType"] = typeof(AbpZeroTemplateDbContext)
	};

	var connectionString = ConnectionStringHelper.GetConnectionString(
		_connectionStringResolver.GetNameOrConnectionString(args)
	);

	using (var dbContext = _dbContextResolver.Resolve<AbpZeroTemplateDbContext>(connectionString, null))
	{
		await dbContext.Database.EnsureDeletedAsync();
	}
 }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment