ASP.NET Web API 2 的返回结果
原文地址:https://www.cnblogs.com/xgzh/p/11208611.html
HttpResponseMessage
HttpResponseMessage是ASP.NET Web API 的标准返回值可以直接将转换为 HTTP 响应消息,那为什么我们不推荐使用HttpResponseMessage,主要是因为用起来比较麻烦,当然HttpResponseMessage提供大量控制的响应消息用来操作设置的缓存控制标头。为什么说HttpResponseMessage是ASP.NET Web API 的标准返回值,最后再讲,先看看如何使用HttpResponseMessage作为返回值。
public HttpResponseMessage Get()
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Accepted, "value");
//设置内容和编码
response.Content = new StringContent("Link sucess", Encoding.BigEndianUnicode);
response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromMinutes(10),//设置缓存
};
return response;
}
HTTP 响应:
HTTP/1.1 202 Accepted
Cache-Control: max-age=1200
Content-Length: 22
Content-Type: text/plain; charset=utf-16
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RTpcZ2l0SHViXFdlYkFQSVN0dWR5QXBwbGljYXRpb25cV2ViQVBJU3R1ZHlBcHBsaWNhdGlvblxhcGlcUmV0dXJuVmFsdWU=?=
X-Powered-By: ASP.NET
HttpResponseMessage作为返回值使用的太少,我除了下载文件外基本没用到过,
public HttpResponseMessage DownloadFile(string filename)
{
string filePath = HttpContext.Current.Server.MapPath("/") + "Files\\" + filename;
FileStream stream = new FileStream(filePath, FileMode.Open);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = HttpUtility.UrlEncode(fileName)
};
response.Headers.Add("Access-Control-Expose-Headers", "FileName");
response.Headers.Add("FileName", HttpUtility.UrlEncode(fileName));
return response;
}
IHttpActionResult
IHttpActionResult Web API 2 中引入了接口。 从根本上来说,用于将其他类型的值转换为HttpResponseMessage类型值的工厂。果控制器操作返回IHttpActionResult,Web API 调用ExecuteAsync方法创建HttpResponseMessage。 然后它会将转换HttpResponseMessage到 HTTP 响应消息。我个人比较用的多。使用IHttpActionResult:
- 测试时更加简单方便。
- 在单独的类创建 HTTP 响应的常见逻辑,响应的内容为HttpResponseMessage。
- 通过隐藏构造响应的低级细节,使控制器操作的意图更加清晰。
下面是一个和返回值为void一样功能的VoiResult,该类实现了IHttpActionResult仅返回状态代码 204 (无内容) 的空 HTTP 响应。
/// <summary>
/// 一个无响应内容的响应信息
/// </summary>
public class VoidResult : IHttpActionResult
{
HttpRequestMessage request;
public VoidResult(HttpRequestMessage httpRequest)
{
this.request = httpRequest;
}
public VoidResult(ApiController controller)
{
this.request = controller.Request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult<HttpResponseMessage>(new HttpResponseMessage(HttpStatusCode.NoContent) { RequestMessage = request });
}
}
调用代码:
public IHttpActionResult Get()
{
return new VoidResult(Request);
}
HTTP 响应:
HTTP/1.1 204 No Content
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RTpcZ2l0SHViXFdlYkFQSVN0dWR5QXBwbGljYXRpb25cV2ViQVBJU3R1ZHlBcHBsaWNhdGlvblxhcGlcUmV0dXJuVmFsdWU=?=
X-Powered-By: ASP.NET
该示例说明了通过IHttpActionResult来构造响应的具体细节,使控制器操作的意图更加清晰和复用。
IHttpActionResult包含一个方法ExecuteAsync,以便以异步方式创建HttpResponseMessage实例。
public interface IHttpActionResult
{
Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken);
}
如果控制器操作返回IHttpActionResult,Web API 调用ExecuteAsync方法创建HttpResponseMessage。 然后它会将转换HttpResponseMessage到 HTTP 响应消息。一般情况下我们只需要使用ApiController类内置的方法即可,方法内生成的instance定义在System.Web.Http.Results下。
方法 | 实例的类名 | 响应信息 | 响应内容 |
---|---|---|---|
OK() | OKResult | 200 (正常) | 无 |
Ok |
OkNegotiatedContentResult | 200 (正常 | 序列化的结果 |
Json |
JsonResult | 200 | Json序列化的结果 |
Json |
JsonResult | 200 | Json序列化的结果 |
NotFound() | NotFoundResult | 404 | |
Redirect(..) | RedirectResult | 跳转 | |
RedirectToRoute(...) | RedirectToRouteResult | 跳转 | |
ResponseMessage(HttpResponseMessage response) | ResponseMessageResult | [别用浪费资源] | |
StatusCode(HttpStatusCode status) | StatusCodeResult | 输入的状态码 | 无 |
Unauthorized(params AuthenticationHeaderValue[] challenges) | UnauthorizedResult | 401 | 未授权的信息明细 |
void
如果Web API Action返回类型为void,Web API 仅返回状态代码 204 (无内容) 的空 HTTP 响应。
[HttpGet]
public void Test()
{
//连接测试
}
HTTP 响应:
HTTP/1.1 204 No Content
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RTpcLk5FVCBNVkMgIEFDRSBhZG1pblxXZWJcYXBpXEF1dGhvcml6YXRpb24=?=
X-Powered-By: ASP.NET
某些其他类型
对于所有其他返回类型,Web API 使用媒体格式化程序要序列化的返回值。 Web API 将序列化的值写入到响应正文。 响应状态代码为 200 (正常)。似乎所有类型都可以作为返回值,其实不然。再说这一问题前线看看什么样的实例能作为返回值。
- 值类型但是其值为null,可空的值不在其范围内例如(int不可以返回null, Nullable
也就是int?是可以返回为null的) - 类型不是泛型并且也不是Nullable<>类型的null实例不能做为返回值。
- 不能被赋值给新实例的实例不能作为返回值
某些其他类型返回值的控制器最终回传的是什么格式的数据:回执的数据格式决定在于请求的Accept参数的第一个格式(不包括txt,如果是/则返回Json)或者是在Global.asax里的设置或被调用的设置。
Produce[] produces = new Produce[] {
new Produce{id=1,Name="自动化测试3",Price=11.2},
new Produce{id=2,Name="自动化测试2",Price=12.2 },
new Produce{id=3,Name="自动化测试2",Price=13.2 }
};
[HttpGet]
public Produce[] Test()
{
return produces;
}
HTTP 响应:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RTpcLk5FVCBNVkMgIEFDRSBhZG1pblxXZWJcYXBpXEF1dGhvcml6YXRpb24=?=
X-Powered-By: ASP.NET
数据内容为:
[{"id":1,"Name":"自动化测试3","Price":11.2},{"id":2,"Name":"自动化测试2","Price":12.2},{"id":3,"Name":"自动化测试2","Price":13.2}]
既然那么多的数据类型都可以作为返回值,那么执行Web Api是怎么处理返回值的呢?我们通过查看源码可以直到,最终是由ApiControllerActionInvoker.InvokeActionAsyncCore 来执行Action的。在InvokeActionAsyncCore可中将返回值作为以下几类处理
- IHttpActionResult:该类型直接调用ExecuteAsync方法来获取一个HttpResponseMessage实例,将该实例返回;
- HttpResponseMessage:将实例设置RequestMessage后直接返回
- void: 返回一个新的HttpResponseMessage实例,设置其HttpStatusCode为NoContent
- 不在上述类型中的类型:返回一个新的HttpResponseMessage实例,设置其HttpStatusCode为NoContent,Content为ObjectContent<T >。
总结归纳
- WEB API2 的最终返回值的类型为HttpResponseMessage,其他的返回值类型会经过一系列的处理形成一个HttpResponseMessage实例。
- 除了返回JsonResult实例返回的数据格式是Json外,其他的返回格式按请求或者设置而定。