對Asp.net WebApi中異步(async+await)接口實際使用及相關思考(示例給出了get,post,提交文件,異步接口等實踐).

【不少初學者的疑問】html

  爲什麼做爲web api這樣的自然的併發應用,還須要在controller的action上聲明使用async這些呢?web

  <參考解答>api

在 web 服務器上,.NET Framework 維護用於處理 ASP.NET 請求的線程池。 當請求到達時,將調度池中的線程以處理該請求。 若是以同步方式處理請求,則處理請求的線程將在處理請求時處於繁忙狀態,而且該線程沒法處理其餘請求。
若是請求發出須要兩秒鐘時間才能完成的 web 服務調用,則該請求將須要兩秒鐘,不管是同步執行仍是異步執行。 可是,在異步調用期間,線程在等待第一個請求完成時不會被阻止響應其餘請求。 所以,當有多個併發請求調用長時間運行的操做時,異步請求會阻止請求隊列和線程池的增加。服務器

[注]總的來講,對單個客戶端請求來講,它感覺到的速度,響應時間並無由於使用異步而提高,但對整個服務器來講,由於線程在異步場景下等待的同時還在服務其它的線程,所以線程數不會增加太快,進而不會輕易達到繁忙狀態。併發

【給出一個本身寫的分析代碼】異步

using ConfigLab.Comp;
using ConfigLab.Comp.HttpRequestTools.HttpClient;
using ConfigLab.Comp.MetaData;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Hosting;
using System.Web.Http;

namespace ConfigLab.WebApiProject.Controllers
{
    /// <summary>
    /// 功能簡介:web api中的異步接口體會
    /// 建立時間:2020-8-23
    /// 建立人:pcw
    /// 備註:若是不須要全部接口有一個默認的 /api/*中的api這段,須要自行修改RouteConfig.cs中的路由設置
    /// </summary>
    public class CommonAPIController : ApiController
    {
        /// <summary>
        /// https://localhost:44305/CommonAPI/getTest1?userid=u001
        /// </summary>
        /// <param name="userid"></param>
        /// <returns></returns>
        public string getTest(string userid)
        {
            return $"test1_result(from web api):userid={userid}";
        }
        /// <summary>
        /// https://localhost:44305/CommonAPI/getTest2
        /// 參數:userid=u002&optype=add
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [HttpPost]
        public string postTest([FromBody] userActin data)
        {
            return $"test2_result(from web api):userid={data.userid},optype={data.optype}";
        }
        /// <summary>
        /// 請求地址:https://localhost:44305/CommonAPI/postListByAsync
        /// 參數:userid=u002&optype=add
        /// 返回:多個網站的返回值
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<List<ResponseResult>> postListByAsync([FromBody] userActin data)
        {
            List<ResponseResult> listResult = new List<ResponseResult>();
            HttpClientAssisterAsync httpAssist = new HttpClientAssisterAsync();//介紹(https://www.cnblogs.com/taohuadaozhu/p/13548266.html),Nuget 搜索安裝: ConfigLab.Comp便可使用
            Task<ResponseResult> tsk_rrs = httpAssist.SendRequestByGet("http://www.baidu.com");
            await tsk_rrs;
            listResult.Add(tsk_rrs.Result);
            tsk_rrs = httpAssist.SendRequestByGet("http://www.ifeng.com");
            await tsk_rrs;
            listResult.Add(tsk_rrs.Result);
            return listResult;
        }
        /// <summary>
        /// 請求地址:https://localhost:44305/CommonAPI/SaveFile?projectId=p001&userid=u003
        /// 附加參數:文件流
        /// </summary>
        /// <param name="projectId"></param>
        /// <param name="userid"></param>
        /// <returns></returns>
        public async Task<RunResult> SaveFile(string projectId, string userid)
        {
            RunResult rrs = new RunResult();
            if (!Request.Content.IsMimeMultipartContent())
            {
                //throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
                return new RunResult() { RunCode = -1, RunMsg = "HttpStatusCode.UnsupportedMediaType" };
            }
            //string root = Path.Combine(HostingEnvironment.MapPath(ConfigurationManager.AppSettings["FileStorePath"]), DateTime.Now.ToShortDateString(), projectId);
            string root = Path.Combine(ConfigurationManager.AppSettings["FileStorePath"], DateTime.Now.ToShortDateString(), projectId);
            if (!Directory.Exists(root)) Directory.CreateDirectory(root);
            MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(root);
            try
            {
                await Request.Content.ReadAsMultipartAsync(provider); 
                return new RunResult() { RunCode = 0, RunMsg = "" };
            }
            catch (Exception ex)
            {
                rrs.RunCode = -2;
                rrs.RunMsg = $"獲取客戶端上傳的文件流失敗,ex.msg={ex.Message},ex.stacktrace={ex.StackTrace}";
            }
            return rrs;
        }
    }
    /// <summary>
    /// 測試用的post參數對象
    /// </summary>
    public class userActin
    {
        public string userid { get; set; }
        public string optype { get; set; }

    }
}
相關文章
相關標籤/搜索