现在webapi越来越流行了,很多时候它都用来做接口返回json格式的数据,webapi原本是根据客户端的类型动态序列化为json和xml的,但实际很多时候我们都是序列化为json的,所以webapi的序列化比我们用ServiceStack.Text序列化要多花费一些时间,还有如果返回的数据量比较大那么我们应该启动gzip和deflate压缩。而这些实现都不得影响现有的code, 我个人喜欢同时也是习惯用特性来完成压缩和json格式化。
1.压缩的code:
namespace MvcApp { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Web; using System.Web.Http.Filters; using System.IO.Compression; using System.Net.Http; public class CompressAttribute : ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { var content = actionExecutedContext.Response.Content; var acceptEncoding = actionExecutedContext.Request.Headers.AcceptEncoding.Where(x => x.Value == "gzip" || x.Value == "deflate").ToList(); if (acceptEncoding != null && acceptEncoding.Count > 0 && content != null && actionExecutedContext.Request.Method != HttpMethod.Options) { var bytes = content.ReadAsByteArrayAsync().Result; if (acceptEncoding.FirstOrDefault().Value == "gzip") { actionExecutedContext.Response.Content = new ByteArrayContent(CompressionHelper.GzipCompress(bytes)); actionExecutedContext.Response.Content.Headers.Add("Content-Encoding", "gzip"); } else if (acceptEncoding.FirstOrDefault().Value == "deflate") { actionExecutedContext.Response.Content = new ByteArrayContent(CompressionHelper.DeflateCompress(bytes)); actionExecutedContext.Response.Content.Headers.Add("Content-encoding", "deflate"); } } base.OnActionExecuted(actionExecutedContext); } } class CompressionHelper { public static byte[] DeflateCompress(byte[] data) { if (data == null || data.Length < 1) return data; try { using (MemoryStream stream = new MemoryStream()) { using (DeflateStream gZipStream = new DeflateStream(stream, CompressionMode.Compress)) { gZipStream.Write(data, 0, data.Length); gZipStream.Close(); } return stream.ToArray(); } } catch (Exception) { return data; } } public static byte[] GzipCompress(byte[] data) { if (data == null || data.Length < 1) return data; try { using (MemoryStream stream = new MemoryStream()) { using (GZipStream gZipStream = new GZipStream(stream, CompressionMode.Compress)) { gZipStream.Write(data, 0, data.Length); gZipStream.Close(); } return stream.ToArray(); } } catch (Exception) { return data; } } } }
首先判断客户端是否启动gzip,deflate压缩,如果启用并且请求类型不是Options同时又返回数据,那么我们就压缩返回数据。至于用gzip还是deflate那就看客户端接受的一个压缩是gzip,deflate?
2.json
如下:
public IEnumerable<Users> Get()
{
return _userList;
}
很多时候我们会把这个api的返回类型改为HttpResponseMessage同时序列化为json格式的数据,写成一个通用的方法大家来调用。我推荐的实现方式采用Attribute来做。
相关code:
namespace MvcApp { using ServiceStack.Text; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Reflection; using System.Text; using System.Web; using System.Web.Http.Controllers; using System.Web.Http.Filters; public class JsonResultConverterAttribute : ActionFilterAttribute { public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) { //actionContext.ActionDescriptor.ResultConverter ; var actionDescriptor = actionContext.ActionDescriptor; var field = typeof(HttpActionDescriptor).GetField("_converter", BindingFlags.NonPublic | BindingFlags.Instance); if (field != null) { field.SetValue(actionDescriptor, new JsonResultConverter()); //actionDescriptor.ReturnType = typeof(HttpResponseMessage); } var test = actionDescriptor.ResultConverter; base.OnActionExecuting(actionContext); } } public class JsonResultConverter : IActionResultConverter { public HttpResponseMessage Convert(HttpControllerContext controllerContext, object actionResult) { if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } HttpResponseMessage resultAsResponse = actionResult as HttpResponseMessage; if (resultAsResponse != null) { // resultAsResponse.EnsureResponseHasRequest(controllerContext.Request); return resultAsResponse; } string jsonResult = TypeSerializer.SerializeToString(actionResult); var content = new StringContent(jsonResult, Encoding.UTF8, "application/json"); return controllerContext.Request.CreateResponse(HttpStatusCode.OK, jsonResult); } } }
注意HttpActionDescriptor的私有字段_converter在ResultConverter属性中暴露出来,遗憾的是是个只读属性,所以我们需要用反射来设置它的value(实现IActionResultConverter接口)。
运行结果我也就不贴图了,代码下载地址:http://download.csdn.net/detail/dz45693/9486586