網頁

ASP.NET Web API-取代JsonFormatter新選擇-招喚JilFormatter

ASP.NET Web API-取代JsonFormatter新選擇-招喚JilFormatter

ASP.NET Web API一開始就以JSON.NET來取代JavaScriptSerializer以完成世代交替,JSON.NET的表現一直是中規中矩,以我的認知他是求穩。ASP.NET Web API採用Formatter的設計方式,預設有JsonFormatter與XmlFormatter,在求快的過程,如同頭文字D的86,換上一顆新F1引擎是最快的方式,我們來替ASP.NET Web API安裝一顆JilFormatter的高速引擎。

Jil Media-Type Formatter

    // Ref: https://github.com/bmbsqd/jil-mediaformatter
    // Ref: http://blog.developers.ba/replace-json-net-jil-json-serializer-asp-net-web-api/
    public class JilFormatter : MediaTypeFormatter
    {
        private static readonly MediaTypeHeaderValue applicationJsonMediaType = new MediaTypeHeaderValue("application/json");
        private static readonly MediaTypeHeaderValue textJsonMediaType = new MediaTypeHeaderValue("text/json");
        private static readonly Task<bool> done = Task.FromResult(true);

        private readonly Options options;

        public JilFormatter(Options options)
        {
            this.options = options;
            SupportedMediaTypes.Add(applicationJsonMediaType);
            SupportedMediaTypes.Add(textJsonMediaType);

            SupportedEncodings.Add(new UTF8Encoding(false, true));
            SupportedEncodings.Add(new UnicodeEncoding(false, true, true));
        }

        public JilFormatter() : this( GetDefaultOptions() ) { }

        private static Options GetDefaultOptions()
        {
            return new Options(dateFormat: DateTimeFormat.ISO8601);
        }

        public override bool CanReadType(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            return true;
        }

        public override bool CanWriteType(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            return true;
        }

        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            var reader = new StreamReader(readStream);
            var deserialize = TypedDeserializers.GetTyped(type);
            var result = deserialize(reader, options);
            return Task.FromResult(result);
        }

        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
        {
            var writer = new StreamWriter(writeStream);
            JSON.Serialize(value, writer, options);
            writer.Flush();
            return done;
        }
    }

    static class TypedDeserializers
    {
        private static readonly ConcurrentDictionary<Type, Func<TextReader, Options, object>> methods;
        private static readonly MethodInfo method = typeof(JSON).GetMethod("Deserialize", new[] { typeof(TextReader), typeof(Options) });

        static TypedDeserializers()
        {
            methods = new ConcurrentDictionary<Type, Func<TextReader, Options, object>>();
        }

        public static Func<TextReader, Options, object> GetTyped(Type type)
        {
            return methods.GetOrAdd(type, CreateDelegate);
        }

        private static Func<TextReader, Options, object> CreateDelegate(Type type)
        {
            return (Func<TextReader, Options, object>)method
                .MakeGenericMethod(type)
                .CreateDelegate(typeof(Func<TextReader, Options, object>));
        }
    }  
 

這樣我們就製作好新的JilFormatter。

安裝JilFormatter引擎

開啟WebApiConfig.cs組態檔,將JilFormatter安裝進ASP.NET Web API之中。

 // Replace Jil                                            
 config.Formatters.Remove(config.Formatters.JsonFormatter);
 config.Formatters.Remove(config.Formatters.XmlFormatter); 
 config.Formatters.Add(new JilFormatter());                  
 

這裡我是把ASP.NET Web API兩個預設JsonFormatter與XmlFormatter給移除,並把新的JilFormatter結設定進去。如果你不想一次JsonFormatter與XmlFormatter都給移除,那麼也可以用Insert()的方式來設置:

 config.Formatters.RemoveAt(0);
 config.Formatters.Insert(0, new JilFormatter());  
 

這樣的意思是把index 0的JsonFormatter給移除,並把新的JilFormatter插入至index 0的位置,也就是第一順位使用JilFormatter來執行(反)序列化。

    public IHttpActionResult Get()
    {
        var dt = DateTime.Now;
        return Ok(dt);
    }
 
Web API Jil Datetime test

進行簡單測試,確認序列化日期是正常的。

    public IHttpActionResult Get()
    {
        List  bigList = new User().GenSimData();
        return Ok(bigList);
    }  
 
Web API Jil BigList test

透過之前的評比程式取得2萬筆資料進行序列化測試。再提醒一次,Jil的序列化會進行UTC時區處理,所以資料接收端要進行時區修正的動作。

小結

針對ASP.NET MVC(JsonResult)/Web API的效能提升,換上一顆高效的JSON(反)序列化處理引擎,尤其是ASP.NET Web API本身就是專門針對JSON格式所設計的Framework,在效能改善上有著非常正能量的幫助。

Github Sample Source code:KK.JilTest

系列文章

  1. JSON(反)序列化之唯快不破新選擇-Jil
  2. ASP.NET MVC-取代JsonResult新選擇-招喚JilResult
  3. ASP.NET Web API-取代JsonFormatter新選擇-招喚JilFormatter

2 則留言:

  1. 你好, 我試過有bug, Master-Detail 資料表會只出現Detail的資料

    回覆刪除
    回覆
    1. 嗯,這套我們很用久了,沒碰到你說的狀況也...

      刪除

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。