《進擊吧!Blazor!》系列入門教程 第一章 8.部署

MicrosoftReactor發表於2021-04-10

《進擊吧!Blazor!》是本人與張善友老師合作的Blazor零基礎入門教程視訊,此教程能讓一個從未接觸過Blazor的程式設計師掌握開發Blazor應用的能力。
視訊地址:https://space.bilibili.com/483888821/channel/detail?cid=151273
Blazor WebAssembly 是單頁應用 (SPA) 框架,用於使用 .NET 生成互動式客戶端 Web 應用,採用 C# 代替 JavaScript 來編寫前端程式碼
本系列文章基於《進擊吧!Blazor!》編寫,但因篇幅有限,省略了部分程式碼,完整示例程式碼:https://github.com/TimChen44/Blazor-ToDo

作者:陳超超
Ant Design Blazor 專案貢獻者,擁有十多年從業經驗,長期基於.Net技術棧進行架構與開發產品的工作,現就職於正泰集團。
郵箱:timchen@live.com
歡迎各位讀者有任何問題聯絡我,我們共同進步。

部署是開發的最後一部,我們這次就來聊聊Blazor的部署方法。

釋出

VS已經為我們預製了多個目標的釋出工具,使用這些工具可以很容易的完成釋出和部署。

1.首先在ToDo.Server專案上右鍵,選擇釋出...功能
在這裡插入圖片描述

2.接著選擇要釋出的目標,常用的環境都支援,我們就以Azure為例
在這裡插入圖片描述
3.根據目標不同填寫一些配置,VS也會幫我們儲存配置資訊便於下次使用。
在這裡插入圖片描述
4.配置一些依賴,比如本例中需要配置資料庫,最後點選”釋出“按鈕,接著喝杯茶等待一下。
在這裡插入圖片描述
5.經過VS後臺的一頓操作,釋出完成,並且會自動開啟發布的站點,效果如下
在這裡插入圖片描述
到這裡,這篇文章結束了,各位再見!?

這個?,我們本著“搞事情”的精神,"沒有困難製造困難"的理念來重構我們的釋出,各位走起~~~~

首先可以確定上面VS為我們提供的釋出工具確實非常方便,比較適合小團隊開發一些小規模的系統,但是通常企業中使用會遇到以下的問題

  • 負責釋出的運維工程師與負責編碼的開發工程師不是同一撥人,不可能讓運維工程師用VS開著原始碼進行釋出,程式碼安全,生產環境安全雙雙無法保證。
  • 自動化的IC/CD普及度的增加,生成和釋出過程挪到了各DevOps平臺,所以也不適合在VS中操作。

廣告時間:推薦大家嘗試一下微軟的Azure DevOps,支援本地部署,支援所有語言,預製各平臺釋出流程等等,配置一個專案的IC/CD過程猶如前面的操作一樣,滑鼠點點就完事,懶人的福音。

綜上述,我們可以採用比較靈活的的做法,先將專案釋出成檔案,然後將這些檔案部署到不同的環境中。這也符合自動化的IC/CD的常規流程,先整合再部署。

如果使用Docker,可以在IC時直接Build出Image,也可以在CD時Build出Image,我覺得沒有標準,適合自己就行。

釋出到資料夾

那麼我們繼續使用VS的釋出工具將專案打包

1.選擇釋出到資料夾選項,並設定輸出位置
在這裡插入圖片描述
2.點選發布完成編譯並輸出。
在這裡插入圖片描述
3.點選上面的”鉛筆“圖示可以進行詳細配置
在這裡插入圖片描述
目標框架 設定使用那個.net框架進行編譯
部署模式 它分為框架依賴獨立兩個選共享
框架依賴 模式下生成的檔案需要.net執行時才能執行,優點體積較小,程式本省不依賴目標執行時,方便移植
獨立 模式下編譯器會把.net執行時與程式打包在一起,執行平臺無需.net執行時,缺點是體積較大,編譯的程式依賴於目標執行時
目標執行時 選擇針對那個平臺編譯,可以是win、linux、osx系統,以及x64、x86、arm指令集
生成單個檔案 勾選後可以把程式打包在一個檔案中,執行的時候程式會自動解包並執行
裁剪未使用的程式集 將一些專案中引用但是程式碼中並未使用的程式集剔除以減少程式包的體積

我們的示例程式使用配置 部署模式依賴框架目標執行時可移植

