Ef core как получить iwebhostenvironment в модели

Ef core как получить iwebhostenvironment в модели

Для взаимодействия со средой, в которой запущено приложение, применяются объекты, реализующие интерфейс IHostingEnvironment . Этот интерфейс предлагает ряд свойств, с помощью которых мы можем получить информацию об окружении:

ApplicationName : возвращает имя приложения

EnvironmentName : возвращает описание среды, в которой хостируется приложение

ContentRootPath : возвращает путь к корневой папке приложения

WebRootPath : возвращает путь к папке, в которой хранится статический контент приложения, как правило, это папка wwwroot

ContentRootFileProvider : возвращает реализацию интерфейса Microsoft.AspNetCore.FileProviders.IFileProvider , которая может использоваться для чтения файлов из папки ContentRootPath

WebRootFileProvider : возвращает реализацию интерфейса Microsoft.AspNetCore.FileProviders.IFileProvider , которая может использоваться для чтения файлов из папки WebRootPath

При разработке мы можем использовать эти свойства. Но наиболее часто при разработке придется сталкиваться со свойством EnvironmentName . По умолчанию имеются три варианта значений для этого свойства: Development, Staging и Production. В проекте это свойство задается через установку переменной среды ASPNETCORE_ENVIRONMENT . Ее текущее значение можно посмотреть в свойствах проекта на вкладке Debug:

Environment Name in ASP.NET Core

Здесь же также можно изменить значение этой переменной.

Кроме того, в проекте в папке Properties есть файл launchSettings.json , который также содержит описания переменных сред:

Здесь можно увидеть, что переменная «ASPNETCORE_ENVIRONMENT» встречается два раза — для запуска через IISExpress и для запуска через Kestrel. В обоих случаях она имеет значение Development. Здесь мы также можем поменять значение этой переменной. Причем файл launchSettings.json переопределяет настройки проекта. Например, если в launchSettings.json мы определим «ASPNETCORE_ENVIRONMENT»: «Production» , то имя среды нашего проекта будет «Production», хотя в настройках проекта может стоять «Development».

Для определения значения этой переменной для интерфейса IWebHostEnvironment определены специальные методы расширения:

IsEnvironment(string envName) : возвращает true , если имя среды равно значению параметра envName

IsDevelopment() : возвращает true , если имя среды — Development

IsStaging() : возвращает true , если имя среды — Staging

IsProduction() : возвращает true , если имя среды — Production

Например, при создании нового проекта в методе Configure() класса Startup можно найти следующие строки:

Таким образом, если имя среды имеет значение «Development», то есть приложение находится в состоянии разработки, то при ошибке разработчик увидит детальное описание ошибки. Если же приложение развернуто на хостинге и соответственно имеет другое имя хостирующей среды, то простой пользователь при ошибке ничего не увидит. Таким образом, в зависимости от стадии, на которой находится проект, мы можем скрывать или задействовать часть функционала приложения.

Определение своих состояний среды

Хотя по умолчанию среда может принимать три состояния: Development, Staging, Production, но мы можем при желании вводить новые значения. Например, нам надо отслеживать какие-то дополнительные состояния. К примеру, изменим в файле launchSettings.json значение «ASPNETCORE_ENVIRONMENT» на «Test» (значение может быть произвольное):

Далее мы можем использовать это состояния для выполнения различных действий. Например, используем состояние «Test» в классе Startup:

How to get the Development/Staging/production Hosting Environment in ConfigureServices

How do I get the Development/Staging/production Hosting Environment in the ConfigureServices method in Startup?

The ConfigureServices method only takes a single IServiceCollection parameter.

ArunPratap's user avatar

Muhammad Rehan Saeed's user avatar

15 Answers 15

You can easily access it in ConfigureServices, just persist it to a property during Startup method which is called first and gets it passed in, then you can access the property from ConfigureServices.

Joe Audette's user avatar

