簡體   English   中英

我的桌面應用程序掛起了使用async和await的Web API服務調用

[英]My desktop application hangs on web API service call with async and await

在數據庫中保存數據時,我遇到了很多延遲。 我有一個exe(Deskptop應用程序)從串口讀取數據並通過Web API服務將該條目推送到數據庫,但我的應用程序在此行上掛起:

httpClient.PostAsync("api/MyController/Save", httpConent).Result;

這個exe負責調用我的Web API服務方法並將數據保存到我的數據庫。

這是我的代碼:

void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
       {
           int dataLength = _serialPort.BytesToRead;
           byte[] data = new byte[dataLength];
           int nbrDataRead = _serialPort.Read(data, 0, dataLength);

           if (nbrDataRead == 0)
               return;

           // Send data to whom ever interested
           if (NewSerialDataRecieved != null)
           {
               NewSerialDataRecieved(this, new SerialDataEventArgs(data));
           }
       }

 void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)
        {
            if (this.InvokeRequired)
            {
                // Using this.Invoke causes deadlock when closing serial port, and BeginInvoke is good practice anyway.
                //// Fired-off asynchronously; let the current thread continue.
                this.BeginInvoke(new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved), new object[] { sender, e });
                return;
            }
            //data is converted to text
            string str = Encoding.ASCII.GetString(e.Data);
            if (!string.IsNullOrEmpty(str))
            {
               CallWebservice(str)
            }
        }

public void CallWebservice(string xmlRequest)
        {
            using (var httpClient = new HttpClient())
            {
               httpClient.BaseAddress = new Uri("WebService Url");
                httpClient.DefaultRequestHeaders.Accept.Clear();
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                StringContent httpConent = new StringContent(xmlRequest, Encoding.UTF8);
                HttpResponseMessage responseMessage = null;
                try
                {
                    responseMessage = httpClient.PostAsync("api/MyController/Save", httpConent).Result;
                }
                catch (Exception ex)
                {
                    if (responseMessage == null)
                    {
                        responseMessage = new HttpResponseMessage();
                    }
                    responseMessage.StatusCode = HttpStatusCode.InternalServerError;
                    responseMessage.ReasonPhrase = string.Format("RestHttpClient.SendRequest failed: {0}", ex);
                }
            }
        }

我的web api方法:

 public async Task<HttpResponseMessage> Save(HttpRequestMessage request)
        {
               var requestdata = request.Content.ReadAsStringAsync().Result;//extract Users Id's from this
                var users=context.User.Where(t => (t.Stats == userId1) || (t.Stats == userId2)).ToList();
                var objUsersMapping= new UsersMapping();
                objUsersMapping.Work1 = users[0].Work1;
                objUsersMapping.Work2 = users[1].Work1;
                await this.SaveUsersMapping(objUsersMapping); 
        }

 public async Task<UsersMapping> SaveUsersMapping(UsersMapping objUsersMapping)
        {
            using (var context = new MyEntities())
            {
                try
                {
                    context.UsersMapping.Add(objUsersMapping);
                    await context.SaveChangesAsync();
                    return objUsersMapping;
                }
                catch (Exception foExe)
                {
                    return null;
                }
            }
        }

我沒有在Windows應用程序上工作太多,所以我不明白為什么我的應用程序掛起。

注意 :數據將不斷進入我的串口,因此通過Web服務保存數據不應該干擾_serialPort_DataReceived事件。


這是我在OP問題下的評論摘要


您正在同步調用異步方法。 這將導致當前線程阻塞。 擺脫.Result並相應地改變其余的代碼(比如包括asyncawait那里)。

例如改變這一行

responseMessage = httpClient.PostAsync("api/MyController/Save", httpConent).Result;

...至:

 responseMessage = await httpClient.PostAsync("api/MyController/Save", httpConent);

您的方法簽名需要更改如下:

public async Task CallWebservice(string xmlRequest)
{

}

調用它的任何方法也需要是async並使用await例如_spManager_NewSerialDataRecieved()方法。

請注意,它已從void更改為async void CallWebservice()請注意,在CallWebservice()之前await

async void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)
    {
        if (this.InvokeRequired)
        {
            // Using this.Invoke causes deadlock when closing serial port, and BeginInvoke is good practice anyway.
            //// Fired-off asynchronously; let the current thread continue.
            this.BeginInvoke(new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved), new object[] { sender, e });
            return;
        }
        //data is converted to text
        string str = Encoding.ASCII.GetString(e.Data);
        if (!string.IsNullOrEmpty(str))
        {
           await CallWebservice(str)
        }
    }

關於異步void的注釋

因為上面的方法是一個事件處理程序,所以該方法可以是async void 通常,您希望避免事件處理程序代碼中的async void 欲了解更多信息,請參閱Stephen Cleary先生的精彩文章

先生,這是唯一的問題嗎?

您應該在服務器上修復async Save()方法,因為它也有.Result() 這將阻止服務器上的當前線程。 await前綴。 通常你想避免使用.Result 作為等待任務完成的手段 在等待它之后,可以安全地使用它作為獲取結果的方法,但是有更優雅的方法可以等待並在單行代碼中獲得結果。 例如x = await FooAsync();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM