Lea*_*sed 4 c# asynchronous winforms async-await asp.net-web-api
在数据库中保存数据时,我遇到了很多延迟.我有一个exe(Deskptop应用程序)从串口读取数据并通过Web API服务将该条目推送到数据库,但我的应用程序在此行上挂起:
httpClient.PostAsync("api/MyController/Save", httpConent).Result;
Run Code Online (Sandbox Code Playgroud)
这个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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我没有在Windows应用程序上工作太多,所以我不明白为什么我的应用程序挂起.
注意:数据将不断进入我的串口,因此通过Web服务保存数据不应该干扰_serialPort_DataReceived事件.
这是我在OP问题下的评论摘要
您正在同步调用异步方法.这将导致当前线程阻塞.摆脱.Result并相应地改变代码的其余部分(如包括async与await有太多).
例如改变这一行
responseMessage = httpClient.PostAsync("api/MyController/Save", httpConent).Result;
Run Code Online (Sandbox Code Playgroud)
...至:
responseMessage = await httpClient.PostAsync("api/MyController/Save", httpConent);
Run Code Online (Sandbox Code Playgroud)
您的方法签名需要更改如下:
public async Task CallWebservice(string xmlRequest)
{
}
Run Code Online (Sandbox Code Playgroud)
任何调用它的方法也需要async使用await例如你的_spManager_NewSerialDataRecieved()方法.
请注意它已从更改void为async void.await之前也要注意CallWebservice().
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)
}
}
Run Code Online (Sandbox Code Playgroud)
因为上面的方法是一个事件处理程序,所以方法就可以了async void.通常,您希望避免async void使用非事件处理程序代码.欲了解更多信息,请参阅Stephen Cleary先生的精彩文章.
先生,这是唯一的问题吗?
您应该async Save()在服务器上修复您的方法,因为它也有.Result().这将阻止服务器上的当前线程.用它作为前缀await.通常,您希望避免.Result 作为等待任务完成的手段.在等待它之后,可以安全地使用它作为获取结果的方法,但是有更优雅的方法可以等待并在单行代码中获得结果.例如x = await FooAsync();.
| 归档时间: |
|
| 查看次数: |
1188 次 |
| 最近记录: |