Set an environment variable called ASPNETCORE_ENVIRONMENT with the name of the environment (e.g. Production ). Then do one of two things:

  • Inject IHostingEnvironment into Startup.cs , then use that ( env here) to check: env.IsEnvironment(«Production») . Do not check using env.EnvironmentName == «Production» !
  • Use either separate Startup classes or individual Configure / ConfigureServices functions. If a class or the functions match these formats, they will be used instead of the standard options on that environment.
    • Startup() (entire class) || example: StartupProduction()
    • Configure() || example: ConfigureProduction()
    • ConfigureServices() || example: ConfigureProductionServices()

    Full explanation

    The .NET Core docs describe how to accomplish this. Use an environment variable called ASPNETCORE_ENVIRONMENT that’s set to the environment you want, then you have two choices.

    Внедрить IWebHostingEnvironment в переопределенный метод

    Используя ASP.NET Core 5.0, я пытаюсь получить доступ IWebHostEnvironment к классу модели EF Core 5.0. Как я могу получить доступ к проверке IsDevelopment истинности из окружения?

    Я вызываю следующий класс из своих контроллеров так:

    Мне действительно нужно раскручивать IWebHostEnvironment каждый контроллер, который вызывает этот класс EF, чтобы выбрать правильный конструктор?

    Я видел несколько угроз по поводу DI, но, честно говоря, у них есть запутанные решения, которые я не могу понять.

    Исследуем .NET 6. Часть 3. Рассматриваем код WebApplicationBuilder

    В предыдущем посте я сравнивал новый WebApplication с универсальным хостом. В этом посте я рассмотрю код, лежащий в основе WebApplicationBuilder , чтобы увидеть, как он обеспечивает более чистый, минимальный API хостинга, при этом обеспечивая ту же функциональность, что и универсальный хост.

    WebApplication и WebApplicationBuilder: новый способ начальной загрузки приложений ASP.NET Core

    В .NET 6 представлен совершенно новый способ «начальной загрузки» приложения ASP.NET Core. Вместо традиционного разделения между Program.cs и Startup.cs весь код находится в Program.cs и является гораздо более процедурным, чем множество лямбда-методов, которых требовал универсальный хост в предыдущих версиях:

    В язык C# добавлены различные обновления, которые делают всё это более чистым (операторы верхнего уровня, неявные директивы using, выведение типов в лямбдах и т. д.). Но также появились два новых типа: WebApplication и WebApplicationBuilder . В предыдущем посте я кратко описал, как использовать WebApplication и WebApplicationBuilder для настройки приложения ASP.NET Core. В этом посте мы рассмотрим их код, чтобы увидеть, как получился более простой API, при сохранении той же гибкости и настраиваемости, что и у универсального хоста.

    Создание WebApplicationBuilder

    Первым шагом в нашем примере программы является создание экземпляра WebApplicationBuilder с использованием статического метода класса WebApplication :

    Это создаёт новый экземпляр WebApplicationOptions , инициализирует аргументы Args из аргументов командной строки и передаёт объект параметров в конструктор WebApplicationBuilder (показанный кратко ниже):

    Кстати, новое сокращённое ключевое слово new , когда целевой тип неочевиден, — просто отстой при разборе кода. Невозможно даже предположить, что создаёт второй new() в приведённом выше коде. Во многом претензии те же самые, как и к повсеместному использованию var , но в данном случае это меня особенно раздражает.

    WebApplicationOptions предоставляет простой способ программного переопределения некоторых важных свойств. Если они не установлены, они будут выведены в значения по умолчанию, как и в предыдущих версиях .NET.

    Конструктор WebApplicationBuilder – это то место, где происходит большая часть магии, чтобы заставить работать концепцию минимального хостинга:

    Я ещё не показал тело метода, так как в этом конструкторе много чего происходит и используется много вспомогательных типов. Мы вернёмся к ним через секунду, а пока сосредоточимся на публичном API WebApplicationBuilder .

    Публичный API WebApplicationBuilder

    Публичный API WebApplicationBuilder состоит из набора свойств, доступных только для чтения, и одного метода Build() , который создаёт WebApplication .

    Если вы знакомы с ASP.NET Core, вы заметите, что многие из этих свойств используют стандартные типы из предыдущих версий:

    IWebHostEnvironment – используется для получения имени среды, пути к корню контента и подобных значений.

    IServiceCollection – используется для регистрации сервисов в контейнере DI. Обратите внимание, что это альтернатива методу ConfigureServices() , используемому универсальным хостом для достижения того же результата.

    ConfigurationManager – используется как для добавления новой конфигурации, так и для получения значений конфигурации. См. первый пост в серии, где обсуждается этот вопрос.

    ILoggingBuilder – используется для регистрации дополнительных поставщиков журналов, как и в случае с методом ConfigureLogging() в универсальном хосте.

    Свойства WebHost и Host интересны тем, что они предоставлены новыми типами ConfigureWebHostBuilder и ConfigureHostBuilder . Эти типы реализуют IWebHostBuilder и IHostBuilder соответственно и в основном представлены как замена для используемых ранее методов расширения.

    Например, в предыдущем посте я показал, как можно зарегистрировать интеграцию Serilog с ASP.NET Core, вызвав UseSerilog() на свойстве Host :

    Раскрытие интерфейсов IWebHostBuilder и IHostBuilder было абсолютно необходимо для обеспечения возможности перехода к новому минимальному API хостинга WebApplication , но это также оказалось проблемой. Как согласовать конфигурацию в виде лямбд/обратных вызовов в IHostBuilder с императивным стилем в WebApplicationBuilder ? Вот где в игру вступают ConfigureHostBuilder и ConfigureWebHostBuilder вместе с некоторыми внутренними реализациями IHostBuilder :

    Мы начнём с рассмотрения публичных ConfigureHostBuilder и ConfigureWebHostBuilder .

    ConfigureHostBuilder

    ConfigureHostBuilder и ConfigureWebHostBuilder были добавлены как часть обновлений для минимального хостинга. Они реализуют IHostBuilder и IWebHostBuilder соответственно. В этом посте мы подробно рассмотрим ConfigureHostBuilder :

    ConfigureHostBuilder реализует IHostBuilder , и похоже, что он реализует ISupportsConfigureWebHost , но взгляд на реализацию показывает, что это не так:

    Это означает, что хотя следующий код и компилируется

    он выбрасывает исключение NotSupportedException во время выполнения. Это явно не идеально, но это цена, которую мы платим за наличие хорошего императивного API для настройки сервисов и т. д. То же самое верно и для метода IHostBuilder.Build() – он выбросит NotSupportedException .

    Видеть исключения времени выполнения никогда не доставляет радости, но это помогает думать о ConfigureHostBuilder как об «адаптере» для существующих методов расширения (таких как метод UseSerilog() ), а не как о «реальном построителе» хоста. Это становится очевидным, когда вы видите, как такие методы, как ConfigureServices() или ConfigureAppConfiguration() , реализованы для этих типов:

    Например, метод ConfigureServices() немедленно выполняет предоставленный делегат Action<> , используя внедрённую коллекцию IServiceCollection из WebApplicationBuilder . Таким образом, следующие два вызова функционально идентичны:

    Последний подход явно не стоит использовать в обычной практике, но существующий код, который полагается на этот метод (например, методы расширения), все ещё можно использовать.

    Не все делегаты, переданные методам в ConfigureHostBuilder , запускаются немедленно. Некоторые из них, например UseServiceProviderFactory() , сохраняются в списке и выполняются позже при вызове WebApplicationBuilder.Build()

    Вот примерно и всё про тип ConfigureHostBuilder . ConfigureWebHostBuilder очень похож и действует как адаптер от предыдущего API к новому императивному стилю. Теперь мы можем вернуться к конструктору WebApplicationBuilder .

    Вспомогательный класс BootstrapHostBuilder

    Прежде чем мы отвлеклись на ConfigureHostBuilder , мы собирались взглянуть на конструктор WebApplicationBuilder . Но мы еще не готовы к этому. сначала нужно взглянуть на ещё один вспомогательный класс, BootstrapHostBuilder .

    BootstrapHostBuilder – это внутренняя реализация IHostBuilder , используемая в WebApplicationBuilder . В основном это относительно простая реализация, которая «запоминает» все полученные вызовы IHostBuilder . Например, функции ConfigureHostConfiguration() и ConfigureServices() выглядят следующим образом:

    В отличие от ConfigureHostBuilder , который немедленно выполнял переданный делегат, BootstrapHostBuilder «сохраняет» переданные делегаты в список для последующего выполнения. Это похоже на то, как работает универсальный HostBuilder. Но обратите внимание, что BootstrapHostBuilder – это ещё одна «нестроящаяся» реализация IHostBuilder , в которой вызов Build() выдаёт исключение:

    Большая часть сложности BootstrapHostBuilder заключается в его методе RunDefaultCallbacks(ConfigurationManager, HostBuilder) . Он используется для применения сохранённых делегатов в правильном порядке, как мы увидим позже.

    Конструктор WebApplicationBuilder

    Наконец, мы дошли до конструктора WebApplicationBuilder . Он содержит много кода, поэтому я буду рассматривать его по частям.

    Обратите внимание, что я позволил себе вольность удалить второстепенные фрагменты кода (например, защитные конструкции и тестовый код).

    Начнем с приватных полей и свойств. _hostBuilder – это экземпляр универсального хоста HostBuilder , который является «внутренним» хостом в WebApplicationBuilder . У нас также есть поле BootstrapHostBuilder (из предыдущего раздела) и экземпляр WebApplicationServiceCollection , являющийся реализацией IServiceCollection , которую я пока не буду рассматривать.

    WebApplicationBuilder действует как «адаптер» для универсального хоста _hostBuilder, предоставляя императивный API, который я исследовал в моём предыдущем посте, сохраняя при этом ту же функциональность, что и универсальный хост.

    К счастью, следующие шаги в конструкторе хорошо документированы:

    После создания экземпляра BootstrapHostBuilder первым вызывается метод расширения HostingBuilderExtension.ConfigureDefaults() . Это тот же метод, который вызывается универсальным хостом при вызове Host.CreateDefaultBuilder() .

    Обратите внимание, что аргументы не передаются в вызов ConfigureDefaults() , а вместо этого применяются позже. В результате на этом этапе аргументы не используются для настройки конфигурации хоста (конфигурация хоста определяет такие значения, как имя приложения и среда хостинга).

    Следующий вызов метода GenericHostBuilderExtensions.ConfigureWebHostDefaults() , который является тем же методом расширения, который мы обычно вызываем при использовании универсального хоста в ASP.NET Core 3.x/5.

    Этот метод по сути добавляет «адаптер» IWebHostBuilder поверх BootstrapHostBuilder , вызывает на нём WebHost.ConfigureWebDefaults() , а затем немедленно запускает переданный лямбда-метод. Это регистрирует метод WebApplicationBuillder.ConfigureApplication() для последующего вызова, который устанавливает целую кучу промежуточного ПО. Мы вернёмся к этому методу в следующем посте.

    После настройки веб-хоста следующий метод применяет аргументы к конфигурации хоста, гарантируя, что они правильно переопределяют значения по умолчанию, установленные предыдущими методами расширения:

    Наконец, вызывается метод BootstrapHostBuilder.RunDefaultCallbacks() , который запускает все сохранённые обратные вызовы, которые мы накопили до сих пор, в правильном порядке, чтобы построить HostBuilderContext . Затем HostBuilderContext используется для окончательной установки остальных свойств в WebApplicationBuilder .

    Это конец конструктора. На этом этапе приложение настроено со всеми настройками по умолчанию для «хостинга»: конфигурация, ведение журнала, службы DI, среда и т. д.

    Теперь вы можете добавить все свои собственные сервисы, дополнительную конфигурацию или ведение журнала в WebApplicationBuilder :

    Закончив настройку конкретного приложения, вы вызываете Build() для создания экземпляра WebApplication . В последнем разделе этого поста мы заглянем внутрь метода Build() .

    Построение WebApplication в WebApplicationBuilder.Build()

    Метод Build() не очень длинный, но его немного сложно понять, поэтому я рассмотрю его построчно:

    Первое, что мы делаем, это копируем источники конфигурации, настроенные в ConfigurationManager , в реализацию ConfigurationBuilder _hostBuilder . Когда вызывается этот метод, построитель изначально пуст, поэтому он заполняет все источники, которые были добавлены как методами расширения построителя по умолчанию, так и дополнительные источники, которые вы настроили впоследствии.

    Обратите внимание, что технически метод ConfigureHostConfiguration запускается не сразу. Скорее, мы регистрируем обратный вызов, который будет вызываться, когда мы далее вызовем _hostBuilder.Build() .

    Затем мы делаем то же самое для IServiceCollection , копируя их из экземпляра _services в коллекцию _hostBuilder . Комментарии здесь достаточно выразительные. В этом случае коллекция сервисов _hostBuilder не всегда пуста, но мы добавляем в неё всё из Services, а затем «сбрасываем» Services в экземпляр _hostBuilder .

    В следующей строке мы запускаем все обратные вызовы, которые мы собрали в свойстве ConfigureHostBuilder , как я показывал выше.

    Если они есть, то это обратные вызовы, такие как ConfigureContainer() и UseServiceProviderFactory() , которые обычно используются только в том случае, если вы используете сторонний контейнер DI.

    Наконец, мы вызываем _hostBuilder.Build() для создания экземпляра Host и передаём его новому экземпляру WebApplication . Вызов _hostBuilder.Build() – это то место, где вызываются все зарегистрированные обратные вызовы.

    Теперь нам надо сделать небольшую уборку. Чтобы всё было согласовано, экземпляр ConfigurationManager очищается и связывается с конфигурацией, хранящейся в WebApplication . Кроме того, IServiceCollection в WebApplicationBuilder помечается как доступный только для чтения, поэтому попытка добавить службы после вызова WebApplicationBuilder вызовет исключение InvalidOperationException . Наконец, возвращается построенное веб-приложение.

    Это почти всё для WebApplicationBuilder , но мы ещё не выполнили обратный вызов ConfigureApplication() . В следующем посте мы рассмотрим код, лежащий в основе типа WebApplication , и увидим, где, наконец, вызывается ConfigureApplication() .

    Итого

    В этом посте мы рассмотрели часть кода нового API минимального хостинга WebApplicationBuilder . Я показал, как типы ConfigureHostBuilder и ConfigureWebHostBuilder действуют как адаптеры для универсального хоста и как BootstrapHostBuilder используется в качестве оболочки для внутреннего HostBuilder . Было довольно много запутанного кода только для создания экземпляра WebApplicationBuilder , но мы закончили статью, вызвав Build() для создания WebApplication . В следующем посте мы рассмотрим код WebApplication .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *