今天咱們來實現一個特殊的需求,這個需求說來也不過度,不過有點違背WebAPi的真實用途,WebAPi不過是做爲傳輸數據而用,若非在項目開發中斷不可想到還要實現一個頁面來實時顯示列表並進行後續其餘操做。接下來咱們來看看。javascript
當咱們創建一個應用程序時能夠選擇是否創建WebAPi項目,咱們選擇創建WebAPi,同時在其根目錄下創建一個Index的Html頁面,因而乎則有了以下的樣子:html
咱們運行起來看看是否能正確顯示結果:java
從這裏咱們能夠看出貌似不存在咱們本節所須要講解的問題,這裏的介紹也就僅供咱們玩玩而已,實際開發中會把WebAPi徹底抽離出來做爲服務來進行數據傳輸,而這裏可以正確訪問到Index頁面依然是以MVC爲主導,WebAPi寄宿爲WebHost,因此訪問其目錄下的內容毫無疑問會訪問到,若是咱們將WebAPi徹底隔離出來也就是不依賴於IIS,利用Slef-Host來實現。(有關WebAPi中的WebHost以及Self-Host能夠參考前面系列文章)。api
咱們來創建一個Windows應用程序起名爲WebAPiReturnHtml。跨域
咱們新創建一個HttpServerHost類利用 HttpSelfHostServer 來監聽Http請求,代碼以下:服務器
public class HttpServerHost { /// <summary> /// HttpSelfHostServer實例 /// </summary> private HttpSelfHostServer _server; /// <summary> /// 啓動HTTP服務器 /// </summary> public void Start() { var config = new HttpSelfHostConfiguration("http://localhost:8080"); config.MaxReceivedMessageSize = int.MaxValue; config.Routes.MapHttpRoute("Default", "api/{controller}/{action}"); //設置最大接收消息大小 config.MaxReceivedMessageSize = int.MaxValue; config.Formatters.Clear(); config.Formatters.Add(new JsonpFormatter()); _server = new HttpSelfHostServer(config); //容許跨域 _server.Configuration.MessageHandlers.Add(new CorsHandler()); _server.OpenAsync().Wait(); } }
咱們來演示下效果:函數
結果出錯了,此時咱們應該注意應該以【管理員身份運行VS】纔可。測試
咱們緊接着添加測試類以下:spa
public class HomeController : ApiController { [HttpGet] public string Test() { return "OK"; } }
咱們來看看演示結果:code
整個徹底抽離出WebAPi的過程就是這麼簡單,接着咱們回到開頭的話題介紹,咱們在此項目下創建Index頁面以下來訪問試試:
結果以下:
此時則讓咱們大失所望,徹底抽離出WebAPi此時則無妨訪問到靜態資源,此時咱們來利用讀取文件字符串的形式來返回該靜態資源,以下:
public HttpResponseMessage GetHtml() { var currentRunPath = AppDomain.CurrentDomain.BaseDirectory; var substringBin = currentRunPath.IndexOf("bin"); var path = currentRunPath.Substring(0, substringBin) + "Index.html"; var httpResponseMessage = new HttpResponseMessage(); httpResponseMessage.Content = new StringContent(File.ReadAllText(path), Encoding.UTF8); httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html"); return httpResponseMessage; }
咱們再來看看結果:
如上請求咱們能夠設置路由特性,以下:
[HttpGet] [Route("Index")]
此時訪問的路徑則變爲 localhost:8080/index 更加簡潔。爲了實現這樣的需求只能無所不用其極,若是是加載圖片呢,又該如何呢?固然也有解決辦法,上述既然有讀取字符串StringContent,那確定有讀取圖片的流,將上述
httpResponseMessage.Content = new StringContent(File.ReadAllText(path), Encoding.UTF8); httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
修改成以下便可:
httpResponseMessage.Content = new StreamContent(new FileStream(path, FileMode.Open)); httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("image/*");
那麼如今問題來了,如何在上述Index.html頁面中去請求JS呢?既然有了這個思路那就好辦了,咱們繼續往下看。
在控制器中返回JS定義以下:
[HttpGet] public HttpResponseMessage GetJS(string file) { var currentRunPath = AppDomain.CurrentDomain.BaseDirectory; var substringBin = currentRunPath.IndexOf("bin"); var path = currentRunPath.Substring(0, substringBin) + file; var httpResponseMessage = new HttpResponseMessage(); httpResponseMessage.Content = new StringContent(File.ReadAllText(path), Encoding.UTF8); httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("text/javascript"); return httpResponseMessage; }
在根目錄下創建Index.js,去定義函數以下:
function btnClick() { alert("調用Index.js成功"); }
請求Index.js,以及結構以下:
接下來咱們再來進行演示:
到這裏咱們達到咱們需求就已徹底結束。
這其中仍是有一點小小的疑惑,若是是在WebAPi2中須要啓動 config.MapHttpAttributeRoutes(); 在上述請求Index方法時若是咱們添加 [Route(index)] ,此時請求index.js則需進行以下修改
<script type="text/javascript" src="GetJS?file=/index.js"></script>
修改成
<script type="text/javascript" src="api/home/GetJS?file=/index.js"></script>
可是在WebAPi2.2中應該沒有了 config.MapHttpAttributeRoutes(); 想必是已經默認啓動了該路由特性可是此時在上述請求Index方法時若定路由定性 [Route("index")] 此時根本請求不到該Index方法,不知是何緣故!
特殊需求有特殊的實現方法,若未有此需求的提出根本想不出這樣去實現,同時很少加思考也會停滯不前感受這樣作根本是不可能,可是並不是不可能,不是嗎!可能說對於這樣在WebAPi中存放頁面不是太可取,若是能放在其餘的UI,我又何須這樣作呢,需求如此,只能這樣作了,固然也能夠直接將樣式和腳本放在服務器上經過CDN來加載,實現的僅僅是顯示一個列表從而進行其餘幾個操做而已,不須要進行這樣的大動做。