ASP.NET Web API 应用教程(一) ——数据流使用

简介:

 

相信已经有很多文章来介绍ASP.Net Web API 技术,本系列文章主要介绍如何使用数据流,HTTPS,以及可扩展的Web API 方面的技术,系列文章主要有三篇内容。

主要内容如下:

I  数据流

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 技术实现对多平台的支持。

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 开发项目”

下载源代码

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

 

相信已经有很多文章来介绍ASP.Net Web API 技术,本系列文章主要介绍如何使用数据流,HTTPS,以及可扩展的Web API 方面的技术,系列文章主要有三篇内容。

主要内容如下:

I  数据流

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 技术实现对多平台的支持。

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

本文转自ITPUB博客77rou的博客,原文链接:ASP.NET Web API 应用教程(一) ——数据流使用,如需转载请自行联系原博主。

相关文章
|
1月前
|
JSON API 数据库
解释如何在 Python 中实现 Web 服务(RESTful API)。
解释如何在 Python 中实现 Web 服务(RESTful API)。
26 0
|
1月前
|
缓存 JavaScript 算法
活用 Composition API 核心函数,打造卓越应用(下)
活用 Composition API 核心函数,打造卓越应用(下)
|
1月前
|
存储 JavaScript API
活用 Composition API 核心函数,打造卓越应用(上)
活用 Composition API 核心函数,打造卓越应用(上)
|
1月前
|
数据采集 监控 安全
各种业务场景调用API代理的API接口教程
API代理的API接口在各种业务场景中具有广泛的应用,本文将介绍哪些业务场景可以使用API代理的API接口,并提供详细的调用教程和代码演示,同时,我们还将讨论在不同场景下使用API代理的API接口所带来的好处。
|
1月前
|
人工智能 关系型数据库 Serverless
Serverless 应用引擎常见问题之API生成的函数镜像改为自定义的镜像如何解决
Serverless 应用引擎(Serverless Application Engine, SAE)是一种完全托管的应用平台,它允许开发者无需管理服务器即可构建和部署应用。以下是Serverless 应用引擎使用过程中的一些常见问题及其答案的汇总:
39 3
|
9天前
|
开发框架 前端开发 JavaScript
采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示
技术架构:Asp.NET CORE 3.1 MVC + SQLserver + Redis等 开发语言:C# 6.0、JavaScript 前端框架:JQuery、EasyUI、Bootstrap 后端框架:MVC、SQLSugar等 数 据 库:SQLserver 2012
|
30天前
|
开发框架 .NET 物联网
.NET从入门到精通,零基础也能搞定的基础知识教程
.NET从入门到精通,零基础也能搞定的基础知识教程
21 0
|
1月前
|
安全 API 数据安全/隐私保护
email api接口配置教程步骤详解
Email API是用于程序化访问邮件服务的工具,让开发者能集成邮件功能到应用中。配置Email API包括选择供应商(如SendGrid、Mailgun、AokSend),注册获取API密钥,配置API参数,及测试邮件发送。使用Email API能提升邮件发送的可靠性和效率,便于邮件管理及营销活动。AokSend支持大量验证码发送,适合高效邮件运营。
|
1月前
|
搜索推荐 数据挖掘 API
1688商品详情API在电商平台中的应用与实践
随着电子商务的迅猛发展,越来越多的商家选择利用API(应用程序编程接口)来提升其在线业务的效率和用户体验。特别是在商品信息展示方面,1688商品详情API作为连接商家和消费者的重要桥梁,扮演着至关重要的角色。本文将深入探讨1688商品详情API的功能、应用场景以及如何通过该API提高电商平台的商品信息展示质量。
|
1月前
|
XML JSON API
通过Flask框架创建灵活的、可扩展的Web Restful API服务
通过Flask框架创建灵活的、可扩展的Web Restful API服务