Как получить среду разработки / размещения / производства в ConfigureServices

171

Как получить среду хостинга для разработки / организации / производства в ConfigureServicesметоде Startup?

public void ConfigureServices(IServiceCollection services)
{
    // Which environment are we running under?
}

ConfigureServicesМетод только принимает один IServiceCollectionпараметр.

Мухаммед Рехан Саид
источник
4
почему нельзя IHostingEnvironmentпросто ввести в ConfigureServices? надзор? или причину, которую мы должны знать?
Simon_Waaaver

Ответы:

226

Вы можете легко получить к нему доступ в ConfigureServices, просто сохранить его в свойстве во время запуска метода, который сначала вызывается и получает его, затем вы можете получить доступ к свойству из ConfigureServices.

public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
    ...your code here...
    CurrentEnvironment = env;
}

private IHostingEnvironment CurrentEnvironment{ get; set; } 

public void ConfigureServices(IServiceCollection services)
{
    string envName = CurrentEnvironment.EnvironmentName;
    ... your code here...
}
Джо Одетт
источник
13
Согласно документации , этот метод не должен использоваться. Вы должны вместо этого использовать CurrentEnvironment.IsEnvironment("environmentname").
vaindil
28
или CurrentEnvironment.IsDevelopment()/CurrentEnvironment.IsProduction()
Simon_Weaver
3
@vaindil - документы, на которые вы ссылаетесь, не говорят, что этот метод не должен использоваться. Ваш пример просто игнорирует регистр, который во многих случаях предпочтителен, но не заповедь
Coruscate5
3
@ Coruscate5 Хорошо, он явно не говорит, что НЕ использует этот метод, но он говорит, чтобы использовать другой метод INSTEAD. Это практически то же самое.
Вайндил
8
устарел IHostingEnvironment env, вместо этого используйте IWebHostEnvironment env
Марк Шультейс
56

TL; DR

Установите переменную среды, вызываемую ASPNETCORE_ENVIRONMENTс именем среды (например Production). Затем сделайте одно из двух:

  • Вводят IHostingEnvironmentв Startup.cs, а затем использовать что ( envздесь) , чтобы проверить: env.IsEnvironment("Production"). Не проверяйте с помощью env.EnvironmentName == "Production"!
  • Используйте либо отдельные Startupклассы, либо отдельные Configure/ ConfigureServicesфункции. Если класс или функции соответствуют этим форматам, они будут использоваться вместо стандартных параметров в этой среде.
    • Startup{EnvironmentName}() (весь класс) || пример:StartupProduction()
    • Configure{EnvironmentName}()|| пример:ConfigureProduction()
    • Configure{EnvironmentName}Services()|| пример:ConfigureProductionServices()

Полное объяснение

Документы .NET Core описывают, как этого добиться . Используйте переменную окружения, ASPNETCORE_ENVIRONMENTкоторая называется желаемой средой, тогда у вас есть два варианта.

Проверьте название среды

Из документов :

IHostingEnvironmentСлужба предоставляет базовую абстракцию для работы со средами. Этот сервис предоставляется хостингом ASP.NET и может быть внедрен в логику запуска через Dependency Injection. Шаблон веб-сайта ASP.NET Core в Visual Studio использует этот подход для загрузки специфичных для среды файлов конфигурации (если они есть) и для настройки параметров обработки ошибок приложения. В обоих случаях такое поведение достигается путем обращения к указанной в данный момент среде путем вызова EnvironmentNameили IsEnvironmentэкземпляра, IHostingEnvironmentпереданного в соответствующий метод.

ПРИМЕЧАНИЕ: Проверка фактического значения env.EnvironmentNameявляется не рекомендуется!

Если вам необходимо проверить, работает ли приложение в определенной среде, используйте env.IsEnvironment("environmentname")его, поскольку оно будет правильно игнорировать регистр (вместо проверки, env.EnvironmentName == "Development"например, если ).

Используйте отдельные классы

Из документов :

