iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 11
1

ASP.NET Core 支援在不同 runtime 環境可以進行不同的行為。應用程式啟動時,會讀取 ASPNETCORE_ENVIRONMENT 環境變數來判斷執行中的環境,並將值儲存在 IHostingEnvironment.Environment 屬性中。ASPNETCORE_ENVIRONMENT 可以是任何值,但 ASP.NET Core 架構中有內建三個值:

沒有設定 ASPNETCORE_ENVIRONMENT 環境變數時,預設為 Production

Windows 和 macOS 中,環境變數與其值不區分大小寫。 Linux 環境則預設為區分大小寫

設定開發環境

Properties/launchSettings.json 檔案中,可以設定開發時使用的環境。在這個檔案中設定的值,會覆寫系統中的設定。透過 MVC 範本建立的專案,會自動產生 launchSettings.json 檔案:

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:54061",
      "sslPort": 44315
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "ironman2018": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "https://localhost:5001;http://localhost:5000"
    }
  }
}

我們可以透過修改 profile 中的 ASPNETCORE_ENVIRONMENT 值,來設定開發時使用的環境。

除了直接修改 Properties/launchSettings.json 檔案外,VS 也有提供 GUI 來編輯這個檔案。在 VS 中,「右鍵點選專案 > 屬性 > 偵錯頁籤」即可編輯。
https://ithelp.ithome.com.tw/upload/images/20181025/20107875qkpF0UaAdT.png

根據環境來切換工作

說這麼多,到底要怎麼在應用程式中根據不同環境來進行不同的工作呢?用個簡單的例子來跟大家說明。完整範例程式碼可以參考這邊

先建立一個 IEnvironmentsService 介面,包含 string GetEnvironmentName() 方法,會回傳 runtime 的環境名稱。並建立三個實作此介面的類別,分別代表 DevelopmentProductionRex 三種環境。

public interface IEnvironmentsService
{
    /// <summary>
    /// 回傳 runtime 的環境名稱
    /// </summary>
    /// <returns></returns>
    string GetEnvironmentName();
}

public class DevelopmentEnvironmentsService : IEnvironmentsService
{
    public string GetEnvironmentName()
    {
        return "Development";
    }
}

public class ProductionEnvironmentsService : IEnvironmentsService
{
    public string GetEnvironmentName()
    {
        return "Production";
    }
}

public class RexEnvironmentsService : IEnvironmentsService
{
    public string GetEnvironmentName()
    {
        return "Rex";
    }
}

接下來在 Startup.ConfigureServices 方法中,依不同的環境將對應的服務加到依賴注入的服務容器中:

public void ConfigureServices(IServiceCollection services)
{
    // ......
    // other services registration
    // ......

    if (_env.IsDevelopment())
    {
        services.AddSingleton<IEnvironmentsService, DevelopmentEnvironmentsService>();
    }

    if (_env.IsProduction())
    {
        services.AddSingleton<IEnvironmentsService, ProductionEnvironmentsService>();
    }

    // 會忽略大小寫
    if (_env.IsEnvironment("rEx"))
    {
        services.AddSingleton<IEnvironmentsService, RexEnvironmentsService>();
    }
}

IHostingEnvironment 提供四種擴充方法來判斷 runtime 的環境,分別為 IsDevelopmentIsStagingIsProductionIsEnvironment,前三個方法分別對應到 ASP.NET Core 架構中內建的三種環境類型,第四個方法則需傳入一個代表環境類型的字串,用來判斷是否符合 runtime 時的環境名稱。由於 IsEnvironment 方法在判斷時會忽略大小寫,所以建議使用這個方法而非 _env.EnvironmentName == "rEx"。另外也可以透過 tag helper 來判斷 runtime 環境。

再來建立 EnviromentsController,同時加入 Index Action:

public class EnviromentsController : Controller
{
    private readonly IEnvironmentsService _environmentsService;

    public EnviromentsController(IEnvironmentsService environmentsService)
    {
        _environmentsService = environmentsService;
    }

    public IActionResult Index()
    {
        ViewBag.EnvironmentName = _environmentsService.GetEnvironmentName();

        return View();
    }
}

最後,建立 EnviromentsController/Index.cshtml,對應到 Controller/Action 的 View

@{
    ViewData["Title"] = "Environments Example";
}

<h2>Environments Example</h2>

<hr/>

<h3>Injection in ConfigureServices</h3>
<p>Runtime Environment Name: @ViewBag.EnvironmentName</p>

<hr/>

<h3>Tag Helper</h3>
<environment include="Development">
    Dev<br/>
</environment>
<environment include="Production">
    Prod<br />
</environment>
<environment exclude="Rex">
    Not from Rex<br />
</environment>

因為預設的 ASPNETCORE_ENVIRONMENT 環境變數值是 Development,瀏覽器上顯示的畫面會是這樣:
https://ithelp.ithome.com.tw/upload/images/20181025/20107875eqzwMZh1Q0.png

根據環境來提供 Startup 類別和方法

除了在程式邏輯中判斷環境以外,也可以定義符合環境類型的 Startup 類別和方法,讓應用程式來判斷執行時的使用對象。

建立代表環境類型的 Startup{EnvironmentName} 類別,並修改 Main 方法中的 CreateWebHostBuilder 方法,就可以讓應用程式抓到對應的類別。

  • Main 方法
public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    // 原本是這樣
    //        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    //            WebHost.CreateDefaultBuilder(args)
    //                .UseStartup<Startup>();

    // 改成這樣來讓應用程式找到對應環境的 Startup 類別
    public static IWebHostBuilder CreateWebHostBuilder(string[] args)
    {
        var startupAssemblyName = typeof(Startup).GetTypeInfo().Assembly.FullName;

        return WebHost.CreateDefaultBuilder(args)
            .UseStartup(startupAssemblyName);
    }
}
  • StartupDevelopment.cs
public class StartupDevelopment
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IEnvironmentsService, DevelopmentEnvironmentsService>();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Enviroments}/{action=StartupClassConvention}/{id?}");
        });
    }
}

或者可以在原本的 Startup 類別中建立 Configure{EnvironmentName}Configure{EnvironmentName}Services 方法,也可以讓應用程式在啟動時呼叫對應的方法。

public void ConfigureProduction(IApplicationBuilder app)
{
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Enviroments}/{action=StartupConfigureMethodConvention}/{id?}");
    });
}

參考資料


上一篇
Static Files 靜態檔案
下一篇
Configuration 組態設定 - 1/2
系列文
.Net Core 網站開發 10131
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言