2018 年 9 月

第 33 卷 9

本文章是由機器翻譯。

網頁程式開發-Blazor 瀏覽器中的 C#

藉由Jonathan Miller

Blazor 是新的 Microsoft 實驗性架構,會將 C# 成任何沒有的外掛程式的瀏覽器。它會保留現代化單一頁面應用程式,結合使用 C# 和其龐大的基底類別程式庫的能力的承諾。Blazor 採用 C# 開發帶入全新境界。它是製作語言的完整堆疊的開發工具所需的最後一步。它會有熱門的 JavaScript 架構,但根據使用熟悉的語言、 Api 及工具的 Microsoft.NET framework 的所有的功能。

如果您來自傳統 Microsoft 背景,而且不熟悉 ASP.NET Web Form 或模型-檢視-控制器 (MVC),快速上手 Blazor 上其實非常簡單,相較於 mountain 時,特別是 Microsoft 開發人員必須爬來取得中的 JavaScript 架構,例如 Angular 或 React 相等的知識。

請務必了解 Blazor 執行完全在瀏覽器內。一旦編譯 Blazor 應用程式時,它會是基本上是一組檔案,取得瀏覽器中載入並執行。不同於傳統的 ASP.NET 應用程式沒有需要任何特殊的後端來處理它。Blazor 站台可提供任何平台上的網頁伺服器。與用戶端,支援 WebAssembly 標準的任何瀏覽器支援 Blazor。包含立即傳送的所有主要瀏覽器。

瀏覽器中執行時,應用程式不其實也很有用,而不需要存取外部資料和服務。就像標準的 JavaScript 單一頁面應用程式,Blazor 應用程式會存取 Web 服務使用的 HTTP REST Api。這些 Api 可以使用 Microsoft 工具,例如 Web API 或任何技術,可以呈現的 HTTP REST 端點來建立。在本文中,我示範 Blazor 應用程式的能力,可在網站上的免費的 Web 服務。

取得設定

第一個步驟取得 Blazor 安裝最新組建。撰寫本文時為 Blazor 仍不支援的實驗性架構。這表示您不應該在生產環境中使用它。Blazor 安裝是非常低影響,但您不一定要將它安裝在您的日常工作電腦。  請考慮安裝在另一部電腦或虛擬環境。主要的需求是使用 ASP.NET 和 Web 開發工作負載安裝、.NET Core SDK 和 Blazor 語言擴充功能的 Visual Studio 2017。請檢閱 blazor.net 的 「 開始 」 步驟。相當快速,逐步引導 Blazor 小組,有時候您需要特定版本的 Visual Studio 或.NET Core,使用目前的實驗版本。

建立新的 Blazor 應用程式

我要把開始建立範例 Blazor 應用程式,然後再修改它來呼叫某些 Web 服務。首先,讓我們在 Visual Studio 中建立新的 ASP.NET Core Web 應用程式。

接下來,選擇 [Blazor 應用程式,然後按一下 [確定]。如果您沒有看到 Blazor 的選擇清單中,您可能會遺失 Blazor 語言服務延伸模組。

建立預設 Blazor 應用程式遠低於空白的畫布。它包含一個基本的網站,利用 Bootstrap。有幾個範例頁面,使其能夠輕鬆地及執行,並使用 Blazor 中立即開始試用。提取資料] 索引標籤會顯示內嵌於預設應用程式的 JSON 檔案的某些虛擬的天氣資料。

這是怎麼甚至辦到?

C# 的瀏覽器中執行的概念.NET Silverlight 開發以來已經一場夢。它非常適合特定業務應用程式,但它是必要的外掛程式,和新興的 iOS 模型,並不允許瀏覽器外掛程式限制嚴格的 Silverlight 未來的事實。

