WebAPi返回類型到底應該是什么才合適,這是個問題?


前言

有些問題只有真正遇到或者用到並且多加思考才會想到,平常若作為自學的心態去學習則不會考慮太多,我慢慢明白對於那些有太多要學的東西或者說的更加明確而且具體一點的話,如果對於你現在不是迫切要學或者需要掌握的技能,那就暫且放在一邊吧,比如現在比較火的angular和react,我之前也花時間去學了,但是公司壓根不用或者有專門的前端你學多了貌似沒什么很大的實際用途,其實僅僅做一點基本的了解即可,至少別人問起也知道一二,不要看到別人學什么或者火了什么就盲目跟風,還是根據自身實際情況來學習才是王道。這不剛說到根據自身來學習,腦袋妄想着正在做的項目,突然冒出一個想法,為什么那不可以,為什么它又存在呢?這篇文章就出來了。

話題介紹

我們知道在WebAPi中對於響應結果我們都是這樣用的:

        public HttpResponseMessage GetResult<T>(T t)
        {
            return Request.CreateResponse<T>(HttpStatusCode.OK, t);
        }

在項目中前端為了和其他統一,封裝了一套響應的結果和狀態碼,要求直接返回對象,於是將上述修改成比如如下:

    public Result<List<Person>> GetResult()
    {
       var result = new Result<List<Person>>();
       return result;
    }


    public class Result<T> : BaseResult
    {
        public T Data;
    }

    public class BaseResult
    {
        public string Message;
        public int Status;
        public ErrorCode ErrorCode;
    }

    public enum ErrorCode
    {
    ......
    }

統觀以上兩種方法,一種是WebAPi內置響應的結果,另外一種則是直接返回自定義響應結果。

於是乎,我開始思索這兩種方法雖然都能得到我們想要的結果,但是有什么區別沒有呢?說的更加明確一點的是,二者在數據響應上有沒有性能上的差異呢?

WebAPi響應結果和自定義響應結果二者性能差異

以上則是需要返回對象來進行處理,而有些我們則不需要返回任何對象來進行處理例如直接返回void,而在WebAPi中對應需要返回 IHttpActionResult 例如自定義返回則是如下:

   public void GetFirst()
   {.....}

在WebAPi中則是進行如下返回:

   public IHttpActionResult GetSecond()
   {
     return OK();            
   }

下面我們在控制台中分別來測試這二者在WebHost以及在SelfHost上的差異,我們如何獲取其差異呢?我們通過對void方法和http方法在控制台中發出1000個請求來獲取其總共花費時間來進行比較。

SelfHost

       [HttpGet]
        public void GetFirst()
        {
            StringBuilder stringbuilder = new StringBuilder();
            for (int i = 0; i < 20; i++)
            {
                stringbuilder.Append("something");
            }
        }

        [HttpGet]
        public IHttpActionResult GetSecond()
        {
            StringBuilder stringbuilder = new StringBuilder();
            for (int i = 0; i < 20; i++)
            {
                stringbuilder.Append("something");
            }
            return Ok();
        }

在控制台中方法如下:

        private const string voidUrl = "http://localhost:8080/api/home/GetFirst";
        private const string httpUrl = "http://localhost:8080/api/home/GetSecond";
        private static List<TimeSpan> voidTimes = new List<TimeSpan>();
        private static List<TimeSpan> httpTimes = new List<TimeSpan>();
        static void Main(string[] args)
        {
            Console.WriteLine("Start Test....");
            for (int i = 0; i < 1000; i++)
            {
                voidTimes.Add(getResponse(voidUrl));
                Thread.Sleep(10);
                Console.WriteLine("void Test " + i);
            }
            Console.WriteLine("Finished Void Test");
            for (int i = 0; i < 1000; i++)
            {
                httpTimes.Add(getResponse(httpUrl));
                Thread.Sleep(10);
                Console.WriteLine("http Test " + i);
            }
            Console.WriteLine("Finished Http Test");
            var voidTotalTime = voidTimes.Sum(t => t.Milliseconds);
            Console.WriteLine("void方法發出1000個請求總共需要時間:" + voidTotalTime);
            Console.WriteLine("void方法平均每一個請求需要時間:" + voidTotalTime / 1000.00 + "");

            var httpTotalTime = httpTimes.Sum(t => t.Milliseconds);
            Console.WriteLine("http方法發出1000個請求總共需要時間: " + httpTotalTime);
            Console.WriteLine("http方法平均每一個請求需要時間: " + httpTotalTime / 1000.00 + "");

            Console.Read();
        }


        static TimeSpan getResponse(string url)
        {
            var stopWatch = new Stopwatch();
            stopWatch.Start();
            var httpClient = new HttpClient();
            httpClient.BaseAddress = new Uri(url);
            var task = httpClient.GetAsync(httpClient.BaseAddress).Result;
            var result = task.Content.ReadAsAsync(typeof(object));
            var timeSpan = stopWatch.Elapsed;
            stopWatch.Stop();
            return timeSpan;
        }

下面我們來直觀演示整個過程:

 從上看出似乎由http方法節約一點時間,我們將上述中的方法循環次數,進行如下修改:

            for (int i = 0; i < 200000; i++)
            {
                stringbuilder.Append("something");
            }

這時候我們再來看看結果:

當有二十萬條數據時此時時間又多節約一點點。接下來我們再來測試WebHost。

WebHost

在WebHost中我們利用特性來管理請求方法:

        [HttpGet]
        [Route("test/void")]
        public void GetFirst()
        {
            StringBuilder stringbuilder = new StringBuilder();
            for (int i = 0; i < 20; i++)
            {
                stringbuilder.Append("something");
            }
        }

        [HttpGet]
        [Route("test/IHttpActionResult")]
        public IHttpActionResult GetSecond()
        {
            StringBuilder stringbuilder = new StringBuilder();
            for (int i = 0; i < 20; i++)
            {
                stringbuilder.Append("something");
            }
            return Ok();
        }

此時將控制台請求地址進行對應修改即可:

 private const string voidUrl = "http://localhost:2531/test/void";
 private const string httpUrl = "http://localhost:2531/test/IHttpActionResult";

此時演示結果如下:

此時快了接近一秒。此時我們將數據增加到同樣20萬時再看看:

 

此時還是快了1秒。到了這里是不是就算結束了呢,我們再來看看

當我們請求void方法時返回的狀態碼為如下:

此時利用http來進行響應則是如下:

其返回狀態也不同,我們則需要有對應的處理方式。

總結

在演示void方法和http方法時有時也會出現http方法時間比void方法慢的原因,不知是何緣故,理論上來說用HttpResponseMessage來作為響應結果會快一點,因為HttpResponseMessage內置對於一些異常都做了處理並返回對應的狀態碼而void方法則未做任何處理。但是從另外一個角度看,若我們自定義一套返回的狀態碼來進行處理也並非不可,個人覺得利用WebAPi內置的HttpResponseMessage響應機制來進行結果響應最佳,期待各位的批評和答案,同時不知上述測試是否合理。當時想到這個問題時也查了相關資料,還真有做過類似測試的,於是借用了一下。

參考資料:http://stackoverflow.com/questions/22689888/webapi-2-is-a-void-response-faster-then-ihttpactionresult

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM