我在数据库中保存数据时遇到很多延迟。我有一个 exe(桌面应用程序),它从串行端口读取数据并通过 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 应用程序上的工作不多,所以我不明白为什么我的应用程序挂起。
注意:数据将不断进入我的串行端口,因此通过网络服务保存数据不应干扰 _serialPort_DataReceived
事件。
最佳答案
这是我在 OP 问题下的评论摘要
您正在同步调用异步方法。这将导致当前线程阻塞。去掉 .Result
并相应地更改其余代码(例如也包括 async
和 await
)。
例如改变这一行
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()
之前的 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)
}
}
关于 async void 的注释
因为上面的方法是一个事件处理程序,所以该方法可以是 async void
。通常,您希望避免在非 事件处理程序代码中使用async void
。有关详细信息,请参阅 this brilliant article Stephen Cleary 先生。
Is this the only problem sir??
您也应该修复服务器上的 async Save()
方法,因为它也有一个 .Result()
。这将阻塞服务器上的当前线程。用 await
作为前缀。通常,您希望避免使用 .Result
作为等待任务完成的方式。在等待之后用作获取结果的方法是安全的,但还有更优雅的方法来等待并在一行代码中获取结果。例如x = await FooAsync();
。
关于c# - 我的桌面应用程序在使用 async 和 await 调用 Web API 服务时挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37248388/