如果編譯過程使用自動化工具進行打包,除了打包命令中額外增加引數外,我們也可以在.csproj檔案中做以下配置來實現上面的引數

<PropertyGroup>
	<PublishSingleFile>True</PublishSingleFile><!-- 生成單個檔案  -->
	<PublishTrimmed>True</PublishTrimmed><!-- 裁剪未使用的程式集  -->
	<SelfContained>true</SelfContained><!-- 框架依賴:獨立  -->
	<RuntimeIdentifier>win-x86</RuntimeIdentifier><!-- 目標執行時  -->
</PropertyGroup>

4.程式以檔案形式輸出在我們給定的路徑

部署

使用 ASP.NET Core 進行託管部署

如果使用ASP.NET Core的Kestrel Web 伺服器託管程式,我們只需執行我們上面釋出輸出的ToDo.Server.exe檔案即可
在這裡插入圖片描述
到這裡有個小問題,就是我們不想使用預設的5000和5001埠,這個我們就需要人為的給定埠。

修改ToDo.ServerProgram.cs檔案

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder
            .UseUrls("http://*:4000", "https://*:4001")
            .UseStartup<Startup>();
        });

我們使用.UseUrls來給定Url地址,這裡*代表適配所有IP或域名,埠分別設定為40004001

這裡又冒出一個小問題,目前埠硬編碼在程式中,釋出後無法修改,遇到這個問題,我們可以通過啟動引數、配置檔案等多個方法實現釋出後修改,在這裡我貼上通過啟動引數修改埠的程式碼。

public static IHostBuilder CreateHostBuilder(string[] args)
{
    var configuration = new ConfigurationBuilder().AddCommandLine(args).Build();
    return Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder
            .UseUrls($"http://*:{configuration["httpport"] ?? "5000"}", $"https://*:{configuration["httpsport"] ?? "5001"}")
            .UseStartup<Startup>();
        });
}

啟動的時候附上對應引數實現修改埠的目的。
在這裡插入圖片描述

使用 IIS 進行託管部署

我們也可以使用IIS來託管部署我們的程式。

  1. 需要在部署的伺服器上安裝ASP.NET Core Hosting Bundle,這個可以讓IIS支援.Net Core應用。下載地址:https://dotnet.microsoft.com/download/dotnet/5.0

  2. 新增名為ToDo的站點,選擇釋出的檔案所在目錄,配置埠等
    在這裡插入圖片描述

  3. 將應用程式池ToDoNET CLR版本設定為無託管程式碼
    在這裡插入圖片描述

  4. 啟動站點就能看到自己部署的程式了。
    在這裡插入圖片描述

與ASP.Net Core的區別

看到這裡,各位覺得Blazor和ASP.Net Core在部署上有什麼區別嗎?答案是:沒區別?。

前後端分開部署

當遇到規模不小的專案時,我們會考慮到效能、安全等因素時,可能會選擇前後端分別部署在不同的伺服器上,這時我們只需要新建一個空專案,然後引用Blazor專案即可,操作如下

  1. 新增名為ToDo.BlazorHost的ASP.NET Core空專案
    在這裡插入圖片描述

  2. 引用ToDo.Client專案

  3. 安裝Microsoft.AspNetCore.Components.WebAssembly.Server

  4. 修改launchSettings.json檔案,配置應用埠預設為4000

    "iisExpress": {
      "applicationUrl": "http://localhost:4000",
      "sslPort": 0
    }
  1. 修改Startup.cs檔案,讓專案支援Blazor應用
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseBlazorFrameworkFiles();//配置應用程式從根“/”提供Blazor框架檔案
    app.UseStaticFiles();//提供靜態檔案支援
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapFallbackToFile("index.html");//配置預設路由地址
    });
}
  1. 修改ToDo.Client專案Program.cs檔案,設定HttpClient預設請求地址為ToDo.Server專案的地址
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri($"http://localhost:5000") });
  1. 修改ToDo.Server專案launchSettings.json檔案,配置IIS Express除錯埠預設為5000
      "iisExpress": {
        "applicationUrl": "http://localhost:5000",
        "sslPort": 0
      }
  1. 修改Startup.cs檔案,新增跨域支援,此處為了演示方便,我開啟了所有跨域設定
app.UseCors(config => config.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials().WithOrigins("http://localhost:4000"));
  1. 刪除ToDo.ServerToDo.Client的引用,以及Blazor相關的設定,ToDo.Server作為一個存粹的WebAPI站點存在。

  2. 為了驗證前端請求的資料是那個服務返回,我們做一個反饋伺服器地址的介面給前端呼叫。

修改AuthController.cs檔案

[HttpGet]
public string GetHost()
{
    return HttpContext.Request.Host.ToString();
}

修改Login.razor檔案

<p>前端地址:<span>@ClientHost</span></p>
<p>API服務地址:<span>@ServerHost</span></p>
string ClientHost;
string ServerHost;
protected override async Task OnInitializedAsync()
{

    ClientHost = WebAssemblyHostBuilder.CreateDefault().HostEnvironment.BaseAddress;
    ServerHost = await Http.GetStringAsync($"api/Auth/GetHost");
    await base.OnInitializedAsync();
}

同時啟動ToDo.ServerToDo.BlazorHost專案的除錯,看到以下效果
在這裡插入圖片描述

閘道器部署

當使用者多了,獲作為關鍵服務時,單點部署就有點不合時宜了,這時需要高可用,負載均衡等需求,因此我們就要拿出我們的閘道器,把他放在最前面,負責請求分發。

  1. 新增名為ToDo.BlazorHost的ASP.NET Core空專案作為閘道器ToDo.Gateway

  2. 新增Ocelot元件,Ocelot是一個用.NET Core實現並且開源的API閘道器,它功能強大,包括了:路由、請求聚合、服務發現、認證、鑑權、限流熔斷、並內建了負載均衡器與Service Fabric、Butterfly Tracing整合。

在這裡插入圖片描述

  1. 修改launchSettings.json檔案,將訪問埠改成5500
    "iisExpress": {
      "applicationUrl": "http://localhost:5500",
      "sslPort": 0
    }
  1. 新增Ocelot.json檔案,配置我們閘道器的策略
{
  "Routes": [
    {
      // - 上游服務配置
      "UpstreamPathTemplate": "/api/{url}",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ],

      // - 下游服務配置
      "DownstreamPathTemplate": "/api/{url}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5000
        }
      ],

      // - LoadBalancer將決定負載均衡的演算法,三種取值
      // RoundRobin:輪流傳送
      // LeastConnection:將請求發往最空閒的那個伺服器
      // NoLoadBalance:總是發往第一個請求或者是服務發現
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      }
    },
    {
      // - 上游服務配置
      "UpstreamPathTemplate": "/{url}",
      "UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ],

      // - 下游服務配置
      "DownstreamPathTemplate": "/{url}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5100
        }
      ],

      // - LoadBalancer將決定負載均衡的演算法,三種取值
      // RoundRobin:輪流傳送
      // LeastConnection:將請求發往最空閒的那個伺服器
      // NoLoadBalance:總是發往第一個請求或者是服務發現
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      }
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "https://api.mybusiness.com"
  }
}

上面Ocelot.json檔案中註釋只是為了介紹常用屬性,實際使用中json檔案中不能包含註釋,否則會造成解析失敗,切記。

  1. 修改Program.cs檔案,新增載入Ocelot.json檔案的程式碼
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureAppConfiguration((hostContext, config) =>
            {
                config.AddJsonFile("Ocelot.json");
            })
            .UseStartup<Startup>();
        });
  1. 修改Startup.cs檔案,新增Ocelot服務
public void ConfigureServices(IServiceCollection services)
{
    services.AddOcelot();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseOcelot();
}
  1. 修改ToDo.Client專案的Program.cs檔案,配置HttpClient預設地址為閘道器地址
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri($"http://localhost:5500") });
  1. 修改ToDo.Server專案的Startup.cs檔案,追加跨域請求地址“http://localhost:5500
app.UseCors(config => config.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials().WithOrigins("http://localhost:4000", "http://localhost:5500"));

同時除錯ToDo.BlazorHostToDo.GatewayToDo.Server三個專案,開啟地址http://localhost:5500
我們看到前端地址是localhost:5500,請求的地址也是localhost:5500,但是為我們返回資料的API服務地址是localhost:5000,說明閘道器已經幫我做了轉發。
在這裡插入圖片描述

最後

感謝有讀者能看到這裡,這是本人第一次寫專欄,文章可能會存在一些瑕疵,我會在將來盡力改進。

《進擊吧!Blazor!》系列入門教程 第一章到這裡就結束了,後續我會繼續為大家帶來與.Net和Blazor有關的原創文章,文章內容爭取做到易讀、高質量。

謝謝大家!

相關文章