目录
介绍
使契约异步
接口
实现
将同步方法转换为异步
原始同步方法
异步修改
从同步方法调用异步方法
从异步方法调用异步方法
结论
介绍本文提供了一些关于如何将现有的工作WCF契约增量地转换为异步的想法,以便在一段时间内轻松测试功能,并且契约可以在任何阶段正常运行。
这里提出的想法不是原创的,而是基于网络搜索。没有一位作者可以感谢,但我要感谢所有那些花时间分享知识的开发人员。
我遇到的问题是工作的WCF IIS托管服务。契约都是同步的。它们涉及一些数据库活动,并呼叫另一个第三方服务。我想尽可能多地从契约中取出。
从一般阅读来看,似乎异步编程会产生收益(主要是在IIS服务器中不浪费线程)。我想清楚我是一个异步的学习者,这是我的“发现之旅”的编年史。希望那里的专家不会发现太多不同意的意见。
有许多事情必须解决。
- 在不破坏界面的情况下将契约更改为异步的。
- 将同步方法转换为异步。
- 从同步方法调用异步方法。
注意:需要 .NET Framework 4.6.1或更高版本才能使用async和await关键字。
让我们按顺序解决这些问题。
使契约异步将接口契约声明的返回类型T(如果有)更改为Task。对实现代码执行相同操作,并将async关键字添加到实现代码声明中。
接口[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
Task ProcessRequests(TransList incoming);
实现
public async Task ProcessRequestsV2(TransList incoming)
{
TransList response = new TransList;
DoSomeStuff;
return response;
}
一旦声明就绪,代码仍应编译并生成编译器警告CS4014:
警告CS4014和CS1998:当您完成转换时,这些警告会随之而来。它们提供了指向尚未实现异步的指针。代码仍然有效,您的服务仍然有效。
将同步方法转换为异步显示的方法来自DataBase辅助类。它显示了使用内置的.framework异步方法从数据库中读取数据。
原始同步方法public bool GetProcessAllowed(string user)
{
const string sSql = "proc_GetProcessAllowed";
using (var conn = new SqlConnection(_msConn))
{
using (var cmd = new SqlCommand(sSql, conn))
{
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@user", user);
using (var r = cmd.ExecuteReader())
{
if (r.Read())
{
return r.GetBoolean(0);
}
throw new ApplicationException("Dt.GetProcessAllowed not able to access database.");
}
}
}
}
异步修改
public async Task<bool> GetProcessAllowed(string user)
{
const string sSql = "proc_GetProcessAllowed";
using (var conn = new SqlConnection(_msConn))
{
await conn.OpenAsync();
using (var cmd = new SqlCommand(sSql, conn))
{
//conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@user", user);
using (var r = await cmd.ExecuteReaderAsync())
{
if (r.Read())
{
return r.GetBoolean(0);
}
throw new ApplicationException("Dt.GetProcessAllowed not able to access database.");
}
}
}
}
从同步方法调用异步方法
为了清楚起见,调用方法仍然是同步的。它没有将异步添加到其声明中,并且返回类型未更改。以下代码段显示对被调用方法的同步版本(已注释掉)的原始调用以及对异步版本的新调用。
请注意使用Result属性来返回原始布尔变量。
//bool getProcessAllowed = _db.GetProcessAllowed(credentials.UserId);
//bool writeProcessRunning = _db.WriteProcessRunning(credentials.UserId, true);
Task getProcessAllowedAsync = _db.GetProcessAllowed(credentials.UserId);
Task writeProcessRunningAsync = _db.WriteProcessRunning(credentials.UserId, true);
bool getProcessAllowed = getProcessAllowedAsync.Result;
bool writeProcessRunning = writeProcessRunning.Result;
if (getProcessAllowed && writeProcessRunning)
{Do some stuff}
从异步方法调用异步方法
这里,调用方法已转换为异步。async关键字已添加到其声明中,其返回类型是Task,因此它可以等待(await)从被调用方法返回的内容。
以下代码段显示对同步版本方法(已注释掉)的原始调用以及对异步版本的新调用。
注意使用await而不是Result属性来返回原始的布尔变量。
//bool getProcessAllowed = _db.GetProcessAllowed(credentials.UserId);
//bool writeProcessRunning = _db.WriteProcessRunning(credentials.UserId, true);
Task getProcessAllowedAsync = _db.GetProcessAllowed(credentials.UserId);
Task writeProcessRunningAsync = _db.WriteProcessRunning(credentials.UserId, true);
bool getProcessAllowed = await getProcessAllowedAsync;
bool writeProcessRunning = await writeProcessRunningAsync;
if (getProcessAllowed && writeProcessRunning)
{Do some stuff}
结论
对我来说,关键是要理解上面显示的同步和异步方法之间的关系。
花了一段时间才意识到将异步关键字添加到方法并将其返回值从T更改为Task仍然允许它同步运行。
在您实现更改时,编译器警告提供了一个很好的指导,您正在处理的部分仍需要更多工作。
原文地址:https://www.codeproject.com/Tips/1274500/WCF-Sync-to-Async-Conversion