Browse Source

feat(tests): 添加用户应用服务和数据种子初始化测试

新增用户应用服务单元测试,包含创建、查询、更新和删除等功能测试。同时增加数据种子初始化测试,验证角色和用户的创建。更新EF Core测试模块,使用PostgreSQL代替内存数据库,并添加数据种子。
pull/1149/head
feijie 1 year ago
parent
commit
db61240c23
  1. 5
      aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName.CompanyName.ProjectName.Application.Tests.csproj
  2. 137
      aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/DataSeeder/ProjectNameDataSeederTests.cs
  3. 54
      aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/ProjectNameApplicationTestModule.cs
  4. 64
      aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/TestFileProvider.cs
  5. 21
      aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/TestHostEnvironment.cs
  6. 265
      aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/Users/UserAppServiceTests.cs
  7. 6
      aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests.csproj
  8. 62
      aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreTestModule.cs

5
aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName.CompanyName.ProjectName.Application.Tests.csproj

@ -7,12 +7,17 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LINGYUN.Abp.Identity.Application" />
<PackageReference Include="Volo.Abp.BackgroundJobs.HangFire" />
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.Identity" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Hangfire.MemoryStorage" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\PackageName.CompanyName.ProjectName.Application\PackageName.CompanyName.ProjectName.Application.csproj" />
<ProjectReference Include="..\PackageName.CompanyName.ProjectName.Domain.Tests\PackageName.CompanyName.ProjectName.Domain.Tests.csproj" />
<ProjectReference Include="..\PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests\PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests.csproj" />
</ItemGroup>
</Project>

137
aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/DataSeeder/ProjectNameDataSeederTests.cs

@ -0,0 +1,137 @@
using Microsoft.Extensions.DependencyInjection;
using PackageName.CompanyName.ProjectName.AIO.EntityFrameworkCore.DataSeeder;
using PackageName.CompanyName.ProjectName.Users;
using Shouldly;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;
using Volo.Abp.Uow;
using Xunit;
namespace PackageName.CompanyName.ProjectName.DataSeeder
{
/// <summary>
/// 数据种子初始化测试
/// </summary>
[Collection("Database")]
public class ProjectNameDataSeederTests : ProjectNameApplicationTestBase
{
private readonly IProjectNameDataSeeder _inspectionDataSeeder;
private readonly IRepository<User, Guid> _userRepository;
private readonly IIdentityRoleRepository _identityRoleRepository;
private readonly IIdentityUserRepository _identityUserRepository;
public ProjectNameDataSeederTests()
{
_inspectionDataSeeder = GetRequiredService<IProjectNameDataSeeder>();
_userRepository = GetRequiredService<IRepository<User, Guid>>();
_identityRoleRepository = GetRequiredService<IIdentityRoleRepository>();
_identityUserRepository = GetRequiredService<IIdentityUserRepository>();
}
[Fact]
public async Task Should_Seed_Data_Successfully()
{
// Arrange
var context = new DataSeedContext();
// Act
await _inspectionDataSeeder.SeedAsync(context);
// Assert - 使用单元工作方法包装所有数据库操作
await WithUnitOfWorkAsync(async () =>
{
// 测试角色
var roles = await _identityRoleRepository.GetListAsync();
roles.Count.ShouldBeGreaterThanOrEqualTo(7); // 至少应该有 7 个角色
var superAdminRole = await _identityRoleRepository.FindByNormalizedNameAsync("超级管理员".ToUpperInvariant());
superAdminRole.ShouldNotBeNull();
// 测试用户
var users = await _userRepository.GetListAsync();
users.Count.ShouldBeGreaterThanOrEqualTo(10); // 至少应该有 10 个用户
foreach (var user in users)
{
user.IdentityUserId.ShouldNotBe(Guid.Empty);
var identityUser = await _identityUserRepository.GetAsync(user.IdentityUserId);
identityUser.ShouldNotBeNull();
}
return true;
});
}
[Theory]
[InlineData("超级管理员")]
[InlineData("普通用户")]
public async Task Should_Create_Roles(string roleName)
{
// Arrange
var context = new DataSeedContext();
await _inspectionDataSeeder.SeedAsync(context);
// Act & Assert - 使用单元工作方法包装
await WithUnitOfWorkAsync(async () =>
{
var role = await _identityRoleRepository.FindByNormalizedNameAsync(roleName.ToUpperInvariant());
role.ShouldNotBeNull();
role.Name.ShouldBe(roleName);
return true;
});
}
[Theory]
[InlineData("testuser1")]
[InlineData("testuser2")]
public async Task Should_Create_Users(string nickName)
{
// Arrange
var context = new DataSeedContext();
await _inspectionDataSeeder.SeedAsync(context);
// Act & Assert - 使用单元工作方法包装
await WithUnitOfWorkAsync(async () =>
{
var users = await _userRepository.GetListAsync();
var user = users.FirstOrDefault(u => u.NickName == nickName);
user.ShouldNotBeNull();
user.NickName.ShouldBe(nickName);
user.IdentityUserId.ShouldNotBe(Guid.Empty);
var identityUser = await _identityUserRepository.GetAsync(user.IdentityUserId);
identityUser.ShouldNotBeNull();
identityUser.Name.ShouldBe(nickName);
return true;
});
}
// 添加单元工作方法
protected override Task<TResult> WithUnitOfWorkAsync<TResult>(Func<Task<TResult>> func)
{
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func);
}
// 可选:添加重载方法以支持更多场景
protected async override Task<TResult> WithUnitOfWorkAsync<TResult>(AbpUnitOfWorkOptions options, Func<Task<TResult>> func)
{
using (var scope = ServiceProvider.CreateScope())
{
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>();
using (var uow = uowManager.Begin(options))
{
var result = await func();
await uow.CompleteAsync();
return result;
}
}
}
}
}

54
aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/ProjectNameApplicationTestModule.cs

@ -1,11 +1,63 @@
using Hangfire;
using Hangfire.MemoryStorage;
using LINGYUN.Abp.Identity;
using LINGYUN.Abp.Identity.Session;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using PackageName.CompanyName.ProjectName.AIO.EntityFrameworkCore.DataSeeder;
using PackageName.CompanyName.ProjectName.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Volo.Abp.PermissionManagement.Identity;
using Volo.Abp.Security.Claims;
namespace PackageName.CompanyName.ProjectName;
[DependsOn(
typeof(ProjectNameDomainTestModule),
typeof(ProjectNameApplicationModule)
typeof(ProjectNameApplicationModule),
typeof(AbpIdentityApplicationModule),
typeof(AbpPermissionManagementDomainIdentityModule),
typeof(ProjectNameEntityFrameworkCoreTestModule)
)]
public class ProjectNameApplicationTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// //设置ILogger为NullLogger
context.Services.AddLogging(builder => builder.AddProvider(NullLoggerProvider.Instance));
context.Services.AddTransient<IProjectNameDataSeeder, ProjectNameDataSeeder>();
context.Services.AddLogging(builder => builder.AddProvider(NullLoggerProvider.Instance));
context.Services.AddTransient<IHostEnvironment, TestHostEnvironment>();
context.Services.AddTransient<IFileProvider, TestFileProvider>();
// 增加配置文件定义,在新建租户时需要
Configure<IdentityOptions>(options =>
{
// 允许中文用户名
options.User.AllowedUserNameCharacters = null;
// 支持弱密码
options.Password.RequireDigit = false;
options.Password.RequiredLength = 1;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
});
Configure<AbpClaimsPrincipalFactoryOptions>(options =>
{
options.IsDynamicClaimsEnabled = true;
});
Configure<IdentitySessionCleanupOptions>(options =>
{
options.IsCleanupEnabled = true;
});
// 配置Hangfire
context.Services.AddHangfire(config =>
{
config.UseMemoryStorage();
});
}
}

64
aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/TestFileProvider.cs

@ -0,0 +1,64 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.IO;
namespace PackageName.CompanyName.ProjectName;
public class TestFileProvider : IFileProvider
{
private readonly Dictionary<string, IFileInfo> _files;
public TestFileProvider()
{
_files = new Dictionary<string, IFileInfo>();
}
public IDirectoryContents GetDirectoryContents(string subpath)
{
return new NotFoundDirectoryContents();
}
public IFileInfo GetFileInfo(string subpath)
{
if (_files.TryGetValue(subpath, out var fileInfo))
{
return fileInfo;
}
return new NotFoundFileInfo(subpath);
}
public IChangeToken Watch(string filter)
{
return NullChangeToken.Singleton;
}
public void AddFile(string path, string contents)
{
_files[path] = new TestFileInfo(path, contents);
}
}
public class TestFileInfo : IFileInfo
{
private readonly string _contents;
public TestFileInfo(string name, string contents)
{
Name = name;
_contents = contents;
}
public bool Exists => true;
public long Length => _contents.Length;
public string PhysicalPath => null;
public string Name { get; }
public DateTimeOffset LastModified => DateTimeOffset.UtcNow;
public bool IsDirectory => false;
public Stream CreateReadStream()
{
return new MemoryStream(System.Text.Encoding.UTF8.GetBytes(_contents));
}
}

21
aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/TestHostEnvironment.cs

@ -0,0 +1,21 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using System;
namespace PackageName.CompanyName.ProjectName;
public class TestHostEnvironment : IHostEnvironment
{
public TestHostEnvironment()
{
EnvironmentName = "Test";
ApplicationName = "TestApplication";
ContentRootPath = AppDomain.CurrentDomain.BaseDirectory;
ContentRootFileProvider = new PhysicalFileProvider(ContentRootPath);
}
public string EnvironmentName { get; set; }
public string ApplicationName { get; set; }
public string ContentRootPath { get; set; }
public IFileProvider ContentRootFileProvider { get; set; }
}

265
aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/Users/UserAppServiceTests.cs

