ASP.NET Core da çoklu Environment(Ortam) Konfigürasyonu ve Kullanımı
Selamlar,
Bu yazımda sizlere bir asp.net core projenizde çoklu ortam oluşturma ve bunları kullanmak hakkında bilgiler vereceğim.
Asp.Net Core uygulamanızın davranışını runtime ortamı için set etmiş olduğunuz environment variable ile belirler. Hiç set etmemiş olmanı durumunda otomatik olarak bu değer “Production” olarak kabul edilir.
Bir asp.net core uygulaması nasıl ayağa kalkar, ilk başta neler olur ve request browserdan sizin external(IIS, Apache, Nginx vs.) ve internal(Kestrel vs.) sunucularınıza gelip ne şekilde aşamalardan geçip geri browser a döner bundan bahsetmiştik. Buradan ve buradan okuyabilirsiniz. Uygulamanın startup anında Asp.Net Core, ASPNETCORE_ENVIRONMENT global variable ının değerini okur ve IHostingEnvironment.EnvironmentName propertysine set eder.
Assembly:Microsoft.AspNetCore.Hosting.Abstractions.dll
public string EnvironmentName { get; set; }
Bu değere herhangi birşey set edebilirsiniz, 3 adet değer framework ile beraber geliyor zaten. Çoğunlukla bunlar işinizi görmenize yetecektir. Bunlar aynı assembly altında bulunan
public static readonly string Development;
public static readonly string Staging;
public static readonly string Production;
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } if (env.IsProduction() || env.IsStaging() || env.IsEnvironment("Custom_Stage")) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseMvc(); }
Bir startup dosyasında yukarıdakine benzer bir kod illaki görmüşsünüzdür. Burada söylenen şey aslında şudur.
- Eğer ASPNETCORE_ENVIRONMENT global variable ın değer “Development” ise UseDeveloperExceptionPage middleware inin, request akışı sırasında ilk olarak devreye alınması. Dolayısı ile, uygulama ayağa kalktıktan sonra request öncelikle buradan geçecek ve yine en son bu middleware den geçip broweser a doğru yola çıkacak.
- Eğer environment “Production”, “Staging” yada bizim konfigürasyon dosyasında custom tanımladığımız bir “Custom_Stage” değerine eşit ise, o zaman da UseExceptionHandler middleware i request in akışı süresince devreye girecek olan ilk middleware olacak.
Uygulama akışını konfigüre etmek için environment değerlerini set edeceğimiz yer, lokal development için Properties\launchSettings.json dosyasıdır. Burada set ettiğimiz environement değerleri System Environment değerlerini ezecektir. Aşağıda bir adet launchSettings.json dosyasını inceleyelim.
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:54339/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_My_Environment": "1",
"ASPNETCORE_DETAILEDERRORS": "1",
"ASPNETCORE_ENVIRONMENT": "Staging"
}
},
"EnvironmentsSample": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Staging"
},
"applicationUrl": "http://localhost:54340/"
},
"Kestrel Staging": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_My_Environment": "1",
"ASPNETCORE_DETAILEDERRORS": "1",
"ASPNETCORE_ENVIRONMENT": "Staging"
},
"applicationUrl": "http://localhost:51997/"
}
}
}
Buradaki launchSettings dosyamızda 3 farklı profile görüyoruz. Uygulama dotnet run komutu ile ayağa kalktığında ilk profile seçilir ve uygulama ayağa kalkar.
Burada “commandName” : “Project” kısmı önemlidir. commandName;
- IISExpress
- IIS
- Project (External Server olmadan doğrudan Kestrel ayağa kalkar)
bu üç değerden biri set edilebilir.
Bu şekilde uygulamayı çalıştırdığımızda aşağıdaki gibi bir çıktı alırız.,
PS C:\Websites\EnvironmentsSample> dotnet run
Using launch settings from C:\Websites\EnvironmentsSample\Properties\launchSettings.json…
Hosting environment: Staging
Content root path: C:\Websites\EnvironmentsSample
Now listening on: http://localhost:54340
Application started. Press Ctrl+C to shut down.
Visual Studio üzerinden bu launchSettings dosyamızda verdiğimiz profile ları görüp yönetebiliriz. Projenin özelliklerine geldiğimizde Debug tabını açtığımızda, dosyamızda ki değerler burada karşımıza çıkar. Uygulamanın kullanmasını istediğimiz Profile ı buradan da değiştirebiliriz. Ama buradan yaptığımız değişikliklerin doğrudan etkili olması için en azından Kestrel restart olması şart. Restart işleminden sonra kestrel environment taki değişikliklere göre hareket etmeye başlayacaktır.
ASPNETCORE_ENVIRONMENT global environment ını daha global olarak set etmenin birden farklı platformlarda birden çok yolu var. Bunlar şöyle ;
- Windows Command Promt — (current session – uygulamayı dotnet run demeden önce, o çalışma için)
- set ASPNETCORE_ENVIRONMENT=Development
- PowerShell — (current session – uygulamayı dotnet run demen önce, o çalışma için)
- $Env:ASPNETCORE_ENVIRONMENT = “Development”
- Windows Globally Command Promt
- setx ASPNETCORE_ENVIRONMENT Development /M
- PowerShell Windows Globally
- [Environment]::SetEnvironmentVariable(“ASPNETCORE_ENVIRONMENT”, “Development”, “Machine”)
-
macOS
- Uygulamayı çalıştırma aşamasında söylemek için
- ASPNETCORE_ENVIRONMENT=Development dotnet run
- Çalıştırma öncesi
- export ASPNETCORE_ENVIRONMENT=Development
- Machine level seviyesinde set etmek için
- export ASPNETCORE_ENVIRONMENT=Development
- Uygulamayı çalıştırma aşamasında söylemek için
Environment-based Startup Class
Kullanımını çok az görmüş olsam da uygulamamızdaki startup dosyalarını da environment variable a bağlı olarak çalışabilecekleri şekilde farklı isimlerde oluşturup, ilgili environment variable altında ilgili startp class ının ve onun metodlarının devreye girmelerini sağlayabiliriz.
Startup{EnvironmentName} şeklinde farklı startup dosyaları oluşturduğumuzda frameowork otomatik olarak ayağa kalktığı andaki environmentname ile biten bir startup dosyası varsa onu çalıştıracaktır.
// Startup class to use in the Development environment public class StartupDevelopment { public void ConfigureServices(IServiceCollection services) { ... } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { ... } } // Startup class to use in the Production environment public class StartupProduction { public void ConfigureServices(IServiceCollection services) { ... } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { ... } } // Fallback Startup class // Selected if the environment doesn't match a Startup{EnvironmentName} class public class Startup { public void ConfigureServices(IServiceCollection services) { ... } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { ... } }
Bunun devreye girmesi için IWebHostBUilder tarafında UseStartup metodunun string parametre olarak assembly name alan overload unu kullanmak yeterli.
public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) { var assemblyName = typeof(Startup).GetTypeInfo().Assembly.FullName; return WebHost.CreateDefaultBuilder(args) .UseStartup(assemblyName); }
Yukarıdaki gibi her bir environment için yeni bir startup dosyası oluşturmak istemez isek, tekbir startup dosyasına, aynı mantıkla metodların isimlerinin arasına EnvironmentName adını koyarsak ayağa kalkış anındaki environment name e sahip oklan ConfigureStaging.. ve ConfigureStagingervices.. metodları çalışacaktır. Aynı isme sahip bir metod bulunamazsa default olarak Configure ve ConfigureServices metodları çalışacaktır.
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { StartupConfigureServices(services); } public void ConfigureStagingServices(IServiceCollection services) { StartupConfigureServices(services); } private void StartupConfigureServices(IServiceCollection services) { services.AddMvc() .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } if (env.IsProduction() || env.IsStaging() || env.IsEnvironment("Staging_2")) { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseMvc(); } public void ConfigureStaging(IApplicationBuilder app, IHostingEnvironment env) { if (!env.IsStaging()) { throw new Exception("Not staging."); } app.UseExceptionHandler("/Error"); app.UseStaticFiles(); app.UseMvc(); } }
Bir sonraki yazımda görüşmek üzere.