繁体   English   中英

如何从 ASP.NET Core 中的 Program.cs 访问 IWebHostEnvironment

[英]How to access IWebHostEnvironment from Program.cs in ASP.NET Core

我有 ASP.NET 核心 Razor 页面应用程序,我想在我的Program.cs中访问IWebHostEnvironment 我在应用程序开始时为 DB 播种,我需要将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>();
            });
}

种子数据.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();
        }

因为我在wwwroot中有图像,我需要在初始化期间从那里获取图像的名称。 我尝试在配置方法中从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();
        });
    }

但似乎Startup.Configure方法在Program.Main方法之后执行。 然后我决定在Startup.ConfigureServices方法中进行,但事实证明该方法最多只能占用 1 个参数。 有什么办法可以做到这一点? 但是,我不确定我尝试播种数据的方式是最好的方式,我只是认为这种方式最适合我的情况,所以我非常感谢任何其他建议的方法。

我发现的类似问题:

原始问题演示了如何尝试将 DI 与 static 类一起使用会导致比它解决的问题更多的问题。

播种器可以是一个作用域注册的 class 并在构建后从主机解析。 主机环境和任何其他依赖项可以通过构造函数注入显式注入

例如

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

}

请注意不再需要服务定位器反模式。 所有必要的依赖项都根据需要显式注入到 class 中。

然后可以简化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>();
            });
}

播种机在主机上注册并在运行主机之前根据需要进行解析。 现在不需要访问除了播种机之外的任何东西。 IWebHostEnvironment和所有其他依赖项将由 DI 容器解析并在需要的地方注入。

我的问题的解决方案是简单地从ServiceProvider.GetRequiredService<T>请求IWebHostEnvironment

主要的

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM