博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET Web API 应用教程(一) ——数据流使用
阅读量:5976 次
发布时间:2019-06-20

本文共 16735 字,大约阅读时间需要 55 分钟。

 

相信已经有很多文章来介绍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:  /// 
2:  /// File streaming API
3:  /// 
4:  [RoutePrefix("filestreaming")]
5:  [RequestModelValidator]
6:  public class StreamFilesController : ApiController
7:  {
8:      /// 
9:      /// Get File meta data
10:      /// 
11:      /// FileName value
12:      /// 
FileMeta data response.
13:      [Route("getfilemetadata")]
14:      public HttpResponseMessage GetFileMetaData(string fileName)
15:      {
16:          // .........................................
17:          // Full code available in the source control
18:          // .........................................
19:   
20:      }
21:   
22:      /// 
23:      /// Search file and return its meta data in all download directories
24:      /// 
25:      /// FileName value
26:      /// 
List of file meta datas response
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:      /// 
37:      /// Asynchronous Download file
38:      /// 
39:      /// FileName value
40:      /// 
Tasked File stream response
41:      [Route("downloadasync")]
42:      [HttpGet]
43:      public async Task
DownloadFileAsync(string fileName)
44:      {
45:          // .........................................
46:          // Full code available in the source control
47:          // .........................................
48:      }
49:   
50:      /// 
51:      /// Download file
52:      /// 
53:      /// FileName value
54:      /// 
File stream response
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:      /// 
65:      /// Upload file(s)
66:      /// 
67:      /// An indicator to overwrite a file if it exist in the server
68:      /// 
Message response
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:      /// 
79:      /// Asynchronous Upload file
80:      /// 
81:      /// An indicator to overwrite a file if it exist in the server
82:      /// 
Tasked Message response
83:      [Route("uploadasync")]
84:      [HttpPost]
85:      public async Task
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:  /// 
2:  /// Download file
3:  /// 
4:  /// FileName value
5:  /// 
File stream response
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:  /// 
2:  /// Upload file(s)
3:  /// 
4:  /// An indicator to overwrite a file if it exist in the server.
5:  /// 
Message response
6:  [Route("upload")]
7:  [HttpPost]
8:  public HttpResponseMessage UploadFile(bool overWrite)
9:  {
10:      HttpResponseMessage response = Request.CreateResponse();
11:      List
fileResponseMessages = new List
();
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:  /// 
41:  /// Asynchronous Upload file
42:  /// 
43:  /// An indicator to overwrite a file if it exist in the server.
44:  /// 
Tasked Message response
45:  [Route("uploadasync")]
46:  [HttpPost]
47:  public async Task
UploadFileAsync(bool overWrite)
48:  {
49:      return await new TaskFactory().StartNew(
50:         () =>
51:         {
52:             return UploadFile(overWrite);
53:         });
54:  }
55:   
56:  /// 
57:  /// Process upload request in the server
58:  /// 
59:  /// An indicator to overwrite a file if it exist in the server.
60:  /// List of message object
61:  private HttpResponseMessage ProcessUploadRequest(bool overWrite)
62:  {
63:      // .........................................
64:      // Full code available in the source control
65:      // .........................................
66:  }

调用download 及 upload 文件方法是控制台应用,App 假定文件流服务通过HttpClient和相关类。基本下载文件代码,创建下载HTTP 请求对象。

1:  /// 
2:  /// Download file
3:  /// 
4:  /// 
Awaitable Task object
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:  /// 
52:  /// Process download response object
53:  /// 
54:  /// Local download file path
55:  /// An indicator to overwrite a file if it exist in the client.
56:  /// Awaitable HttpResponseMessage task value
57:  private static void ProcessDownloadResponse(string localDownloadFilePath, bool overWrite,
58:      Task
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:  /// 
2:  /// Upload file
3:  /// 
4:  /// 
Awaitable task object
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:  /// 
68:  /// Process download response object
69:  /// 
70:  /// Awaitable HttpResponseMessage task value
71:  private static void ProcessUploadResponse(Task
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
>().TryResult(), Formatting.Indented)));
81:      }
82:      else
83:      {
84:          ProcessFailResponse(response);
85:      }
86:  }

 

数据流项目由可扩展类和方法组成,本文就不再详述。下篇文章中将介绍“使用HTTPS 开发项目”

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

 

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

 

转载地址:http://yapox.baihongyu.com/

你可能感兴趣的文章
Scrapy框架的基本使用
查看>>
ActionResult,PartialViewResult,EmptyResult,ContentResult
查看>>
关于泛型类,泛型接口,泛型函数
查看>>
@pathvariable和@RequestParam的区别
查看>>
测试驱动开发
查看>>
C++操作符重载
查看>>
Redis实现分布式锁2
查看>>
【Udacity】线性回归方程 Regression
查看>>
前端架构设计1:代码核心
查看>>
RPC 框架通俗解释 转自知乎(洪春涛)
查看>>
获取cookie后,使用cookie进行接下来的自动化操作
查看>>
算法笔记--数论模板小集(待增)
查看>>
SASS初学者入门(转)
查看>>
C语言100个算法经典例题(七)
查看>>
轻松实现远程批量拷贝文件脚本(女学生作品)
查看>>
Nmap在pentest box中的扫描及应用
查看>>
测试组合索引
查看>>
四、物理优化(2)索引视图
查看>>
【沟通之道】头脑风暴-女人的心思你别猜
查看>>
钱趣多风控新举措:源头选择与物理隔离
查看>>