Asp.NetWebAPi gzip圧縮とjsonフォーマット

14786 ワード

現在、webapiはますます流行しており、インタフェースとしてjson形式のデータを返すために使用されることが多い.webapiはもともとクライアントのタイプに応じて動的にjsonとxmlにシーケンス化されていたが、実際にはjsonにシーケンス化されていることが多いので、webapiのシーケンス化は私たちがServiceStackを使うよりも優れている.Textシーケンス化には時間がかかります.また、返されるデータ量が大きい場合はgzipとdeflate圧縮を開始する必要があります.これらの実装は既存のcodeに影響を与えないで、私個人は同時に特性で圧縮とjsonフォーマットを完成するのが好きです.
1.圧縮コード:
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 Get() { return _userList; }
多くの場合、このapiの戻りタイプをHttpResponseMessageに変更し、json形式のデータを同時にシーケンス化し、一般的な方法としてみんなで呼び出すことができます.私がお勧めする実現方法はAttributeを採用しています.
関連コード:
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