简体   繁体   English

我的桌面应用程序挂起了使用async和await的Web API服务调用

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

I am getting lots of delay when saving data in database. 在数据库中保存数据时,我遇到了很多延迟。 I have one exe (Deskptop Application) which reads data from serial port and push that entry in to database through web API service but my application get hangs on this line: 我有一个exe(Deskptop应用程序)从串口读取数据并通过Web API服务将该条目推送到数据库,但我的应用程序在此行上挂起:

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

This exe is responsible to call my web API service method and save data to my database. 这个exe负责调用我的Web API服务方法并将数据保存到我的数据库。

This is my code: 这是我的代码:

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);
                }
            }
        }

My web api method: 我的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;
                }
            }
        }

I haven't work much on Windows application so I am not understanding why my application is hanging. 我没有在Windows应用程序上工作太多,所以我不明白为什么我的应用程序挂起。

Note : data will be continuously coming to my serial port so saving data through web service should not disturb _serialPort_DataReceived event. 注意 :数据将不断进入我的串口,因此通过Web服务保存数据不应该干扰_serialPort_DataReceived事件。


This is a summary of my comments beneath the OP's question 这是我在OP问题下的评论摘要


You are calling an asynchronous method synchronously. 您正在同步调用异步方法。 That will cause the current thread to block. 这将导致当前线程阻塞。 Get rid of the .Result and alter the rest of the code accordingly (like including async and await there too). 摆脱.Result并相应地改变其余的代码(比如包括asyncawait那里)。

eg change this line 例如改变这一行

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

...to: ...至:

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

Your method signature will need to be changed as follows: 您的方法签名需要更改如下:

public async Task CallWebservice(string xmlRequest)
{

}

Any method that calls it will also need to be async and use await for example your _spManager_NewSerialDataRecieved() method. 调用它的任何方法也需要是async并使用await例如_spManager_NewSerialDataRecieved()方法。

Note it has been changed from void to async void . 请注意,它已从void更改为async void Note too the await prior to CallWebservice() . 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)
        }
    }

A note on async void 关于异步void的注释

Because the above method is an event handler it is fine for the method to be async void . 因为上面的方法是一个事件处理程序,所以该方法可以是async void Generally you want to avoid async void in non event handler code. 通常,您希望避免事件处理程序代码中的async void For more info see this brilliant article by Mr Stephen Cleary. 欲了解更多信息,请参阅Stephen Cleary先生的精彩文章

Is this the only problem sir?? 先生,这是唯一的问题吗?

You should fix your async Save() method on the server too as it also has a .Result() . 您应该在服务器上修复async Save()方法,因为它也有.Result() That will block the current thread on the server. 这将阻止服务器上的当前线程。 Prefix it with a await . await前缀。 Generally you want to avoid .Result as a means to wait for the task to complete . 通常你想避免使用.Result 作为等待任务完成的手段 It is safe to use as a means to obtain the result after you have awaited it, but there are more elegant ways to await and get the result in a single line of code. 在等待它之后,可以安全地使用它作为获取结果的方法,但是有更优雅的方法可以等待并在单行代码中获得结果。 eg x = await FooAsync(); 例如x = await FooAsync(); .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM