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 应用教程(一) ——数据流使用,如需转载请自行联系原博主。

相关文章
|
3天前
|
自然语言处理 搜索推荐 数据挖掘
淘宝商品描述 API 接口的开发、应用与收益
淘宝商品描述API接口的开发与应用涵盖注册成为开发者、了解API规范、选择开发工具及语言(如Python)和实现代码调用。该接口可用于优化电商平台商品展示、同步数据、竞品分析、智能客服及个性化推荐,从而提高销售转化率、降低运营成本并拓展业务机会。通过自动化处理和数据分析,企业能更精准地满足消费者需求,提升竞争力。
30 9
|
2天前
|
供应链 搜索推荐 API
深度解析1688 API对电商的影响与实战应用
在全球电子商务迅猛发展的背景下,1688作为知名的B2B电商平台,为中小企业提供商品批发、分销、供应链管理等一站式服务,并通过开放的API接口,为开发者和电商企业提供数据资源和功能支持。本文将深入解析1688 API的功能(如商品搜索、详情、订单管理等)、应用场景(如商品展示、搜索优化、交易管理和用户行为分析)、收益分析(如流量增长、销售提升、库存优化和成本降低)及实际案例,帮助电商从业者提升运营效率和商业收益。
51 17
|
12天前
|
存储 缓存 API
API接口详解及其在电子商务中的应用研究
通过这些内容的详细介绍和实际案例分析,希望能帮助您深入理解API接口及其在电子商务中的应用,提高系统的互操作性和用户体验。
55 14
|
6天前
|
供应链 搜索推荐 API
1688商品类目API接口的开发应用与收益
1688平台作为全球领先的B2B在线交易市场,提供了丰富的API接口,助力企业高效获取商品信息、优化供应链管理。本文聚焦1688商品类目API接口的开发应用,涵盖接口概述、环境配置、Python代码示例及实际案例,展示其为企业带来的显著收益,如提升运营效率、优化市场策略、降低成本和增强用户体验。通过合理调用API,企业可大幅提升竞争力。
23 7
|
7天前
|
JSON 数据挖掘 API
唯品会按关键字搜索 VIP 商品 API 接口的开发应用与收益
在电商蓬勃发展的今天,精准的商品搜索功能至关重要。唯品会的按关键字搜索VIP商品API接口通过高效、精准的检索,提升了用户购物体验和商家销售业绩。该接口基于RESTful架构,采用JSON格式交互,支持唯品会APP内搜索、第三方平台合作及数据分析等场景,显著提升用户活跃度与忠诚度,拓展销售渠道,增加收入,并挖掘数据驱动的商业价值,助力唯品会持续发展。
22 4
|
4天前
|
存储 JSON API
小红书获取笔记详情API接口的开发、应用与收益。
小红书笔记详情API采用Python与Django框架开发,使用MySQL数据库存储数据。接口通过HTTP GET请求获取笔记详情,返回JSON格式数据,包含笔记内容、作者信息、图片链接等。该API应用于小红书APP内笔记展示和互动功能,并支持第三方平台的内容整合与数据分析,提升用户体验与活跃度,促进品牌合作推广,优化平台运营效率,为平台带来显著收益。
38 1
|
4天前
|
供应链 安全 API
API接口在电商的应用及收益
API接口在电商中广泛应用,涵盖商品数据管理、用户认证、订单处理与跟踪及支付集成等核心场景。通过同步商品信息、保障账户安全、实时物流查询和多支付方式集成,提升用户体验与信任,减少超卖现象,增加销售额。开放API促进第三方合作,创造额外收入,如技术服务费和交易分成。自动化交互优化运营效率,降低人工成本和库存积压风险,助力电商平台高效智能发展。
28 1
|
12天前
|
人工智能 运维 监控
发现API安全风险,F5随时随地保障应用和API安全
发现API安全风险,F5随时随地保障应用和API安全
31 7
|
15天前
|
人工智能 监控 安全
自学记录鸿蒙 API 13:骨骼点检测应用Core Vision Skeleton Detection
骨骼点检测技术能够从图片中识别出人体的关键骨骼点位置,如头部、肩部、手肘等,广泛应用于运动健身指导、游戏交互、医疗辅助、安全监控等领域。我决定深入学习HarmonyOS Next API 13中的Skeleton Detection API,并开发一个简单的骨骼点检测应用。通过理解API核心功能、项目初始化与配置、实现检测功能、构建用户界面,以及性能优化和功能扩展,逐步实现这一技术的应用。未来计划将其应用于健身指导和智能监控领域,探索与其他AI能力的结合,开发更智能的解决方案。如果你也对骨骼点检测感兴趣,不妨一起进步!
143 9
|
14天前
|
JSON API 开发者
Lazada 商品评论列表 API 接口:开发、应用与收益
Lazada作为东南亚领先的电商平台,其商品评论数据蕴含丰富信息。通过开发和利用Lazada商品评论列表API接口,企业可深入挖掘这些数据,优化产品、营销和服务,提升客户体验和市场竞争力。该API基于HTTP协议,支持GET、POST等方法,开发者需注册获取API密钥,并选择合适的编程语言(如Python)进行开发。应用场景包括竞品分析、客户反馈处理及精准营销,帮助企业提升销售业绩、降低运营成本并增强品牌声誉。
33 2