Когда запускается приложение ASP.NET Core, этот Startupкласс используется для начальной загрузки приложения, загрузки его параметров конфигурации и т. Д. ( Подробнее о запуске ASP.NET ). Однако, если существует класс с именем Startup{EnvironmentName}(например StartupDevelopment), и ASPNETCORE_ENVIRONMENTпеременная окружения соответствует этому имени, тогда используется этот Startupкласс. Таким образом, вы можете настроить Startupдля разработки, но есть отдельная StartupProduction, которая будет использоваться при запуске приложения в производстве. Или наоборот.

Помимо использования совершенно отдельного Startupкласса, основанного на текущей среде, вы также можете внести коррективы в настройку приложения в Startupклассе. Configure()И ConfigureServices()методы поддержки экологически конкретные версии , аналогичные Startupсамого класса, вида Configure{EnvironmentName}()и Configure{EnvironmentName}Services(). Если вы определите метод, ConfigureDevelopment()он будет вызываться вместо того, Configure()когда среда настроена на разработку. Точно так же ConfigureDevelopmentServices()будет вызван, а не ConfigureServices()в той же среде.

vaindil
источник
29

В .NET Core 2.0MVC app / Microsoft.AspNetCore.Allv2.0.0 у вас может быть класс запуска, специфичный для среды, как описано @vaindil, но мне не нравится такой подход.

Вы также можете ввести IHostingEnvironmentв StartUpконструктор. Вам не нужно хранить переменную среды в Programклассе.

public class Startup
{
    private readonly IHostingEnvironment _currentEnvironment;
    public IConfiguration Configuration { get; private set; }

    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {
        _currentEnvironment = env;
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        ......

        services.AddMvc(config =>
        {
            // Requiring authenticated users on the site globally
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            config.Filters.Add(new AuthorizeFilter(policy));

            // Validate anti-forgery token globally
            config.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());

            // If it's Production, enable HTTPS
            if (_currentEnvironment.IsProduction())      // <------
            {
                config.Filters.Add(new RequireHttpsAttribute());
            }            
        });

        ......
    }
}
Дэвид Лян
источник
1
Подробности можно посмотреть по адресу
Андре Моралес,
Вот ссылка на английский, размещенная Андре: docs.microsoft.com/en-us/aspnet/core/fundamentals/…
ахонг
1
устарел IHostingEnvironment env, вместо этого используйте IWebHostEnvironment env
Марк Шультейс
21

Это может быть выполнено без каких-либо дополнительных свойств или параметров метода, например:

public void ConfigureServices(IServiceCollection services)
{
    IServiceProvider serviceProvider = services.BuildServiceProvider();
    IHostingEnvironment env = serviceProvider.GetService<IHostingEnvironment>();

    if (env.IsProduction()) DoSomethingDifferentHere();
}
edicius6
источник
2
лучший ответ когда-либо. спасибо
Shady
7
Это вызывает следующее предупреждение в .NET Core 3.0: вызов BuildServiceProvider из кода приложения приводит к созданию дополнительной копии одноэлементных сервисов. Рассмотрим альтернативы, такие как сервисы внедрения зависимостей в качестве параметров для «Настройка».
Eternal21
2
устарел IHostingEnvironment env, вместо этого используйте IWebHostEnvironment env
Марк Шультейс
19

Если вам нужно проверить это где-то в вашей кодовой базе, у которой нет простого доступа к IHostingEnvironment, другой простой способ сделать это так:

bool isDevelopment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
Патрик
источник
ну, короткий путь! Имейте в виду, что имя переменной различается между "ядром asp.net" и "asp.net"
nmDat
15

согласно документам

Configure и ConfigureServices поддерживают специфичные для среды версии в форме Configure {EnvironmentName} и Configure {EnvironmentName} Services:

Вы можете сделать что-то вроде этого ...

public void ConfigureProductionServices(IServiceCollection services)
{
    ConfigureCommonServices(services);

    //Services only for production
    services.Configure();
}

