現在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