ASP.NET Web API 應用教程(一) ——數據流使用

 

 

相信已經有不少文章來介紹ASP.Net Web API 技術,本系列文章主要介紹如何使用數據流,HTTPS,以及可擴展的Web API 方面的技術,系列文章主要有三篇內容。html

主要內容以下:數據庫

I  數據流json

II 使用HTTPS瀏覽器

III 可擴展的Web API 文檔服務器

 

項目環境要求

  • VS 2012(SP4)及以上,
  • .Net 框架4.5.1
  • Nuget包,可在packages.config 文件中查尋

本文涉及的知識點

  1. ActionFilter
  2. AuthorizationFilter
  3. DelegateHandler
  4. Different Web API routing 屬性
  5. MediaTypeFormatter
  6. OWIN
  7. Self Hosting
  8. Web API 文檔及可擴展功能

.Net 框架 網絡

  1. Async/Await
  2. .NET reflection
  3. Serialization
  4. ASP.NET Web API/MVC Error handling
  5. IIS ,HTTPS 及Certificate
  6. 設計準則及技術

前言併發

 

自從ASP.NET MVC 4以後.Net 框架開始支持ASP.NET Web API ,ASP.NET Web API 基於HTTP 協議創建的,是構建 RESTful 服務和處理數據的理想平臺,旨在使用HTTP 技術實現對多平臺的支持。app

ASP.NET Web API 以request-response 的消息轉換模式爲主,客戶端向服務器發送請求,服務器端響應客戶端請求。響應可同步或異步。框架

 我的認爲使用Web API建立應用須要注意的三個關鍵點:異步

  • 採用服務及方法知足的目標
  • 每一個方法的輸入,如請求
  • 每一個方法的輸出,如響應

一般狀況下,Asp.Net Web API 定義method語法與HTTP方法一一對應的,如自定義方法名 GetPysicians(),則與HTTP中Get 方法匹配。下圖是經常使用匹配表。

 


可是此方法在不少狀況下,並不實用,假如你想在單個API controller 類中定義多個Get 或Post 方法,在這種狀況下,須要定義包含action 的路徑,將Action 做爲URI 的一部分。如下是配置代碼:

   1:  public static void Register(HttpConfiguration config)
   2:  {
   3:      // Web API configuration and services
   4:      // Web API routes
   5:       config.MapHttpAttributeRoutes();
   6:      
   7:       config.Routes.MapHttpRoute(name: "PhysicianApi",
   8:                  routeTemplate: "{controller}/{action}/{id}",
   9:                  defaults: new { id = RouteParameter.Optional });
  10:  }

可是此方法不足以應對全部狀況,若是想實現從中央倉庫刪除文件,而且想調用同一個方法來獲取文件,這種狀況下,Web API 框架須要假裝Get 及Delete對應的HTTP 方法屬性。如圖所示:

RemoveFile 方法可被Delete(HttpDelete) 或 Get(HttpGet)方法同時調用,從某種程度來講,HTTP 方法使開發人員命名 API「方法」變得簡單而標準。

Web API框架也提供了一些其餘功能來處理路徑方面的問題,與MVC 的路徑處理方法類似。所以可定義不一樣類型的Action方法。 

數據流

網絡App 最多見的執行操做就是獲取數據流。ASP.NET Web API 可以處理客戶端與服務器端傳輸的重量級的數據流,數據流可來源於目錄文件,也但是數據庫中的二進制文件。本文主要介紹兩種方法「Download」和「Upload」實現數據流相關的功能,Download是從服務器下載數據操做,而Upload則是上傳數據到服務器。

相關項目

  • WebAPIDataStreaming
  • WebAPIClient
  • POCOLibrary

在對代碼解釋以前,首先來了解如何配置IIS(7.5)和Web API 服務Web.Config 文件。

1. 保證Downloads/Uploads 涉及的文件具備讀寫權限。

2. 保證有足夠容量的內容或因公安空間處理大文件。

3. 若是文件較大

a. 配置Web.Config 文件時,保證 maxRequestLength 時響應時間 executionTimeout 合理。具體的值主要依賴於數據大小,容許一次性上傳的最大數據爲2 GB

b. 保證 maxAllowedContentLength 在requestFiltering部分配置下正確設置,默認值爲30MB,最大值4GB

一旦完成預先配置,那麼建立數據流服務就很是簡單了,首先 須要定義文件流「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 服務方法首先須要確認請求的文件是否存在,若是未找到,則返回錯誤提示「file is not found」,若是找到此文件,內容則轉換爲字節附加到響應對象,爲「application/octet-stream」 MIMI 內容類型。

   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服務方法則會在multipart/form-data MIMI 內容類型執行,首先會檢測HTTP 請求的內容類型是不是多主體,若是是,則對比內容長度是否超過最大尺寸,若是沒有超過,則開始上傳內容,當操做完成以後,則提示相應的信息。

代碼片斷以下:

   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:  }

調用download 及 upload 文件方法是控制檯應用,App 假定文件流服務經過HttpClient和相關類。基本下載文件代碼,建立下載HTTP 請求對象。

   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 對象發送請求,並等待響應發送Header內容(HttpCompletionOption.ResponseHeadersRead )。而不是發送所有的響應內容文件。一旦Response header 被讀,則執行驗證,一旦驗證成功,則執行下載方法。

如下代碼調用upload 文件流,與下載方法相似,建立多主體表單數據,併發送給服務器端。

   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:  }

 

數據流項目由可擴展類和方法組成,本文就再也不詳述。下篇文章中將介紹「使用HTTPS 開發項目」

數據流是數據傳輸中的重要部分,學習了本節內容有助於你們更好地進行ASP.NET的開發。固然,還能夠藉助一些開發工具來助力開發過程。ComponentOne Studio for ASP.NET 提供了一整套完備的開發工具包,用於在各類瀏覽器中建立和設計具備現代風格的Web應用程序。

 

下載源代碼

原文連接:http://www.codeproject.com/Articles/838274/Web-API-Thoughts-of-Data-Streaming#Hist

 



原文連接:http://www.cnblogs.com/powertoolsteam/p/5029475.html

相關文章
相關標籤/搜索