您的位置:首页 > 编程语言 > ASP

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文件中查寻

本文涉及的知识点

ActionFilter

AuthorizationFilter

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(HttpDelete
)或Get([code]HttpGet)方法同时调用,从某种程度来说,HTTP方法使开发人员命名API“方法”变得简单而标准。[/code]

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在requestFiltering部分配置下正确设置,默认值为30MB,最大值4GB




一旦完成预先配置,那么创建数据流服务就非常简单了,首先需要定义文件流“[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的开发。当然,还可以借助一些开发工具来助力开发过程。ComponentOneStudioforASP.NET提供了一整套完备的开发工具包,用于在各种浏览器中创建和设计具有现代风格的Web应用程序。

下载源代码

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

原文链接:http://www.cnblogs.com/powertoolsteam/p/5029475.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
章节导航