public void ConfigureDevelopmentServices(IServiceCollection services)
{
    ConfigureCommonServices(services);

    //Services only for development
    services.Configure();
}

public void ConfigureStagingServices(IServiceCollection services)
{
    ConfigureCommonServices(services);

    //Services only for staging
    services.Configure();
}

private void ConfigureCommonServices(IServiceCollection services)
{
    //Services common to each environment
}
башмак
источник
1
Это самая
хорошая
11

Я хотел получить окружающую среду в одном из моих сервисов. Это действительно легко сделать! Я просто вставляю это в конструктор так:

    private readonly IHostingEnvironment _hostingEnvironment;

    public MyEmailService(IHostingEnvironment hostingEnvironment)
    {
        _hostingEnvironment = hostingEnvironment;
    }

Теперь позже в коде я могу сделать это:

if (_hostingEnvironment.IsProduction()) {
    // really send the email.
}
else {
    // send the email to the test queue.
}

РЕДАКТИРОВАТЬ:

Код выше для .NET Core 2. Для версии 3 вы захотите использовать IWebHostEnvironment.

Джесс
источник
5

Среда размещения происходит из переменной среды ASPNET_ENV, которая доступна во время запуска с использованием метода расширения IHostingEnvironment.IsEnvironment или одного из соответствующих вспомогательных методов IsDevelopment или IsProduction. Сохраните то, что вам нужно, в Startup () или в вызове ConfigureServices:

var foo = Environment.GetEnvironmentVariable("ASPNET_ENV");
Джефф Данлоп
источник
IHostingEnvironmentнедоступно в ConfigureServices.
Мухаммед Рехан Саид
1
Нет, это не так. Обратитесь к моему ответу о том, как с этим бороться.
Джефф Данлоп
8
Переменная среды теперь "ASPNETCORE_ENVIRONMENT"
Энтони,
устарел IHostingEnvironment env, вместо этого используйте IWebHostEnvironment env
Марк Шультейс
5

На всякий случай, если кто-то тоже смотрит на это. В .net core 3+ большая часть этого устарела. Способ обновления:

public void Configure(
    IApplicationBuilder app,
    IWebHostEnvironment env,
    ILogger<Startup> logger)
{
    if (env.EnvironmentName == Environments.Development)
    {
        // logger.LogInformation("In Development environment");
    }
}
Ваагн Нахапетян
источник
2

В Dotnet Core 2.0 Startup-конструктор ожидает только IConfiguration-параметр.

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

Как читать там хостинг? Я сохраняю его в классе Program во время ConfigureAppConfiguration (используйте полный BuildWebHost вместо WebHost.CreateDefaultBuilder):

public class Program
{
    public static IHostingEnvironment HostingEnvironment { get; set; }

    public static void Main(string[] args)
    {
        // Build web host
        var host = BuildWebHost(args);

        host.Run();
    }

    public static IWebHost BuildWebHost(string[] args)
    {
        return new WebHostBuilder()
            .UseConfiguration(new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("hosting.json", optional: true)
                .Build()
            )
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
                var env = hostingContext.HostingEnvironment;

                // Assigning the environment for use in ConfigureServices
                HostingEnvironment = env; // <---

                config
                  .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                  .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                if (env.IsDevelopment())
                {
                    var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
                    if (appAssembly != null)
                    {
                        config.AddUserSecrets(appAssembly, optional: true);
                    }
                }

                config.AddEnvironmentVariables();

                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
            .ConfigureLogging((hostingContext, builder) =>
            {
                builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                builder.AddConsole();
                builder.AddDebug();
            })
            .UseIISIntegration()
            .UseDefaultServiceProvider((context, options) =>
            {
                options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
            })
            .UseStartup<Startup>()
            .Build();
    }

Затем Ant читает его в ConfigureServices следующим образом:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    var isDevelopment = Program.HostingEnvironment.IsDevelopment();
}
toralux
источник
устарел IHostingEnvironment env, вместо этого используйте IWebHostEnvironment env
Марк Шультейс