Mir*_*ziz 5 c# development-environment dependency-injection asp.net-core
我有 ASP.NET Core Razor 页面应用程序,我想IWebHostEnvironment在我的Program.cs. 我在应用程序开始时播种数据库,并且需要将其传递IWebHostEnvironment给初始化程序。这是我的代码:
程序.cs
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
SeedData.Initialize(services);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Run Code Online (Sandbox Code Playgroud)
种子数据.cs
public static class SeedData
{
private static IWebHostEnvironment _hostEnvironment;
public static bool IsInitialized { get; private set; }
public static void Init(IWebHostEnvironment hostEnvironment)
{
if (!IsInitialized)
{
_hostEnvironment = hostEnvironment;
IsInitialized = true;
}
}
public static void Initialize(IServiceProvider serviceProvider)
{
//List<string> imageList = GetMovieImages(_hostEnvironment);
int d = 0;
using var context = new RazorPagesMovieContext(
serviceProvider.GetRequiredService<
DbContextOptions<RazorPagesMovieContext>>());
if (context.Movie.Any())
{
return; // DB has been seeded
}
var faker = new Faker("en");
var movieNames = GetMovieNames();
var genreNames = GetGenresNames();
foreach(string genreTitle in genreNames)
{
context.Genre.Add(new Genre { GenreTitle = genreTitle });
}
context.SaveChanges();
foreach(string movieTitle in movieNames)
{
context.Movie.Add(
new Movie
{
Title = movieTitle,
ReleaseDate = GetRandomDate(),
Price = GetRandomPrice(5.5, 30.5),
Rating = GetRandomRating(),
Description = faker.Lorem.Sentence(20, 100),
GenreId = GetRandomGenreId()
}
);
}
context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
因为我有图像,wwwroot所以我需要在初始化期间从那里获取图像的名称。我尝试IWebHostEnvironment从Startup.cs内部的配置方法传递:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
int d = 0;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
SeedData.Init(env); // Initialize IWebHostEnvironment
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Run Code Online (Sandbox Code Playgroud)
但似乎该Startup.Configure方法是在该方法之后执行的Program.Main。然后我决定用method来做Startup.ConfigureServices,但结果发现这个方法最多只能带1个参数。有什么办法可以实现这一点吗?但是,我不确定我尝试播种数据的方式是最好的方式,我只是认为这种方式最适合我的情况,所以我非常感谢任何其他建议的方法。
我发现类似的问题:
The original issue demonstrates how trying to use DI with static classes cause more problems than it solves.
The seeder can be a scoped registered class and resolved from the host after it has been built. The host environment and any other dependencies can be explicitly injected via constructor injection
For example
public class SeedData {
private readonly IWebHostEnvironment hostEnvironment;
private readonly RazorPagesMovieContext context;
private readonly ILogger logger;
public SeedData(IWebHostEnvironment hostEnvironment, RazorPagesMovieContext context, ILogger<SeedData> logger) {
this.hostEnvironment = hostEnvironment;
this.context = context;
this.logger = logger;
}
public void Run() {
try {
List<string> imageList = GetMovieImages(hostEnvironment); //<<-- USE DEPENDENCY
int d = 0;
if (context.Movie.Any()) {
return; // DB has been seeded
}
var faker = new Faker("en");
var movieNames = GetMovieNames();
var genreNames = GetGenresNames();
foreach(string genreTitle in genreNames) {
context.Genre.Add(new Genre { GenreTitle = genreTitle });
}
context.SaveChanges();
foreach(string movieTitle in movieNames) {
context.Movie.Add(
new Movie {
Title = movieTitle,
ReleaseDate = GetRandomDate(),
Price = GetRandomPrice(5.5, 30.5),
Rating = GetRandomRating(),
Description = faker.Lorem.Sentence(20, 100),
GenreId = GetRandomGenreId()
}
);
}
context.SaveChanges();
} catch (Exception ex) {
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
// ... other code
}
Run Code Online (Sandbox Code Playgroud)
Note how there was no longer a need for Service Locator anti-pattern. All the necessary dependencies are explicitly injected into the class as needed.
Program can then be simplified
public class Program {
public static void Main(string[] args) {
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope()) {
SeedData seeder = scope.ServiceProvider.GetRequiredService<SeedData>();
seeder.Run();
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices(services => {
services.AddScoped<SeedData>(); //<-- NOTE
})
.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>();
});
}
Run Code Online (Sandbox Code Playgroud)
where the seeder is registered with the host and resolved as needed before running the host. Now there is no need to access anything other than the seeder. IWebHostEnvironment and all other dependencies will be resolved by the DI container and injected where needed.
| 归档时间: |
|
| 查看次数: |
10746 次 |
| 最近记录: |