目錄
介紹
這是由兩部分組成的文章系列的第二部分,也是最後一部分。
您可以從以下網站閱讀第一部分:.NET Core Web API:您需要了解的最少知識(第1部分,共2部分)
在本文中,我們將介紹:
- 創建用於向WeatherForecastController提交Post的基本HTML頁面
- 更改dotnet Web API以返回靜態頁面(服務HTML)。
- 基本的JavaScript,它將包含創建XmlHttpRequest(XHR)的代碼
- 配置XHR以在正文和適當的標頭(header)中發佈數據。
在第一篇文章中
在第一篇文章中,我們創建了基本的Web API模板項目,並學習瞭如何使用PostMan ^將其post到該項目。
現在,我們將在此學到的所有知識應用到創建一個可以將JSON post到我們的Web API的網頁上。
讓我們直接進入並創建我們的HTML頁面,該頁面將用於post到我們的Web控制器。
添加SubFolder和index.htm
我要做的第一件事是將一個新的子文件夾添加到名爲wwwroot的項目中。我要添加該文件夾名稱,因爲它是我可以在其中部署Web API的託管網站上將文件部署到的文件夾的名稱。
您還將看到dotnet運行的默認服務器將自動了解wwwroot並直接從該目錄提供index.htm文件。
接下來,我添加一個名爲index.htm的新文件,並添加基本HTML,它將爲我們提供一個按鈕,我們可以單擊該按鈕以將帖子提交到Web API。
這是整個HTML文件。非常簡單,請記住,整個示例都使用普通JavaScript(不需要外部JavaScript庫),因此所有代碼都非常簡單。
<!DOCTYPE html>
<html lang="en">
<head>
<title>XHR Poster</title>
<meta charset="utf-8">
<script src="main.js"></script>
<style>
body{padding: 5px 15px 5px 15px;}
</style>
</head>
<body>
<label for="tempC">Temp (C)</label>
<input id="tempC" type="number" value="20">
<button onclick="postData()">Post TempC</button><br>
<label for="tempF">Temp (F)</label>
<input id="tempF" type="text">
</body>
</html>
該頁面在瀏覽器中呈現以下內容。
HTML的四個要點
由於它是不言自明的,因此我不會解釋所有的HTML,但我將指出四點要注意的事項:
- 頂部加載的main.js包含我們所有提供所需功能的JavaScript代碼
- 有一個number輸入,允許用戶設置發佈到Web API的
TempC
值(以攝氏度表示值) - 文本輸入顯示Web API返回的
TemperatureF
輸出值(以華氏表示) - 通過單擊調用在main.js中找到的JavaScript方法postData()的按鈕來觸發頁面的功能。
如果您要繼續,請立即將main.js文件添加到/ wwwroot文件夾。這是我的Visual Studio Code(VSC)IDE(集成開發環境)中所有文件的外觀快照。
如果仔細觀察,您會發現/wwwroot目錄包含兩個文件(index.htm和main.js)。
dotnet run:啓動您的Web服務器
讓我們運行dotnet,以便它再次編譯Web API併爲我們啓動Web服務器,以便我們嘗試將其提供給index.htm文件。這會導致錯誤,但會有所啓發。
要啓動Web API,請進入您的控制檯窗口(所有這些都在本系列的第1部分中進行了詳細介紹),然後輸入以下命令:
$>dotnet run
這樣做時,服務器將在默認主機和端口(localhost:5001)上啓動,因此我們可以嘗試加載index.htm。
客戶端代碼和服務器代碼(Web API)
請記住,現在我們的項目包含客戶端代碼(index.htm和main.js)和服務器代碼(用C#編寫)。但是,dotnet引擎基本上會忽略我們的HTML和JavaScript。它知道不需要編譯該代碼,而只需要使用找到的C#代碼即可。但是dotnet要做的另一件事是爲您啓動一個不錯的Web服務器。
嘗試加載index.htm
試試這個URL,看看是否加載了index.htm: https://localhost:5001/index.htm
這就是您所看到的。這是一個完全空白的頁面。
您的第一個想法可能是您需要更改URL以包括以下子目錄/wwwroot,如https://localhost:5001/wwwroot/index.htm
我想也許是我嘗試解決此問題時遇到的問題。
您可能還認爲其中至少有一些框架HTML,但我向您保證沒有。當您點擊該URL(Web API不存在)時,服務器將不響應。
如果您是第一次嘗試,可能會造成混淆,因爲您可能認爲其他問題。搜索也是一個非常困難的問題,因爲沒有錯誤值或錯誤消息。
問題在於Web API未設置爲提供靜態網頁,例如index.htm。讓我們改變它。
更改Web API以服務靜態頁面
默認情況下,Web API項目將不會提供靜態頁面,例如index.htm。這可能很有意義,因爲這是我們正在創建的Web API。但是,如果您希望能夠測試Web API而不遇到CORS(跨原始資源共享)的各種麻煩,那麼很高興知道如何更改Web API,這非常容易。
更改Startup.cs
爲此,我們只需要打開Startup.cs並添加一個新服務即可開始在dotnet應用程序上運行。
當您打開Startup.cs並查看Configure()方法的內部時,您將看到已經加載了許多服務。在更改代碼之前,它將類似於以下內容:
// 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.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
您可以看到項目模板已經添加了許多服務,可以開始在app對象上運行。這些服務提供某些功能,例如路由(UseRouting())和HttpsRedirection()等。
我們只需要添加一行代碼即可添加靜態頁面服務。
讓我們在具有以下內容的當前行之後添加一行:
app.UseAuthorization();
我們的新代碼行將是:
app.UseStaticFiles();
在VSC中看起來像這樣:
進行更改後,返回控制檯並停止Web API(CTRL-C),然後通過 $> dotnet run重新啓動。
現在,我們可以再次嘗試該URL,然後該頁面將正確投放:
https://localhost:5001/index.htm^
這樣更好
現在,我們開始嘗試一些JavaScript代碼。但是現在我們需要使用XmlHttpRequest(XHR)來使JavaScript正確無誤。我們將在main.js文件中完成所有這些工作。
在JavaScript中配置XHR
我們需要做四件事:
- 實例化內置的(JavaScript/Browser提供的XHR對象)
- 在異步請求完成時將事件偵聽器添加到XHR對象(加載事件)
- 將事件偵聽器添加到XHR對象,如果發生錯誤它將運行
- 添加一個變量來保存我們將發佈到的URL
這是我放在main.js頂部的四行代碼
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", transferComplete);
xhr.addEventListener("error", transferFailed);
var url = "http://localhost:5001/WeatherForecast/"
當XHR對象load事件發生時,它將調用一個名爲transferComplete()方法,該方法將在JavaScript代碼中進一步定義。
如果發生XHR對象error事件,則它將調用一個名爲transferFailed()方法,該方法將在我們的JavaScript代碼中進一步定義。
用戶通過單擊按鈕開始該過程
稍後我將向您展示這兩種方法,但首先讓我們看一下用戶單擊[TempC]按鈕時觸發的代碼。
請記住,我們在HTML中連接了按鈕,以便οnclick="postData()"。該方法在我們的main.js JavaScript中定義。
這是VSC中帶有行號的整個方法,因此我們可以討論正在發生的事情。
PostData()方法:逐行
由於我們已經實例化了xhr對象並設置了url,因此我們現在只需要調用xhr對象的open()方法。
我們爲open()方法提供了兩個參數。
- HTTP操作(Get)作爲字符串
- 我們發佈到的URL
yyyy-mm-dd日期格式
在第8行,我們設置一個局部變量來容納日期string。請注意,此日期的格式爲yyyy-mm-dd。
如果使用其他格式,則Web API可能無法在服務器端將字符串轉換爲日期,並且可能會失敗。
第9行
我們調用瀏覽器方法document.querySelector()以獲取對數字輸入控件的引用並獲取其當前值。這樣,用戶可以動態更改值以將不同的值提交到Web API。我們將當前值存儲在局部變量中以備後用。
第10行只是瀏覽器控制檯的console.log(),因此我們可以看到發生了什麼。
第11行:JSON對象
在第11行,我們創建了一個名爲weather的新變量,並使用JSON值對其進行了初始化。JSON中的每個名稱都將成爲本地weather對象的屬性。我這樣做是因爲它使將JSON發佈到Web API變得容易得多。當然,weather
對象中的每個屬性名稱都與我們的WeatherForecast
域對象中的屬性名稱匹配(在Web API中的C#中定義-有關更多信息,請參見本文的第1部分)。
第12行:將值明確轉換爲數字
在第12行中,我將一個新屬性TemperatureC添加到已經創建的天氣對象中。JavaScript是一種動態語言,並允許對其對象進行這種類型的操作。只需在對象上引用新屬性並將其設置爲值,就可以動態添加新屬性。我添加此屬性名稱(TemperatureC),因爲這是Web API端域對象上的預期名稱。
請注意,我還明確地將局部變量tempC值(它是一個字符串)轉換爲JavaScript Number類型(它是Double-數字高精度)。那是因爲我發現,由於Web API期望這樣Int32做TemperatureC,因此如果將值作爲字符串輸入(似乎沒有Int32從JSON對象的字符串自動轉換爲)似乎失敗了。
第13行是另一個console.log()僅用於檢查Date屬性的格式的行。
設置請求頭
在第14行上,我們必須在XHR對象上設置Content-Type請求標頭,否則Web API將失敗並出現415錯誤,就像我們使用PostMan發佈到URL一樣(請參見第1部分)。
XHR發送
最後,在第15行,我們調用XHR send()方法,該方法實際上將發佈到Web API URL。
但是,我們要發佈表示天氣對象的JSON字符串,然後調用內置的瀏覽器方法JSON.stringify(),該方法將天氣對象轉換爲適當的JSON字符串。
但是,這只是使Web API WeatherForecastController默認Post方法啓動的請求。當請求完成並且我們的JavaScript代碼被警告加載事件已觸發時,我們需要做一些工作。這就是我們前面綁定的事件處理程序起作用的地方。
TransferCompleted()逐行
這transferCompleted()是我們定義的極其簡單的方法,並在XHR對象的load事件觸發時運行。
前兩行僅輸出到瀏覽器控制檯,因此我們可以看到Web API返回的內容。現在,我們使用Web API 的默認Post()方法返回華氏溫度,該溫度代表我們發佈到該方法的攝氏溫度(更多信息,請參見第1部分)。
XHR響應屬性
xhr對象的response屬性包含Web API返回的數據。在我們的例子中,這只是代表華氏溫度的整數值。通常,您將返回一個完整的JSON對象,該對象表示比這還複雜的東西,但是對於我們的測試,我們只返回整數值。
在第21行,我們僅使用document.querySelector()
方法來獲取對tempF
文本控件的引用,並將其值設置爲Web API返回的值(xhr.response)。
過程概述
現在,當用戶在數字控件中選擇一個值並單擊按鈕時,將調用Web API,並返回相關的華氏溫度並將其顯示在tempF
文本框中。
這一切都可以,因爲我們使用以下命令正確設置了XHR對象:
- 正確的網址
- 正確的Content-Type標頭
- 正確的JSON(代表WeatherForecast領域對象)
如果您發現其中任何一個不正確,都會在瀏覽器控制檯中看到一個非常基本的錯誤,讓您知道出了點問題。