@ -0,0 +1,265 @@
using PackageName.CompanyName.ProjectName.Users.Dtos;
using Shouldly;
using System;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Validation;
using Xunit;
namespace PackageName.CompanyName.ProjectName.Users
{
/// <summary>
/// UserAppService 的单元测试
/// </summary>
[Collection("Database")]
public class UserAppServiceTests : ProjectNameApplicationTestBase
{
private readonly IUserAppService _userAppService;
private readonly IUserManager _userManager;
public UserAppServiceTests()
{
_userAppService = GetRequiredService<IUserAppService>();
_userManager = GetRequiredService<IUserManager>();
}
[Theory]
[InlineData("testuser1", "Test123456!", true)]
[InlineData("testuser2", "Test123456!", false)]
public async Task Should_Create_User(
string nickName,
string password,
bool isActive)
{
// Arrange
var input = new CreateUpdateUserDto
{
NickName = nickName,
Password = password,
IsActive = isActive
};
// Act
var result = await _userAppService.CreateAsync(input);
// Assert
result.ShouldNotBeNull();
result.NickName.ShouldBe(nickName);
result.IsActive.ShouldBe(isActive);
}
[Theory]
[InlineData("", "Test123456!", "用户名称不能为空")]
[InlineData("test", "123", "密码长度必须在6-20个字符之间")]
public async Task Should_Not_Create_User_With_Invalid_Input(string nickName, string password,
string expectedErrorMessage)
{
// Arrange
var input = new CreateUpdateUserDto
{
NickName = nickName,
Password = password
};
// Act & Assert
var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
{
await _userAppService.CreateAsync(input);
});
exception.ValidationErrors.ShouldContain(x => x.ErrorMessage.Contains(expectedErrorMessage));
}
[Fact]
public async Task Should_Get_User_List()
{
// Arrange
await CreateTestUserAsync("testuser1", "Test123456!");
await CreateTestUserAsync("testuser2", "Test123456!");
// Act
var result = await _userAppService.GetListAsync(
new UserPagedAndSortedResultRequestDto
{
MaxResultCount = 10,
SkipCount = 0,
Sorting = "NickName"
});
// Assert
result.ShouldNotBeNull();
result.TotalCount.ShouldBeGreaterThanOrEqualTo(2);
result.Items.ShouldContain(x => x.NickName == "testuser1");
result.Items.ShouldContain(x => x.NickName == "testuser2");
}
[Fact]
public async Task Should_Filter_Users_By_NickName()
{
// Arrange
await CreateTestUserAsync("testuser1", "Test123456!");
await CreateTestUserAsync("testuser2", "Test123456!");
await CreateTestUserAsync("otheruser", "Test123456!");
// Act
var result = await _userAppService.GetListAsync(
new UserPagedAndSortedResultRequestDto
{
MaxResultCount = 10,
SkipCount = 0,
Sorting = "NickName",
NickName = "testuser"
});
// Assert
result.ShouldNotBeNull();
result.TotalCount.ShouldBe(2);
result.Items.ShouldContain(x => x.NickName == "testuser1");
result.Items.ShouldContain(x => x.NickName == "testuser2");
result.Items.ShouldNotContain(x => x.NickName == "otheruser");
}
[Fact]
public async Task Should_Update_User()
{
// Arrange
var user = await CreateTestUserAsync("updatetest", "Test123456!");
var updateInput = new CreateUpdateUserDto
{
NickName = "updateduser",
Password = "NewPassword123!",
ContactInfo = "13800138000",
Position = "开发工程师",
IsActive = true
};
// Act
var result = await _userAppService.UpdateAsync(user.Id, updateInput);
// Assert
result.ShouldNotBeNull();
result.NickName.ShouldBe("updateduser");
result.ContactInfo.ShouldBe("13800138000");
result.Position.ShouldBe("开发工程师");
// 验证更新后的用户信息
var updatedUser = await _userAppService.GetAsync(user.Id);
updatedUser.NickName.ShouldBe("updateduser");
}
[Fact]
public async Task Should_Not_Update_Non_Existing_User()
{
// Arrange
var input = new CreateUpdateUserDto
{
NickName = "testuser",
Password = "Test123456!"
};
// Act & Assert
await Assert.ThrowsAsync<EntityNotFoundException>(async () =>
{
await _userAppService.UpdateAsync(Guid.NewGuid(), input);
});
}
[Fact]
public async Task Should_Delete_User()
{
// Arrange
var user = await CreateTestUserAsync("deletetest", "Test123456!");
// Act
await _userAppService.DeleteAsync(user.Id);
// Assert - 尝试获取已删除的用户应该抛出异常
await Assert.ThrowsAsync<EntityNotFoundException>(async () =>
{
await _userAppService.GetAsync(user.Id);
});
}
[Fact]
public async Task Should_Change_User_Password()
{
// Arrange
var user = await CreateTestUserAsync("passwordtest", "OldPassword123!");
// Act & Assert
await _userAppService.ChangePasswordAsync(user.Id, "OldPassword123!", "NewPassword123!");
// 尝试用新密码登录(这个需要集成测试才能完整测试)
// 这里我们只是验证方法执行不会抛出异常
}
[Fact]
public async Task Should_Reset_User_Password()
{
// Arrange
var user = await CreateTestUserAsync("resetpasswordtest", "OldPassword123!");
// Act & Assert
await _userAppService.ResetPasswordAsync(user.Id, "NewPassword123!");
// 同样,完整测试需要验证用户能用新密码登录,这需要集成测试
}
[Fact]
public async Task Should_Set_User_Active_Status()
{
// Arrange
var user = await CreateTestUserAsync("activestatustest", "Password123!");
// Act
await _userAppService.SetUserActiveStatusAsync(user.Id, false);
var disabledUser = await _userAppService.GetAsync(user.Id);
await _userAppService.SetUserActiveStatusAsync(user.Id, true);
var enabledUser = await _userAppService.GetAsync(user.Id);
// Assert
disabledUser.IsActive.ShouldBeFalse();
enabledUser.IsActive.ShouldBeTrue();
}
[Theory]
[InlineData("13900000000", "工程师")]
[InlineData("13800000000", "设计师")]
[InlineData(null, null)]
public async Task Should_Create_User_With_Optional_Fields(string contactInfo, string position)
{
// Arrange
var input = new CreateUpdateUserDto
{
NickName = $"user_{Guid.NewGuid():N}",
Password = "Test123456!",
ContactInfo = contactInfo,
Position = position
};
// Act
var result = await _userAppService.CreateAsync(input);
// Assert
result.ShouldNotBeNull();
result.ContactInfo.ShouldBe(contactInfo);
result.Position.ShouldBe(position);
}
private async Task<UserDto> CreateTestUserAsync(string nickName, string password)
{
return await WithUnitOfWorkAsync(async () =>
{
var input = new CreateUpdateUserDto
{
NickName = nickName,
Password = password,
IsActive = true
};
return await _userAppService.CreateAsync(input);
});
}
}
}

6
aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests.csproj

@ -8,10 +8,14 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
<PackageReference Include="Volo.Abp.EntityFrameworkCore.PostgreSql" />
<PackageReference Include="LINGYUN.Abp.Identity.EntityFrameworkCore" />
<PackageReference Include="LINGYUN.Abp.DataProtection.EntityFrameworkCore" />
<PackageReference Include="Volo.Abp.PermissionManagement.EntityFrameworkCore" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\migrations\PackageName.CompanyName.ProjectName.AIO.EntityFrameworkCore\PackageName.CompanyName.ProjectName.AIO.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\src\PackageName.CompanyName.ProjectName.EntityFrameworkCore\PackageName.CompanyName.ProjectName.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\PackageName.CompanyName.ProjectName.Domain.Tests\PackageName.CompanyName.ProjectName.Domain.Tests.csproj" />
</ItemGroup>

62
aspnet-core/templates/aio/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreTestModule.cs

@ -1,38 +1,74 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using PackageName.CompanyName.ProjectName.AIO.EntityFrameworkCore;
using System;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Volo.Abp.Threading;
using Volo.Abp.Timing;
using Volo.Abp.Uow;
namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore;
[DependsOn(
typeof(ProjectNameTestBaseModule),
typeof(ProjectNameEntityFrameworkCoreModule)
)]
typeof(ProjectNameEntityFrameworkCoreModule),
typeof(SingleMigrationsEntityFrameworkCoreModule)
)]
public class ProjectNameEntityFrameworkCoreTestModule : AbpModule
{
// 数据库配置
private const string DefaultPostgresConnectionString =
"Host=127.0.0.1;Port=5432;Database=test_db;User Id=postgres;Password=postgres;";
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddEntityFrameworkInMemoryDatabase();
var connectionString = Environment.GetEnvironmentVariable("TEST_CONNECTION_STRING") ??
DefaultPostgresConnectionString;
var databaseName = Guid.NewGuid().ToString();
// 配置数据库连接字符串
Configure<AbpDbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = connectionString;
});
Configure<AbpDbContextOptions>(options =>
Configure<AbpClockOptions>(options => { options.Kind = DateTimeKind.Utc; });
context.Services.AddAbpDbContext<SingleMigrationsDbContext>(options =>
{
options.Configure(abpDbContextConfigurationContext =>
{
abpDbContextConfigurationContext.DbContextOptions.EnableDetailedErrors();
abpDbContextConfigurationContext.DbContextOptions.EnableSensitiveDataLogging();
options.AddDefaultRepositories(true);
});
abpDbContextConfigurationContext.DbContextOptions.UseInMemoryDatabase(databaseName);
});
// 配置所有DbContext
Configure<AbpDbContextOptions>(options =>
{
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
options.UseNpgsql();
});
Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; //EF in-memory database does not support transactions
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled;
});
}
}
public override void OnPreApplicationInitialization(ApplicationInitializationContext context)
{
var dbContext = context.ServiceProvider.GetRequiredService<SingleMigrationsDbContext>();
// 重置数据库
dbContext.Database.EnsureDeleted();
// // 创建数据库
dbContext.Database.EnsureCreated();
dbContext.Database.GenerateCreateScript();
// dbContext.Database.Migrate();
// 初始化种子数据
var dataSeeder = context.ServiceProvider.GetRequiredService<IDataSeeder>();
AsyncHelper.RunSync(() => dataSeeder.SeedAsync());
}
public override void OnApplicationShutdown(ApplicationShutdownContext context)
{
}
}
Loading…
Cancel
Save