我創(chuàng)建了一個(gè)ASP.NETCoreWebAPI項(xiàng)目而不是ASP.NETCoreWebApp項(xiàng)目,因?yàn)槲艺趯?shí)現(xiàn)一個(gè)API,而不是Web應(yīng)用程序。但是,我的API包含用于管理和測試API函數(shù)的默認(rèn)頁面,并且為了渲染這些頁面和.js文件,我最終實(shí)現(xiàn)了一個(gè)控制器來返回.html和.js文件,這非常錯(cuò)誤的方法。
在這篇簡短的文章中,我將指導(dǎo)您如何創(chuàng)建一個(gè)ASP.NETCoreWebAPI項(xiàng)目,該項(xiàng)目還包括瀏覽器請求的呈現(xiàn)文件。這有一些細(xì)微差別!
為什么不使用Swagger?
Swagger非常適合生成用于測試端點(diǎn)的UI。本文的要點(diǎn)是,它說明了如何在需要以下內(nèi)容的情況下添加網(wǎng)頁:a)更易于使用且b)更復(fù)雜(例如與多個(gè)端點(diǎn)交互的管理頁面)。
那為什么不使用ASP.NETCoreWebApp呢?
因?yàn)橛袝r(shí)候您不需要Razor項(xiàng)目(VS2019中的一個(gè)選項(xiàng)),也不需要Model-View-Controller項(xiàng)目(VS2019中的另一個(gè)選項(xiàng)),并且您當(dāng)然不需要Blazor(VS2019中的另一個(gè)選項(xiàng))。您只需要具有一些內(nèi)置頁面的API,這些API的功能比Swagger還要多,但是由于您正在編寫的API,因此不需要Razor,Blazor或MVC。(就個(gè)人而言,無論多么復(fù)雜,我都不認(rèn)為應(yīng)該使用這三個(gè)選項(xiàng)之一來“要求”使用網(wǎng)絡(luò)應(yīng)用程序,但這就是我。)
因此,您已經(jīng)創(chuàng)建了一個(gè)WebAPI項(xiàng)目:
并且您擁有出色的控制器:
[ApiController] [Route("[controller]")] public class SpiffyController : ControllerBase { [HttpGet] public object Get() { return Content("<b>Hello World</b>", "text/html"); } }12345678910復(fù)制代碼類型:[html]
然后,按照以下出色的StackOverflow文章:
你這兩行添加到Startup.cs的Configure方法:
app.UseDefaultFiles(); app.UseStaticFiles();12復(fù)制代碼類型:[html]
UseDefaultFiles:設(shè)置默認(rèn)頁面為訪問者提供了網(wǎng)站的起點(diǎn)。要從wwwroot提供默認(rèn)頁面而不提供完全限定的URI,請調(diào)用UseDefaultFiles方法-服務(wù)默認(rèn)文檔
UseStaticFiles:靜態(tài)文件存儲(chǔ)在項(xiàng)目的Web根目錄中。默認(rèn)目錄為{contentroot}/wwwroot-ASP.NETCore中的靜態(tài)文件
創(chuàng)建文件夾wwwroot并放入index.html其中(以及您想要在頂層進(jìn)行的其他操作):
我的index.html文件看起來像這樣的這篇文章:
<!DOCTYPE html><html lang="en"><head> <meta charset="utf-8" /> <title>TypeScript HTML App</title></head><body> <div> <button id="btnHi">Say hello</button> <div id="response"></div> <button id="btnGoodbye">Goodbye</button> </div></body></html>123456789101112131415復(fù)制代碼類型:[html]
和goodbye.html看起來像這樣:
<!DOCTYPE html><html><head> <meta charset="utf-8" /> <title></title></head><body> <h2>Goodbye!</h2></body></html>12345678910復(fù)制代碼類型:[html]
至此,運(yùn)行項(xiàng)目,我們看到:
和:
太酷了,我們已經(jīng)渲染了index.html。
然后,您創(chuàng)建一個(gè)Scripts文件夾并添加一個(gè)TypeScript文件(請注意,我將該文件夾直接放在項(xiàng)目下):
這會(huì)給您以下消息:
因此,您必須將ECMAScript版本設(shè)置為至少2017年:
我不希望我的.js文件進(jìn)入同一Scripts文件夾,我只希望它們位于wwwroot/js下:
因此,我轉(zhuǎn)到項(xiàng)目屬性并重定向Typescript編譯器輸出:
我看到那行得通:
但是index.html不知道如何加載將從TypeScript文件編譯的.js文件。因此,我們將以下行添加到index.html:
<script src="/js/app.js"></script>1復(fù)制代碼類型:[html]
現(xiàn)在,我的演示腳本文件如下所示:
window.onload = () => { new App().init(); }; class App { public init() { document.getElementById("btnHi").onclick = () => this.Hi(); document.getElementById("btnGoodbye").onclick = () => window.open('goodbye.html', '_self'); } private Hi(): void { XhrService.get(`${window.location.origin}/Spiffy`) .then(xhr => { document.getElementById("response").innerHTML = xhr.responseText; }); } } class XhrService { public static async get(url: string, ): Promise<XMLHttpRequest> { const xhr = new XMLHttpRequest(); return new Promise((resolve, reject) => { xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr); } else { reject(xhr); } } }; xhr.open("GET", url, true); xhr.setRequestHeader("Content-Type", "application/json"); xhr.send(); }); } }12345678910111213141516171819202122232425262728293031323334353637383940復(fù)制代碼類型:[html]
現(xiàn)在單擊按鈕,我們看到:
和:
開發(fā)人員將RequireJS描述為“JavaScript文件和模塊加載器”。RequireJS加載普通的JavaScript文件以及更多定義的模塊。它針對瀏覽器內(nèi)使用進(jìn)行了優(yōu)化,包括在WebWorker中使用,但可以在其他JavaScript環(huán)境(例如Rhino和Node)中使用。它實(shí)現(xiàn)了異步模塊API。使用像RequireJS這樣的模塊化腳本加載器將提高代碼的速度和質(zhì)量。另一方面,Webpack被詳細(xì)描述為“JavaScript和朋友的捆綁程序”。-要求vs.webpack
上面是一個(gè)簡單的示例,但是如果我的TypeScript類位于單獨(dú)的文件中怎么辦?我傾向于使用require而不是像Webpack這樣的捆綁程序,如果出于其他原因(我認(rèn)為)更容易配置(我認(rèn)為),我已經(jīng)習(xí)慣了。
不要這樣做!您會(huì)得到各種不需要的東西。改為執(zhí)行此操作:
npminstall--save@types/requirejs
只需安裝d.ts文件即可:
AppConfig.ts在“腳本”文件夾中創(chuàng)建一個(gè)文件:
import { App } from "./App" require(['App'], () => { const appMain = new App(); appMain.run(); } );12345678復(fù)制代碼類型:[html]
并重構(gòu)app.ts為兩個(gè)文件:
App.ts:
import { XhrService } from "./XhrService"; export class App { public run() { document.getElementById("btnHi").onclick = () => this.Hi(); document.getElementById("btnGoodbye").onclick = () => window.open('goodbye.html', '_self'); } private Hi(): void { XhrService.get(`${window.location.origin}/Spiffy`) .then(xhr => { document.getElementById("response").innerHTML = xhr.responseText; }); } }123456789101112131415復(fù)制代碼類型:[html]
XhrService.ts
export class XhrService { public static async get(url: string,): Promise<XMLHttpRequest> { const xhr = new XMLHttpRequest(); return new Promise((resolve, reject) => { xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr); } else { reject(xhr); } } }; xhr.open("GET", url, true); xhr.setRequestHeader("Content-Type", "application/json"); xhr.send(); }); } }12345678910111213141516171819202122復(fù)制代碼類型:[html]
運(yùn)行WebAPI項(xiàng)目,使用啟動(dòng)瀏覽器的項(xiàng)目Debug屬性選項(xiàng)作為控制器名稱:
它將到達(dá)API端點(diǎn),或者什么都沒有:
將index.html使用中實(shí)現(xiàn)的功能進(jìn)行渲染App.ts。
現(xiàn)在,完整的項(xiàng)目目錄如下所示:
可以在VisualStudio中調(diào)試TypeScript文件:
不幸的是,由于TypeScript.ts文件位于Scripts文件夾中,而不是wwwrooot/jsChrome文件夾中,當(dāng)您嘗試設(shè)置斷點(diǎn)時(shí)會(huì)顯示以下錯(cuò)誤:
我們可以通過在以下行添加此行來解決此問題Startup.cs:
app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider( Path.Combine(env.ContentRootPath, "Scripts")), RequestPath = "/Scripts" });123456復(fù)制代碼類型:[html]
現(xiàn)在,Chrome可以找到.ts文件,您可以在Chrome控制臺(tái)中進(jìn)行調(diào)試:
現(xiàn)在,我們有一個(gè)可行的示例:
將TypeScript添加到ASP.NETCoreWebApp項(xiàng)目中。
通過添加require,我們可以引用TypeScript文件,而無需使用捆綁程序。
提供默認(rèn)文件,例如index.js
將TypeScript.ts文件與已編譯的.js文件分開。
幫助Chrome的調(diào)試器查找.ts文件。
現(xiàn)在,我可以修復(fù)介紹中提到的gloriosky項(xiàng)目!
聯(lián)系客服