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

简介:   相信已经有很多文章来介绍ASP.Net Web API 技术,本系列文章主要介绍如何使用数据流,HTTPS,以及可扩展的Web API 方面的技术,系列文章主要有三篇内容。 主要内容如下: I  数据流 II 使用HTTPS III 可扩展的Web API 文档   项目环境要求 VS 2012(SP4)及以上, .

 

相信已经有很多文章来介绍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 开发项目”

数据流是数据传输中的重要部分,学习了本节内容有助于大家更好地进行ASP.NET的开发。当然,还可以借助一些开发工具来助力开发过程。ComponentOne Studio for ASP.NET 提供了一整套完备的开发工具包,用于在各种浏览器中创建和设计具有现代风格的Web应用程序。

 

下载源代码

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

 

相关文章
|
3天前
|
JSON 搜索推荐 API
Lazada Item_review API接口的开发应用与收益
Lazada作为东南亚领先的电商平台,通过其丰富的API接口为第三方开发者提供了强大的工具。其中,Lazada商品评论列表API(item_review API)尤为重要,能够实时获取商品评论数据,帮助开发者了解用户反馈、优化商品策略、提高购物体验和建立品牌形象,从而在电商行业中实现显著的收益。本文将深入探讨该API的开发应用及其多方面的价值。
35 14
|
5天前
|
供应链 搜索推荐 安全
唯品会Vip商品详情 API 接口:开发应用与收益深度剖析
唯品会Vip商品详情API接口,作为电商数据交互的枢纽,提供详尽的商品信息与动态数据,助力开发者、商家及市场分析者洞察市场趋势、优化商品推荐、提升用户体验,从而实现销售额增长、利润空间拓展及用户忠诚度加固,推动电商行业创新发展。
39 16
|
3天前
|
搜索推荐 数据挖掘 API
Suning商品详情API接口的开发应用与收益
在电商迅猛发展的时代,API接口技术成为连接不同系统的桥梁,为电商平台提供高效的数据交换能力。苏宁易购的商品详情API接口,为商家和开发者带来诸多便利和收益,包括商品信息获取、选品上架、竞品分析、个性化推荐、自动化管理和运营效率提升等方面,助力商家优化销售策略,提高用户体验,降低运营成本,增强市场竞争力,促进业务创新。
30 2
|
7天前
|
Kubernetes 安全 Devops
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
29 10
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
|
2天前
|
供应链 搜索推荐 API
Walgreens商品详情API接口的开发应用与收益
在数字化时代,API成为连接不同系统和服务的桥梁。Walgreens通过开放其商品详情API接口,为开发者提供了丰富的数据源,支持商品搜索、个性化推荐、价格比较、库存管理等应用,创造了新的商业机会和收益模式。本文将深入探讨Walgreens商品详情API接口的开发应用及其多重收益。
19 5
|
1天前
|
监控 搜索推荐 API
京东商品详情API接口的开发、应用与收益探索
在数字化和互联网高速发展的时代,京东通过开放商品详情API接口,为开发者、企业和商家提供了丰富的数据源和创新空间。本文将探讨该API接口的开发背景、流程、应用场景及带来的多重收益,包括促进生态系统建设、提升数据利用效率和推动数字化转型等。
13 3
|
6天前
|
供应链 搜索推荐 API
探索1688榜单商品详细信息API接口:开发、应用与收益
本文深入探讨了1688榜单商品详细信息API接口的开发与应用,涵盖接口概述、开发条件、调用方法及数据处理等内容。该API帮助企业高效获取1688平台商品信息,应用于商品信息采集、校验、同步与数据分析等领域,有效提升了企业的运营效率、库存管理、销售转化率及市场策略制定能力,降低了采购成本,提升了客户满意度。
31 9
|
8天前
|
数据可视化 搜索推荐 API
速卖通获得aliexpress商品详情API接口的开发、应用与收益。
速卖通(AliExpress)作为阿里巴巴旗下的跨境电商平台,为全球消费者提供丰富商品。其开放平台提供的API接口支持开发者获取商品详情等信息,本文探讨了速卖通商品详情API的开发流程、应用场景及潜在收益,包括提高运营效率、降低成本、增加收入和提升竞争力等方面。
24 1
|
13天前
|
机器学习/深度学习 搜索推荐 API
淘宝/天猫按图搜索(拍立淘)API的深度解析与应用实践
在数字化时代,电商行业迅速发展,个性化、便捷性和高效性成为消费者新需求。淘宝/天猫推出的拍立淘API,利用图像识别技术,提供精准的购物搜索体验。本文深入探讨其原理、优势、应用场景及实现方法,助力电商技术和用户体验提升。
|
14天前
|
供应链 监控 搜索推荐
获得1688商品评论API接口的开发应用与收益
1688商品评论API接口提供丰富的商品评论数据,涵盖评论内容、用户信息、商品评分等,助力电商平台优化运营、市场分析和供应链管理,提升客户满意度与忠诚度,促进商业价值增长。
33 3