ASP.NET Web API 应用教程(一) ——数据流使用
2016-07-12 09:38
691 查看
相信已经有很多文章来介绍ASP.NetWebAPI技术,本系列文章主要介绍如何使用数据流,HTTPS,以及可扩展的WebAPI方面的技术,系列文章主要有三篇内容。
主要内容如下:
I数据流
II使用HTTPS
III可扩展的WebAPI文档
项目环境要求
VS2012(SP4)及以上,.Net框架4.5.1
Nuget包,可在packages.config文件中查寻
本文涉及的知识点
ActionFilterAuthorizationFilter
DelegateHandler
DifferentWebAPIrouting属性
MediaTypeFormatter
OWIN
SelfHosting
WebAPI文档及可扩展功能
.Net框架
Async/Await
.NETreflection
Serialization
ASP.NETWebAPI/MVCErrorhandling
IIS,HTTPS及Certificate
设计准则及技术
前言
自从ASP.NETMVC4之后.Net框架开始支持ASP.NETWebAPI,ASP.NETWebAPI基于HTTP协议建立的,是构建RESTful服务和处理数据的理想平台,旨在使用HTTP技术实现对多平台的支持。
ASP.NETWebAPI以request-response的消息转换模式为主,客户端向服务器发送请求,服务器端响应客户端请求。响应可同步或异步。
个人认为使用WebAPI创建应用需要注意的三个关键点:
采用服务及方法满足的目标
每个方法的输入,如请求
每个方法的输出,如响应
通常情况下,Asp.NetWebAPI定义method语法与HTTP方法一一对应的,如自定义方法名
GetPysicians(),则与HTTP中Get方法匹配。下图是常用匹配表。
但是此方法在很多情况下,并不实用,假如你想在单个APIcontroller类中定义多个Get或Post方法,在这种情况下,需要定义包含action的路径,将Action作为URI的一部分。以下是配置代码:
publicstaticvoidRegister(HttpConfigurationconfig)
[code]{
//WebAPIconfigurationandservices
//WebAPIroutes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(name:"PhysicianApi",
routeTemplate:"{controller}/{action}/{id}",
defaults:new{id=RouteParameter.Optional});
}
[/code]
但是此方法不足以应对所有情况,如果想实现从中央仓库删除文件,并且想调用同一个方法来获取文件,这种情况下,WebAPI框架需要伪装Get及Delete对应的HTTP方法属性。如图所示:
RemoveFile方法可被Delete()或Get([code]HttpGet)方法同时调用,从某种程度来说,HTTP方法使开发人员命名API“方法”变得简单而标准。[/code]HttpDelete
WebAPI框架也提供了一些其他功能来处理路径方面的问题,与MVC的路径处理方法相似。因此可定义不同类型的Action方法。
数据流
网络App最常见的执行操作就是获取数据流。ASP.NETWebAPI能够处理客户端与服务器端传输的重量级的数据流,数据流可来源于目录文件,也可是数据库中的二进制文件。本文主要介绍两种方法“Download”和“Upload”实现数据流相关的功能,Download是从服务器下载数据操作,而Upload则是上传数据到服务器。
相关项目
WebAPIDataStreaming
WebAPIClient
POCOLibrary
在对代码解释之前,首先来了解如何配置IIS(7.5)和WebAPI服务Web.Config文件。
1.保证Downloads/Uploads涉及的文件具有读写权限。
2.保证有足够容量的内容或因公安空间处理大文件。
3.如果文件较大
a.配置Web.Config文件时,保证maxRequestLength时响应时间 executionTimeout合理。具体的值主要依赖于数据大小,允许一次性上传的最大数据为2GB
b.保证[code]maxAllowedContentLength在
一旦完成预先配置,那么创建数据流服务就非常简单了,首先需要定义文件流“[code]ApiController”,如下:
///<summary>
[code]///FilestreamingAPI
///</summary>
[RoutePrefix("filestreaming")]
[RequestModelValidator]
publicclassStreamFilesController:ApiController
{
///<summary>
///GetFilemetadata
///</summary>
///<paramname="fileName">FileNamevalue</param>
///<returns>FileMetadataresponse.</returns>
[Route("getfilemetadata")]
publicHttpResponseMessageGetFileMetaData(stringfileName)
{
//.........................................
//Fullcodeavailableinthesourcecontrol
//.........................................
}
///<summary>
///Searchfileandreturnitsmetadatainalldownloaddirectories
///</summary>
///<paramname="fileName">FileNamevalue</param>
///<returns>Listoffilemetadatasresponse</returns>
[HttpGet]
[Route("searchfileindownloaddirectory")]
publicHttpResponseMessageSearchFileInDownloadDirectory(stringfileName)
{
//.........................................
//Fullcodeavailableinthesourcecontrol
//.........................................
}
///<summary>
///AsynchronousDownloadfile
///</summary>
///<paramname="fileName">FileNamevalue</param>
///<returns>TaskedFilestreamresponse</returns>
[Route("downloadasync")]
[HttpGet]
publicasyncTask<HttpResponseMessage>DownloadFileAsync(stringfileName)
{
//.........................................
//Fullcodeavailableinthesourcecontrol
//.........................................
}
///<summary>
///Downloadfile
///</summary>
///<paramname="fileName">FileNamevalue</param>
///<returns>Filestreamresponse</returns>
[Route("download")]
[HttpGet]
publicHttpResponseMessageDownloadFile(stringfileName)
{
//.........................................
//Fullcodeavailableinthesourcecontrol
//.........................................
}
///<summary>
///Uploadfile(s)
///</summary>
///<paramname="overWrite">Anindicatortooverwriteafileifitexistintheserver</param>
///<returns>Messageresponse</returns>
[Route("upload")]
[HttpPost]
publicHttpResponseMessageUploadFile(booloverWrite)
{
//.........................................
//Fullcodeavailableinthesourcecontrol
//.........................................
}
///<summary>
///AsynchronousUploadfile
///</summary>
///<paramname="overWrite">Anindicatortooverwriteafileifitexistintheserver</param>
///<returns>TaskedMessageresponse</returns>
[Route("uploadasync")]
[HttpPost]
publicasyncTask<HttpResponseMessage>UploadFileAsync(booloverWrite)
{
//.........................................
//Fullcodeavailableinthesourcecontrol
//.........................................
}
}
[/code]
Download服务方法首先需要确认请求的文件是否存在,如果未找到,则返回错误提示“fileisnotfound”,如果找到此文件,内容则转换为字节附加到响应对象,为“application/octet-stream”MIMI内容类型。
///<summary>
[code]///Downloadfile
///</summary>
///<paramname="fileName">FileNamevalue<param>
///<returns>Filestreamresponse<returns>
[Route("download")]
[HttpGet]
publicHttpResponseMessageDownloadFile(stringfileName)
{
HttpResponseMessageresponse=Request.CreateResponse();
FileMetaDatametaData=newFileMetaData();
try
{
stringfilePath=Path.Combine(this.GetDownloadPath(),@"\",fileName);
FileInfofileInfo=newFileInfo(filePath);
if(!fileInfo.Exists)
{
metaData.FileResponseMessage.IsExists=false;
metaData.FileResponseMessage.Content=string.Format("{0}fileisnotfound!",fileName);
response=Request.CreateResponse(HttpStatusCode.NotFound,metaData,newMediaTypeHeaderValue("text/json"));
}
else
{
response.Headers.AcceptRanges.Add("bytes");
response.StatusCode=HttpStatusCode.OK;
response.Content=newStreamContent(fileInfo.ReadStream());
response.Content.Headers.ContentDisposition=newContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName=fileName;
response.Content.Headers.ContentType=newMediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentLength=fileInfo.Length;
}
}
catch(Exceptionexception)
{
//Logexceptionandreturngracefully
metaData=newFileMetaData();
metaData.FileResponseMessage.Content=ProcessException(exception);
response=Request.CreateResponse(HttpStatusCode.InternalServerError,metaData,newMediaTypeHeaderValue("text/json"));
}
returnresponse;
}
[/code]
Upload服务方法则会在multipart/form-dataMIMI内容类型执行,首先会检测HTTP请求的内容类型是否是多主体,如果是,则对比内容长度是否超过最大尺寸,如果没有超过,则开始上传内容,当操作完成之后,则提示相应的信息。
代码片段如下:
[code]///<summary>
[code]///Uploadfile(s)
///</summary>
///<paramname="overWrite">Anindicatortooverwriteafileifitexistintheserver.</param>
///<returns>Messageresponse</returns>
[Route("upload")]
[HttpPost]
publicHttpResponseMessageUploadFile(booloverWrite)
{
HttpResponseMessageresponse=Request.CreateResponse();
List<FileResponseMessage>fileResponseMessages=newList<FileResponseMessage>();
FileResponseMessagefileResponseMessage=newFileResponseMessage{IsExists=false};
try
{
if(!Request.Content.IsMimeMultipartContent())
{
fileResponseMessage.Content="Uploaddatarequestisnotvalid!";
fileResponseMessages.Add(fileResponseMessage);
response=Request.CreateResponse(HttpStatusCode.UnsupportedMediaType,fileResponseMessages,newMediaTypeHeaderValue("text/json"));
}
else
{
response=ProcessUploadRequest(overWrite);
}
}
catch(Exceptionexception)
{
//Logexceptionandreturngracefully
fileResponseMessage=newFileResponseMessage{IsExists=false};
fileResponseMessage.Content=ProcessException(exception);
fileResponseMessages.Add(fileResponseMessage);
response=Request.CreateResponse(HttpStatusCode.InternalServerError,fileResponseMessages,newMediaTypeHeaderValue("text/json"));
}
returnresponse;
}
///<summary>
///AsynchronousUploadfile
///</summary>
///<paramname="overWrite">Anindicatortooverwriteafileifitexistintheserver.<param>
///<returns>TaskedMessageresponse</returns>
[Route("uploadasync")]
[HttpPost]
publicasyncTask<HttpResponseMessage>UploadFileAsync(booloverWrite)
{
returnawaitnewTaskFactory().StartNew(
()=>
{
returnUploadFile(overWrite);
});
}
///<summary>
///Processuploadrequestintheserver
///</summary>
///<paramname="overWrite">Anindicatortooverwriteafileifitexistintheserver.</param>
///</returns>Listofmessageobject</returns>
privateHttpResponseMessageProcessUploadRequest(booloverWrite)
{
//.........................................
//Fullcodeavailableinthesourcecontrol
//.........................................
}
[/code]
调用download及upload文件方法是控制台应用,App假定文件流服务通过HttpClient和相关类。基本下载文件代码,创建下载HTTP请求对象。
///<summary>
[code]///Downloadfile
///</summary>
///<returns>AwaitableTaskobject</returns>
privatestaticasyncTaskDownloadFile()
{
Console.ForegroundColor=ConsoleColor.Green;
Console.WriteLine("PleasespecifyfilenamewithextensionandPressEnter:-");
stringfileName=Console.ReadLine();
stringlocalDownloadPath=string.Concat(@"c:\",fileName);//thepathcanbeconfigurable
booloverWrite=true;
stringactionURL=string.Concat("downloadasync?fileName=",fileName);
try
{
Console.WriteLine(string.Format("Startdownloading@{0},{1}time",
DateTime.Now.ToLongDateString(),
DateTime.Now.ToLongTimeString()));
using(HttpClienthttpClient=newHttpClient())
{
httpClient.BaseAddress=baseStreamingURL;
HttpRequestMessagerequest=newHttpRequestMessage(HttpMethod.Get,actionURL);
awaithttpClient.SendAsync(request,HttpCompletionOption.ResponseHeadersRead).
ContinueWith((response)
=>
{
Console.WriteLine();
try
{
ProcessDownloadResponse(localDownloadPath,overWrite,response);
}
catch(AggregateExceptionaggregateException)
{
Console.ForegroundColor=ConsoleColor.Red;
Console.WriteLine(string.Format("Exception:",aggregateException));
}
});
}
}
catch(Exceptionex)
{
Console.ForegroundColor=ConsoleColor.Red;
Console.WriteLine(ex.Message);
}
}
///<summary>
///Processdownloadresponseobject
///</summary>
///<paramname="localDownloadFilePath">Localdownloadfilepath</param>
///<paramname="overWrite">Anindicatortooverwriteafileifitexistintheclient.</param>
///<paramname="response">AwaitableHttpResponseMessagetaskvalue</param>
privatestaticvoidProcessDownloadResponse(stringlocalDownloadFilePath,booloverWrite,
Task<HttpResponseMessage>response)
{
if(response.Result.IsSuccessStatusCode)
{
response.Result.Content.DownloadFile(localDownloadFilePath,overWrite).
ContinueWith((downloadmessage)
=>
{
Console.ForegroundColor=ConsoleColor.Green;
Console.WriteLine(downloadmessage.TryResult());
});
}
else
{
ProcessFailResponse(response);
}
}
[/code]
注意上述代码中HttpClient对象发送请求,并等待响应发送Header内容(HttpCompletionOption.ResponseHeadersRead)。而不是发送全部的响应内容文件。一旦Responseheader被读,则执行验证,一旦验证成功,则执行下载方法。
以下代码调用upload文件流,与下载方法类似,创建多主体表单数据,并发送给服务器端。
///<summary>
[code]///Uploadfile
///</summary>
///<returns>Awaitabletaskobject</returns>
privatestaticasyncTaskUploadFile()
{
try
{
stringuploadRequestURI="uploadasync?overWrite=true";
MultipartFormDataContentformDataContent=newMultipartFormDataContent();
//ValidatethefileandaddtoMultipartFormDataContentobject
formDataContent.AddUploadFile(@"c:\nophoto.png");
formDataContent.AddUploadFile(@"c:\ReadMe.txt");
if(!formDataContent.HasContent())//Nofilesfoundtobeuploaded
{
Console.ForegroundColor=ConsoleColor.Red;
Console.Write(formDataContent.GetUploadFileErrorMesage());
return;
}
else
{
stringuploadErrorMessage=formDataContent.GetUploadFileErrorMesage();
if(!string.IsNullOrWhiteSpace(uploadErrorMessage))//Somefilescouldn'tbefound
{
Console.ForegroundColor=ConsoleColor.Red;
Console.Write(uploadErrorMessage);
}
HttpRequestMessagerequest=newHttpRequestMessage(HttpMethod.Post,uploadRequestURI);
request.Content=formDataContent;
using(HttpClienthttpClient=newHttpClient())
{
Console.ForegroundColor=ConsoleColor.Green;
Console.WriteLine(string.Format("Startuploading@{0},{1}time",
DateTime.Now.ToLongDateString(),
DateTime.Now.ToLongTimeString()));
httpClient.BaseAddress=baseStreamingURL;
awaithttpClient.SendAsync(request).
ContinueWith((response)
=>
{
try
{
ProcessUploadResponse(response);
}
catch(AggregateExceptionaggregateException)
{
Console.ForegroundColor=ConsoleColor.Red;
Console.WriteLine(string.Format("Exception:",aggregateException));
}
});
}
}
}
catch(Exceptionex)
{
Console.ForegroundColor=ConsoleColor.Red;
Console.WriteLine(ex.Message);
}
}
///<summary>
///Processdownloadresponseobject
///</summary>
///<paramname="response">AwaitableHttpResponseMessagetaskvalue</param>
privatestaticvoidProcessUploadResponse(Task<HttpResponseMessage>response)
{
if(response.Result.IsSuccessStatusCode)
{
stringuploadMessage=string.Format("\nUploadcompleted@{0},{1}time",
DateTime.Now.ToLongDateString(),
DateTime.Now.ToLongTimeString());
Console.ForegroundColor=ConsoleColor.Green;
Console.WriteLine(string.Format("{0}\nUploadMessage:\n{1}",uploadMessage,
JsonConvert.SerializeObject(response.Result.Content.ReadAsAsync<List<FileResponseMessage>>().TryResult(),Formatting.Indented)));
}
else
{
ProcessFailResponse(response);
}
}
[/code]
数据流项目由可扩展类和方法组成,本文就不再详述。下篇文章中将介绍“使用HTTPS开发项目”
数据流是数据传输中的重要部分,学习了本节内容有助于大家更好地进行ASP.NET的开发。当然,还可以借助一些开发工具来助力开发过程。
原文链接:http://www.codeproject.com/Articles/838274/Web-API-Thoughts-of-Data-Streaming#Hist
原文链接:http://www.cnblogs.com/powertoolsteam/p/5029475.html
相关文章推荐
- 编译器错误消息: CS1061: “ASP.yemian_reg_aspx”不包含“Button1_Click1”的定义,并且找不到可接受类型为“ASP.yemian_reg_aspx”的第一个参数的
- Spring Mvc那点事---(27)Spring Mvc基于aspect的AOP实现
- ASP.NET MVC随想
- 使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(三)-- Logger
- 用ASP.NET Core 1.0中实现邮件发送功能-阿里云邮件推送篇
- win10x64配置IIS访问asp,能够使用Microsoft.Jet.OLEDB.4.0
- asp与java的结合|!
- ASP.NET MVC学习之路由篇(3)
- ASP.NET MVC学习之路由篇(2)
- 为ASP.NET MVC应用添加自定义路由
- Introduction to ASP.NET Web Programming Using the Razor Syntax (C#)
- ASP.NET MVC学习之路由篇(1)
- Cglib,asm,Aspect,JDK原生的代理模式这四种有哪些差别,原理各是什么?
- ASP.NET MVC学习之控制器篇(二)
- ASP.NET MVC学习之控制器篇
- [转] c# 模拟Asp.net页面中的某个按钮的点击,向web服务器发出请求
- WebForm页面生命周期及asp.net运行机制
- WebForm页面生命周期及asp.net运行机制
- Robi改造计划更新---moveit终于在树莓派raspberry 3B(raspbian<Jessie>, ROS Indigo版本)上安装好了
- Mixing ASP.NET Webforms and ASP.NET MVC