ASP.NET Web API 应用教程(一) ——数据流使用
?
?
相信已經(jīng)有很多文章來介紹ASP.Net Web API 技術(shù),本系列文章主要介紹如何使用數(shù)據(jù)流,HTTPS,以及可擴(kuò)展的Web API 方面的技術(shù),系列文章主要有三篇內(nèi)容。
主要內(nèi)容如下:
I ?數(shù)據(jù)流
II 使用HTTPS
III 可擴(kuò)展的Web API 文檔
?
項(xiàng)目環(huán)境要求
- VS 2012(SP4)及以上,
- .Net 框架4.5.1
- Nuget包,可在packages.config 文件中查尋
本文涉及的知識(shí)點(diǎn)
.Net 框架
前言
?
自從ASP.NET MVC 4之后.Net 框架開始支持ASP.NET Web API ,ASP.NET Web API 基于HTTP 協(xié)議建立的,是構(gòu)建 RESTful 服務(wù)和處理數(shù)據(jù)的理想平臺(tái),旨在使用HTTP 技術(shù)實(shí)現(xiàn)對(duì)多平臺(tái)的支持。
ASP.NET Web API 以request-response 的消息轉(zhuǎn)換模式為主,客戶端向服務(wù)器發(fā)送請(qǐng)求,服務(wù)器端響應(yīng)客戶端請(qǐng)求。響應(yīng)可同步或異步。
?個(gè)人認(rèn)為使用Web API創(chuàng)建應(yīng)用需要注意的三個(gè)關(guān)鍵點(diǎn):
- 采用服務(wù)及方法滿足的目標(biāo)
- 每個(gè)方法的輸入,如請(qǐng)求
- 每個(gè)方法的輸出,如響應(yīng)
通常情況下,Asp.Net Web API 定義method語法與HTTP方法一一對(duì)應(yīng)的,如自定義方法名?GetPysicians(),則與HTTP中Get 方法匹配。下圖是常用匹配表。
?
但是此方法在很多情況下,并不實(shí)用,假如你想在單個(gè)API controller 類中定義多個(gè)Get 或Post 方法,在這種情況下,需要定義包含action 的路徑,將Action 作為URI 的一部分。以下是配置代碼:
但是此方法不足以應(yīng)對(duì)所有情況,如果想實(shí)現(xiàn)從中央倉庫刪除文件,并且想調(diào)用同一個(gè)方法來獲取文件,這種情況下,Web API 框架需要偽裝Get 及Delete對(duì)應(yīng)的HTTP 方法屬性。如圖所示:
RemoveFile 方法可被Delete(HttpDelete) 或 Get(HttpGet)方法同時(shí)調(diào)用,從某種程度來說,HTTP 方法使開發(fā)人員命名?API“方法”變得簡單而標(biāo)準(zhǔn)。
Web API框架也提供了一些其他功能來處理路徑方面的問題,與MVC 的路徑處理方法相似。因此可定義不同類型的Action方法。?
數(shù)據(jù)流
網(wǎng)絡(luò)App 最常見的執(zhí)行操作就是獲取數(shù)據(jù)流。ASP.NET Web API 能夠處理客戶端與服務(wù)器端傳輸?shù)闹亓考?jí)的數(shù)據(jù)流,數(shù)據(jù)流可來源于目錄文件,也可是數(shù)據(jù)庫中的二進(jìn)制文件。本文主要介紹兩種方法“Download”和“Upload”實(shí)現(xiàn)數(shù)據(jù)流相關(guān)的功能,Download是從服務(wù)器下載數(shù)據(jù)操作,而Upload則是上傳數(shù)據(jù)到服務(wù)器。
相關(guān)項(xiàng)目
- WebAPIDataStreaming
- WebAPIClient
- POCOLibrary
在對(duì)代碼解釋之前,首先來了解如何配置IIS(7.5)和Web API 服務(wù)Web.Config 文件。
1. 保證Downloads/Uploads 涉及的文件具有讀寫權(quán)限。
2. 保證有足夠容量的內(nèi)容或因公安空間處理大文件。
3. 如果文件較大
a. 配置Web.Config 文件時(shí),保證 maxRequestLength 時(shí)響應(yīng)時(shí)間 executionTimeout 合理。具體的值主要依賴于數(shù)據(jù)大小,允許一次性上傳的最大數(shù)據(jù)為2 GB
b. 保證 maxAllowedContentLength 在requestFiltering部分配置下正確設(shè)置,默認(rèn)值為30MB,最大值4GB
一旦完成預(yù)先配置,那么創(chuàng)建數(shù)據(jù)流服務(wù)就非常簡單了,首先 需要定義文件流“ApiController”,如下:
1: /// <summary> 2: /// File streaming API 3: /// </summary> 4: [RoutePrefix("filestreaming")] 5: [RequestModelValidator] 6: public class StreamFilesController : ApiController 7: { 8: /// <summary> 9: /// Get File meta data 10: /// </summary> 11: /// <param name="fileName">FileName value</param> 12: /// <returns>FileMeta data response.</returns> 13: [Route("getfilemetadata")] 14: public HttpResponseMessage GetFileMetaData(string fileName) 15: { 16: // ......................................... 17: // Full code available in the source control 18: // ......................................... 19: ? 20: } 21: ? 22: /// <summary> 23: /// Search file and return its meta data in all download directories 24: /// </summary> 25: /// <param name="fileName">FileName value</param> 26: /// <returns>List of file meta datas response</returns> 27: [HttpGet] 28: [Route("searchfileindownloaddirectory")] 29: public HttpResponseMessage SearchFileInDownloadDirectory(string fileName) 30: { 31: // ......................................... 32: // Full code available in the source control 33: // ......................................... 34: } 35: ? 36: /// <summary> 37: /// Asynchronous Download file 38: /// </summary> 39: /// <param name="fileName">FileName value</param> 40: /// <returns>Tasked File stream response</returns> 41: [Route("downloadasync")] 42: [HttpGet] 43: public async Task<HttpResponseMessage> DownloadFileAsync(string fileName) 44: { 45: // ......................................... 46: // Full code available in the source control 47: // ......................................... 48: } 49: ? 50: /// <summary> 51: /// Download file 52: /// </summary> 53: /// <param name="fileName">FileName value</param> 54: /// <returns>File stream response</returns> 55: [Route("download")] 56: [HttpGet] 57: public HttpResponseMessage DownloadFile(string fileName) 58: { 59: // ......................................... 60: // Full code available in the source control 61: // ......................................... 62: } 63: ? 64: /// <summary> 65: /// Upload file(s) 66: /// </summary> 67: /// <param name="overWrite">An indicator to overwrite a file if it exist in the server</param> 68: /// <returns>Message response</returns> 69: [Route("upload")] 70: [HttpPost] 71: public HttpResponseMessage UploadFile(bool overWrite) 72: { 73: // ......................................... 74: // Full code available in the source control 75: // ......................................... 76: } 77: ? 78: /// <summary> 79: /// Asynchronous Upload file 80: /// </summary> 81: /// <param name="overWrite">An indicator to overwrite a file if it exist in the server</param> 82: /// <returns>Tasked Message response</returns> 83: [Route("uploadasync")] 84: [HttpPost] 85: public async Task<HttpResponseMessage> UploadFileAsync(bool overWrite) 86: { 87: // ......................................... 88: // Full code available in the source control 89: // ......................................... 90: } 91: }Download 服務(wù)方法首先需要確認(rèn)請(qǐng)求的文件是否存在,如果未找到,則返回錯(cuò)誤提示“file is not found”,如果找到此文件,內(nèi)容則轉(zhuǎn)換為字節(jié)附加到響應(yīng)對(duì)象,為“application/octet-stream” MIMI 內(nèi)容類型。
1: /// <summary> 2: /// Download file 3: /// </summary> 4: /// <param name="fileName">FileName value<param> 5: /// <returns>File stream response<returns> 6: [Route("download")] 7: [HttpGet] 8: public HttpResponseMessage DownloadFile(string fileName) 9: { 10: HttpResponseMessage response = Request.CreateResponse(); 11: FileMetaData metaData = new FileMetaData(); 12: try 13: { 14: string filePath = Path.Combine(this.GetDownloadPath(), @"\", fileName); 15: FileInfo fileInfo = new FileInfo(filePath); 16: ? 17: if (!fileInfo.Exists) 18: { 19: metaData.FileResponseMessage.IsExists = false; 20: metaData.FileResponseMessage.Content = string.Format("{0} file is not found !", fileName); 21: response = Request.CreateResponse(HttpStatusCode.NotFound, metaData, new MediaTypeHeaderValue("text/json")); 22: } 23: else 24: { 25: response.Headers.AcceptRanges.Add("bytes"); 26: response.StatusCode = HttpStatusCode.OK; 27: response.Content = new StreamContent(fileInfo.ReadStream()); 28: response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 29: response.Content.Headers.ContentDisposition.FileName = fileName; 30: response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 31: response.Content.Headers.ContentLength = fileInfo.Length; 32: } 33: } 34: catch (Exception exception) 35: { 36: // Log exception and return gracefully 37: metaData = new FileMetaData(); 38: metaData.FileResponseMessage.Content = ProcessException(exception); 39: response = Request.CreateResponse(HttpStatusCode.InternalServerError, metaData, new MediaTypeHeaderValue("text/json")); 40: } 41: return response; 42: }Upload服務(wù)方法則會(huì)在multipart/form-data MIMI 內(nèi)容類型執(zhí)行,首先會(huì)檢測(cè)HTTP 請(qǐng)求的內(nèi)容類型是否是多主體,如果是,則對(duì)比內(nèi)容長度是否超過最大尺寸,如果沒有超過,則開始上傳內(nèi)容,當(dāng)操作完成之后,則提示相應(yīng)的信息。
代碼片段如下:
1: /// <summary> 2: /// Upload file(s) 3: /// </summary> 4: /// <param name="overWrite">An indicator to overwrite a file if it exist in the server.</param> 5: /// <returns>Message response</returns> 6: [Route("upload")] 7: [HttpPost] 8: public HttpResponseMessage UploadFile(bool overWrite) 9: { 10: HttpResponseMessage response = Request.CreateResponse(); 11: List<FileResponseMessage> fileResponseMessages = new List<FileResponseMessage>(); 12: FileResponseMessage fileResponseMessage = new FileResponseMessage { IsExists = false }; 13: ? 14: try 15: { 16: if (!Request.Content.IsMimeMultipartContent()) 17: { 18: fileResponseMessage.Content = "Upload data request is not valid !"; 19: fileResponseMessages.Add(fileResponseMessage); 20: response = Request.CreateResponse(HttpStatusCode.UnsupportedMediaType, fileResponseMessages, new MediaTypeHeaderValue("text/json")); 21: } 22: ? 23: else 24: { 25: response = ProcessUploadRequest(overWrite); 26: } 27: } 28: catch (Exception exception) 29: { 30: // Log exception and return gracefully 31: fileResponseMessage = new FileResponseMessage { IsExists = false }; 32: fileResponseMessage.Content = ProcessException(exception); 33: fileResponseMessages.Add(fileResponseMessage); 34: response = Request.CreateResponse(HttpStatusCode.InternalServerError, fileResponseMessages, new MediaTypeHeaderValue("text/json")); 35: ? 36: } 37: return response; 38: } 39: ? 40: /// <summary> 41: /// Asynchronous Upload file 42: /// </summary> 43: /// <param name="overWrite">An indicator to overwrite a file if it exist in the server.<param> 44: /// <returns>Tasked Message response</returns> 45: [Route("uploadasync")] 46: [HttpPost] 47: public async Task<HttpResponseMessage> UploadFileAsync(bool overWrite) 48: { 49: return await new TaskFactory().StartNew( 50: () => 51: { 52: return UploadFile(overWrite); 53: }); 54: } 55: ? 56: /// <summary> 57: /// Process upload request in the server 58: /// </summary> 59: /// <param name="overWrite">An indicator to overwrite a file if it exist in the server.</param> 60: /// </returns>List of message object</returns> 61: private HttpResponseMessage ProcessUploadRequest(bool overWrite) 62: { 63: // ......................................... 64: // Full code available in the source control 65: // ......................................... 66: }調(diào)用download 及 upload 文件方法是控制臺(tái)應(yīng)用,App 假定文件流服務(wù)通過HttpClient和相關(guān)類。基本下載文件代碼,創(chuàng)建下載HTTP 請(qǐng)求對(duì)象。
1: /// <summary> 2: /// Download file 3: /// </summary> 4: /// <returns>Awaitable Task object</returns> 5: private static async Task DownloadFile() 6: { 7: Console.ForegroundColor = ConsoleColor.Green; 8: Console.WriteLine("Please specify file name with extension and Press Enter :- "); 9: string fileName = Console.ReadLine(); 10: string localDownloadPath = string.Concat(@"c:\", fileName); // the path can be configurable 11: bool overWrite = true; 12: string actionURL = string.Concat("downloadasync?fileName=", fileName); 13: ? 14: try 15: { 16: Console.WriteLine(string.Format("Start downloading @ {0}, {1} time ", 17: DateTime.Now.ToLongDateString(), 18: DateTime.Now.ToLongTimeString())); 19: ? 20: ? 21: using (HttpClient httpClient = new HttpClient()) 22: { 23: httpClient.BaseAddress = baseStreamingURL; 24: HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, actionURL); 25: ? 26: await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead). 27: ContinueWith((response) 28: => 29: { 30: Console.WriteLine(); 31: try 32: { 33: ProcessDownloadResponse(localDownloadPath, overWrite, response); 34: } 35: catch (AggregateException aggregateException) 36: { 37: Console.ForegroundColor = ConsoleColor.Red; 38: Console.WriteLine(string.Format("Exception : ", aggregateException)); 39: } 40: }); 41: } 42: } 43: catch (Exception ex) 44: { 45: Console.ForegroundColor = ConsoleColor.Red; 46: Console.WriteLine(ex.Message); 47: } 48: } 49: ? 50: ? 51: /// <summary> 52: /// Process download response object 53: /// </summary> 54: /// <param name="localDownloadFilePath">Local download file path</param> 55: /// <param name="overWrite">An indicator to overwrite a file if it exist in the client.</param> 56: /// <param name="response">Awaitable HttpResponseMessage task value</param> 57: private static void ProcessDownloadResponse(string localDownloadFilePath, bool overWrite, 58: Task<HttpResponseMessage> response) 59: { 60: if (response.Result.IsSuccessStatusCode) 61: { 62: response.Result.Content.DownloadFile(localDownloadFilePath, overWrite). 63: ContinueWith((downloadmessage) 64: => 65: { 66: Console.ForegroundColor = ConsoleColor.Green; 67: Console.WriteLine(downloadmessage.TryResult()); 68: }); 69: } 70: else 71: { 72: ProcessFailResponse(response); 73: } 74: }?
注意上述代碼中HttpClient 對(duì)象發(fā)送請(qǐng)求,并等待響應(yīng)發(fā)送Header內(nèi)容(HttpCompletionOption.ResponseHeadersRead )。而不是發(fā)送全部的響應(yīng)內(nèi)容文件。一旦Response header 被讀,則執(zhí)行驗(yàn)證,一旦驗(yàn)證成功,則執(zhí)行下載方法。
以下代碼調(diào)用upload 文件流,與下載方法類似,創(chuàng)建多主體表單數(shù)據(jù),并發(fā)送給服務(wù)器端。
1: /// <summary> 2: /// Upload file 3: /// </summary> 4: /// <returns>Awaitable task object</returns> 5: private static async Task UploadFile() 6: { 7: try 8: { 9: string uploadRequestURI = "uploadasync?overWrite=true"; 10: ? 11: MultipartFormDataContent formDataContent = new MultipartFormDataContent(); 12: ? 13: // Validate the file and add to MultipartFormDataContent object 14: formDataContent.AddUploadFile(@"c:\nophoto.png"); 15: formDataContent.AddUploadFile(@"c:\ReadMe.txt"); 16: ? 17: if (!formDataContent.HasContent()) // No files found to be uploaded 18: { 19: Console.ForegroundColor = ConsoleColor.Red; 20: Console.Write(formDataContent.GetUploadFileErrorMesage()); 21: return; 22: } 23: else 24: { 25: string uploadErrorMessage = formDataContent.GetUploadFileErrorMesage(); 26: if (!string.IsNullOrWhiteSpace(uploadErrorMessage)) // Some files couldn't be found 27: { 28: Console.ForegroundColor = ConsoleColor.Red; 29: Console.Write(uploadErrorMessage); 30: } 31: ? 32: HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uploadRequestURI); 33: request.Content = formDataContent; 34: ? 35: using (HttpClient httpClient = new HttpClient()) 36: { 37: Console.ForegroundColor = ConsoleColor.Green; 38: Console.WriteLine(string.Format("Start uploading @ {0}, {1} time ", 39: DateTime.Now.ToLongDateString(), 40: DateTime.Now.ToLongTimeString())); 41: ? 42: httpClient.BaseAddress = baseStreamingURL; 43: await httpClient.SendAsync(request). 44: ContinueWith((response) 45: => 46: { 47: try 48: { 49: ProcessUploadResponse(response); 50: } 51: catch (AggregateException aggregateException) 52: { 53: Console.ForegroundColor = ConsoleColor.Red; 54: Console.WriteLine(string.Format("Exception : ", aggregateException)); 55: } 56: }); 57: } 58: } 59: } 60: catch (Exception ex) 61: { 62: Console.ForegroundColor = ConsoleColor.Red; 63: Console.WriteLine(ex.Message); 64: } 65: } 66: ? 67: /// <summary> 68: /// Process download response object 69: /// </summary> 70: /// <param name="response">Awaitable HttpResponseMessage task value</param> 71: private static void ProcessUploadResponse(Task<HttpResponseMessage> response) 72: { 73: if (response.Result.IsSuccessStatusCode) 74: { 75: string uploadMessage = string.Format("\nUpload completed @ {0}, {1} time ", 76: DateTime.Now.ToLongDateString(), 77: DateTime.Now.ToLongTimeString()); 78: Console.ForegroundColor = ConsoleColor.Green; 79: Console.WriteLine(string.Format("{0}\nUpload Message : \n{1}", uploadMessage, 80: JsonConvert.SerializeObject(response.Result.Content.ReadAsAsync<List<FileResponseMessage>>().TryResult(), Formatting.Indented))); 81: } 82: else 83: { 84: ProcessFailResponse(response); 85: } 86: }?
數(shù)據(jù)流項(xiàng)目由可擴(kuò)展類和方法組成,本文就不再詳述。下篇文章中將介紹“使用HTTPS 開發(fā)項(xiàng)目”
數(shù)據(jù)流是數(shù)據(jù)傳輸中的重要部分,學(xué)習(xí)了本節(jié)內(nèi)容有助于大家更好地進(jìn)行ASP.NET的開發(fā)。當(dāng)然,還可以借助一些開發(fā)工具來助力開發(fā)過程。ComponentOne Studio for ASP.NET?提供了一整套完備的開發(fā)工具包,用于在各種瀏覽器中創(chuàng)建和設(shè)計(jì)具有現(xiàn)代風(fēng)格的Web應(yīng)用程序。
?
下載源代碼
原文鏈接:http://www.codeproject.com/Articles/838274/Web-API-Thoughts-of-Data-Streaming#Hist
?
原文鏈接:http://www.cnblogs.com/powertoolsteam/p/5029475.html
轉(zhuǎn)載于:https://www.cnblogs.com/Percy_Lee/p/5662424.html
總結(jié)
以上是生活随笔為你收集整理的ASP.NET Web API 应用教程(一) ——数据流使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hystrix之Dashboard的常见
- 下一篇: 小米平板5 Pro 12.4英寸公布:尺