讓此所有可能的魔法是稱為 WebAssembly (WASM) 的新標準。WASM 是一種二進位格式可以載入並直接在瀏覽器中執行,以及目前支援的所有主要的瀏覽器。  Mono 的團隊致力於 WASM 中執行的.NET 執行階段版本。Blazor 本身是一種架構,除此之外,Mono 執行階段會針對建立 WASM。當編譯專案時,會將它編譯為.NET 組件取得載入並執行的 Common Language Runtime (CLR) 的瀏覽器內執行。請務必了解瀏覽器中執行的.NET 程式碼在相同的 JavaScript 安全性沙箱中執行。在此問題,如需本主題的詳細資訊,請參閱 Dino Esposito 的技術最前線資料行。

取得實際的氣象預報

預測是假 načetl ze souboru,內嵌在專案中的資料。我真正的 Web 服務的實際資料以取代整個提取資料頁。首先,我需要取代簡單指提示使用者輸入郵遞區號的 HTML。內 FetchData.cshtml,我可以將 HTML 程式碼取代為下列:

<h1>Weather Forecast</h1>
<div class="input-group col-md-3">
  <input type="text" class="form-control" placeholder="Zip code"
    bind="@zip" maxlength="5" />
  <div class="input-group-append">
    <button class="btn btn-secondary" type="button"
      onclick="@GetWeather">Get Weather</button>
  </div>
</div>
<br /><span style="color:red">@errorMessage</span>

請注意 Razor 語法內嵌指令碼中。@ 符號訊號代碼和變數。輸入的標記擷取的郵遞區號,並將它繫結至變數,稱為 zip。按鈕標記具有繫結至 @GetWeather,在 C# (不是 JavaScript) 中呼叫 GetWeather 方法及其 onclick 方法。另外還有一些 @errorMessage 可用如果使用者輸入無效的 ZIP。在相同的 FetchData.cshtml @functions 區塊內定義這些變數和方法:

@functions {
  String zip = String.Empty;
  String errorMessage = String.Empty;
  private async Task GetWeather()
  {
  }
}

執行應用程式現在可讓使用者能夠輸入的郵遞區號,然後按一下 [獲知天氣] 按鈕。因此會發生任何事,是空的 GetWeather 方法。在下一步] 區段中,我將會呼叫 Web 服務,並擷取目前天氣狀況的程式碼。

儲存從 Web 服務傳回的資料

接下來,我會需要某些區域變數在我的頁面,來儲存從 Web 服務呼叫傳回的資料。Razor pages 會繫結至這些變數,因此可以顯示資料。這些變數加入至 @functions 區塊在頁面中,就像這樣:

Models.CurrentConditions currentcondition;
Models.Alert alerts;
Models.ZipLookup ziplookup;
String imgurl = "";

加入郵遞區號 Web 服務

一旦使用者按一下 [獲知天氣] 按鈕時,必須先驗證在方塊中輸入的郵遞區號。第一個公開的 Web 服務是從 zippopotam.us。Http://api.zippopotam.us/US/<zip> API URL 呼叫時,它會傳回指定的郵遞區號的相關資訊。從這個 Web 服務所需的資訊是城市與縣市的名稱。這項資料會顯示給使用者的預測,並州名縮寫將用於後續的 Web 服務呼叫。Web 服務程式碼應該看起來很熟悉,因為它會使用熟悉的 HttpClient 類別。

呼叫查閱郵遞區號 Web 服務中的指令碼**[圖 1** API 從下載的 ZIP 的程式碼資訊,並將它放入稱為 ziplookup 的本機變數。我可以在我的 Razor 程式碼中使用此變數,以顯示 [縣 (市) 名稱。這個 API 會傳回例外狀況,如果 zip 檔無效。如果發生這種情況,會顯示一則錯誤訊息。

[圖 1 取得郵遞區號資訊

try
{
  errorMessage = "";
  var zipresultStr = await Http.GetStringAsync($"http://api.zippopotam.us/US/{zip}");
  zipresultStr = zipresultStr.Replace("place name", "city").Replace(
    "state abbreviation", "stateabbr");
  ziplookup = JsonUtil.Deserialize<Models.ZipLookup>(zipresultStr);
}
catch
{
  errorMessage = "Invalid zip code";
  return;
}

還原序列化 ZIP 查閱資料在先前的程式碼片段中,我是從 Web 服務擷取資料,且它還原序列化 Models.ZipLookup 類別。這是我建立了以符合所傳回的 JSON 資料的結構描述的類別:

public class ZipLookup
{
  public Place[] places { get; set; }
}
public class Place
{
  public String city { get; set; }
  public String stateabbr { get; set; }
}

會傳回更多的資料,但我只建立了屬性和類別,我想要使用的資料。目前的實作有問題的 JSON 欄位名稱中有空格的處理。暫時的解決方法,我使用 String.Replace 移除空格。

顯示的城市和州既然已下載並還原序列化資料,我可以將它顯示在網頁中。下列程式碼區塊會在頁面中顯示的城市與縣市縮寫:

<h1>
  @ziplookup.places[0].city, @ziplookup.places[0].stateabbr<br />
</h1>

新增天氣條件 Web 服務

下一步] 的 Web 服務會擷取目前的狀況,從郵遞區號openweathermap.org Web 服務。您必須建立帳戶,才能接收呼叫 Web 服務時使用的特殊按鍵。

呼叫目前的狀況 Web 服務取得的目前狀況的呼叫運作方式很像先前的 Web 服務呼叫。這裡的例外狀況是 apikey 參數呼叫中。Openweathermap.org 服務需要驗證呼叫端的索引鍵:

currentcondition = await Http.GetJsonAsync<Models.CurrentConditions>(
  $"http://api.openweathermap.org/data/2.5/
  weather?zip={zip},us&appid=<apikey>");
imgurl = $"http://openweathermap.org/img/w/{currentcondition.weather[0].icon}.png";

目前的條件呼叫的結果會儲存在本機變數呼叫 currentcondition。結果也會將對應的圖示以顯示名稱傳遞的目前狀況。映像的名稱會編碼為 imgurl 變數中,因此不會顯示在網頁中。

目前的條件資料還原序列化同樣地,將未經處理的 JSON 資料必須還原序列化的類別,所以可使用,如中所示**[圖 2**。類別定義看起來有點奇怪,但它是設計來比對從 Web 服務所傳回的 JSON 資料的結構描述。沒有更多與這裡顯示所傳回的資料。必須實作所需的屬性。

[圖 2 未經處理的 JSON 資料還原序列化

public class CurrentConditions
{
  public CurrentConditions() { }
  public List<Weather> weather { get; set; }
  public Main main { get; set; }
  public String name { get; set; }
}
public class Weather
{
  public String main { get; set; }
  public String description { get; set; }
  public String icon { get; set; }
}
public class Main
{
  public decimal temp { get; set; }
  public decimal temp_min { get; set; }
  public decimal temp_max { get; set; }
}

轉換的溫度從 Web 服務傳回的溫度位於開氏溫度表示,因此需要轉換成華氏和捨入值。目前的溫度會四捨五入到接近的十分之一的程度。高低溫度會四捨五入到最接近的整程度。

private decimal ConvertKtoF(decimal kelvin, int decimals)
{
  return Math.Round(kelvin * 9 / 5 - 459.67M, decimals);
}

顯示目前的狀況Razor 中的指令碼**[圖 3**會現在更新,以包含目前的溫度、 高和低、 說明目前的狀況,並以對應的圖示目前的狀況。請注意如何溫度會傳遞至稍早建立的 ConvertKtoF 函式。

[圖 3 更新 Razor 指令碼

<h1>
  @ziplookup.places[0].city, @ziplookup.places[0].stateabbr<br />
  @ConvertKtoF(currentcondition.main.temp, 1) &#176;F
</h1>
<h2>
  @currentcondition.weather[0].main <img src="@imgurl" style="display:inline" />
</h2>
<h3>
  <span style="display:inline;color:red">HI
    @ConvertKtoF(currentcondition.main.temp_max, 0)  &#176;F</span> /
  <span style="color:blue">LO @ConvertKtoF(
    currentcondition.main.temp_min, 0)  &#176;F
    </span><br />
</h3>

新增 National 天氣服務警示

最終的 Web 服務會擷取從 National 天氣服務 (NWS) 的 ZIP 程式碼狀態的警示。

呼叫 NWS Web 服務下列程式碼區塊會從 NWS 來擷取所有目前的嚴峻的氣象警示:

alerts = await Http.GetJsonAsync<Models.Alert>(
  $"https://api.weather.gov/alerts/active/area/{ziplookup.places[0].stateabbr}");

從 ziplookup Web 服務擷取的州名縮寫用來篩選警示,以相同的狀態。

還原序列化 NWS 警示資料需要還原序列化成一組類別 NWS JSON 結構描述與對應的 JSON 資料。中的程式碼片段**[圖 4**保存 NWS Web 服務所傳回的警示。

[圖 4 還原序列化 JSON 資料

public class Alert
{
  public String type { get; set; }
  public String title { get; set; }
  public Feature[] features { get; set; }
}
public class Feature
{
  public String type { get; set; }
  public PropertyInfo properties { get; set; }
}
public class PropertyInfo
{
  public String headline { get; set; }
  public String description { get; set; }
  public DateTime effective { get; set; }
  public DateTime expires { get; set; }
}

顯示嚴重的天氣警示既然擷取警示中的程式碼**[圖 5**會新增至 Razor 檢視,來顯示它們。它會建立資料表以顯示警示,並使用 @foreach 循環,並顯示每個警示。生效日期、 標題和描述會顯示每個警示。如果沒有任何警示的狀態,資料表會是空的。

[圖 5 顯示天氣警示

<table class="table">
  <thead>
  <tr>
    <th>Date</th>
    <th>Alert</th>
  </tr>
  </thead>
  <tbody>
    @foreach (var alert in alerts.features)
    {
      <tr>
        <td>@alert.properties.effective.ToString("MM/dd/yyyy hh:mmt")</td>
        <td>
          <span style="font-weight:600">@alert.properties.headline</span><br />
          <span>@alert.properties.description</span>
        </td>
      </tr>
    }
  </tbody>
</table>

整體回顧

應用程式現在已完成,如中所示**[圖 6**。它會完全在瀏覽器中執行,並呼叫三個的外部 Web 服務,以顯示目前天氣狀況和警示。

完成的應用程式
[圖 6 完成的應用程式

發行 Blazor 應用程式

就像任何其他 ASP.NET 應用程式的發行一樣容易發佈 Blazor 應用程式。從 Visual Studio 執行此動作,將會編譯應用程式程式碼,並產生最終的 HTML、 CSS、 指令碼和 Blazor 二進位檔所需的所有完整的 Web 應用程式。好的起點是使用 [發佈到資料夾] 選項。所有應用程式的檔案取得放置在該處。如果您看 Dist 資料夾內,您會發現標準 index.htm 頁面和架構 (_f) 資料夾。架構 (_f) 資料夾包含所有已編譯的組件,以及 Blazor 和 Mono 執行階段元件。

後續步驟

Blazor 仍然是實驗性的 framework,但小組正在前進版本以極快速速率。Blazor 藍圖詳細說明的完整架構路由、 元件、 版面配置和更多功能。在 GitHub 上的開啟開發 Blazor 專案。請瀏覽 blazor.net 頁面,以維持最新狀態,開始體驗目前的位元。


Jonthan Miller是資深架構設計人員。他已開發了十年在 Microsoft stack 上的產品和創立以來,在.NET 程式設計。Waldman 會是完整堆疊產品開發人員具有專才的前端技術 (Windows Form、 Windows Presentation Foundation、 Silverlight、 ASP.NET、 AngularJS/啟動程序)、 中介軟體 (Windows 服務,Web API),以及後端 (SQL server、 Azure)。

感謝下列技術專家檢閱這篇文章:Dino Esposito (BaxEnergy),Daniel Roth (Microsoft)


MSDN Magazine 論壇中的這篇文章的討論