[英]How to access IWebHostEnvironment from Program.cs in ASP.NET Core
I have ASP.NET Core Razor pages app and I would like to access IWebHostEnvironment
in my Program.cs
.我有 ASP.NET 核心 Razor 页面应用程序,我想在我的
Program.cs
中访问IWebHostEnvironment
。 I seed the DB at the beginning of the application, and I need to pass the IWebHostEnvironment
to my initializer.我在应用程序开始时为 DB 播种,我需要将
IWebHostEnvironment
传递给我的初始化程序。 Here is my code:这是我的代码:
Program.cs程序.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>();
});
}
SeedData.cs种子数据.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();
}
Because I have images in wwwroot
and I need to get names of of images from there during initializtion.因为我在
wwwroot
中有图像,我需要在初始化期间从那里获取图像的名称。 I tried to pass IWebHostEnvironment
from Startup.cs inside of configure method:我尝试在配置方法中从Startup.cs传递
IWebHostEnvironment
:
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();
});
}
But it seems that the Startup.Configure
method gets executed after the Program.Main
method.但似乎
Startup.Configure
方法在Program.Main
方法之后执行。 Then I decided to do it in Startup.ConfigureServices
method, but it turns out that this method can only take up to 1 parameter.然后我决定在
Startup.ConfigureServices
方法中进行,但事实证明该方法最多只能占用 1 个参数。 Is there any way to achieve this?有什么办法可以做到这一点? However, I'm not sure that the way I'm trying to seed my data is the best one, I just see this way as the most appropriate for my case, so I would totally appreciate any other suggested approach.
但是,我不确定我尝试播种数据的方式是最好的方式,我只是认为这种方式最适合我的情况,所以我非常感谢任何其他建议的方法。
Similar problems I found:我发现的类似问题:
The original issue demonstrates how trying to use DI with static classes cause more problems than it solves.原始问题演示了如何尝试将 DI 与 static 类一起使用会导致比它解决的问题更多的问题。
The seeder can be a scoped registered class and resolved from the host after it has been built.播种器可以是一个作用域注册的 class 并在构建后从主机解析。 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
}
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.
所有必要的依赖项都根据需要显式注入到 class 中。
Program
can then be simplified然后可以简化
Program
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>();
});
}
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. IWebHostEnvironment
和所有其他依赖项将由 DI 容器解析并在需要的地方注入。
The solution for my problem was to simply request IWebHostEnvironment
from ServiceProvider.GetRequiredService<T>
:我的问题的解决方案是简单地从
ServiceProvider.GetRequiredService<T>
请求IWebHostEnvironment
:
Main主要的
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var hostEnvironment = services.GetRequiredService<IWebHostEnvironment>();
try
{
SeedData.Initialize(services, hostEnvironment);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.