目前我们使用的调用方式基本都是一种请求-响应模型:客户端发起请求,等待远程服务器响应,然后获取返回值。这种方式和调用本地函数非常类似,但是,远程方法调用还有另一种方式——单向通知。
对于有返回值的函数,发起请求后,等待远程服务器返回结果是必要的,因为需要返回值进行下一步操作。但是,对于没有返回值的函数,等待服务器处理完成有时就没必要了,因为本来就没有返回值,等待响应就是等待服务器的处理完成。但是,很多时候,客户端无需关心服务器什么时候才能处理完成,这个时候等待服务器端完成后才返回就是浪费时间了。
例如:对于如下的一个客户端上报通知的服务:
[ServiceContract]
public interface IService1
{
[OperationContract]
void Notify(string message);
}
public class Service1 : IService1
{
public void Notify(string message)
{
//这个是模拟服务器需要长时间才能处理完成
System.Threading.Thread.Sleep(3000);
}
}
在这个服务中,客户端并没有必要关心服务器何时处理完成,但仍需要等待服务器端处理完成,3秒后才能返回。这个是不大合理的,为了解决这个问题,可以使用单向通知方式。
单向通知方式并不是什么新概念,类似我们平常发短信,我们只需要知道短信发送成功就可以了,并不需要等待服务器处理完成就可以返回了。我们编程中也常将一个耗时的操作丢到线程池中执行,至于什么时候执行完成则并不关心。我们通常称为这个方式为Fire-Forget模型,C# 5.0中的async void函数就是一个典型的例子,可以调用,但无法等待。
再接着回到WCF中来,WCF中使用单向通知是非常简单的,只需要将OperationContract中的IsOneWay=true设置上即可(不要在非void函数里面设置IsOneWay=true,设置后服务启动不起来)。
[ServiceContract]
public interface IService1
{
[OperationContract(IsOneWay=true)]
void Notify(string message);
}
而实现则无需任何改动,此时再来调用该函数,马上就返回了,
这个符合我们的预期结果,再来看看响应的消息,和前面的双向通知相比较,它是没有响应消息的。
另外,可以用async void函数来实现单向通知,从而使得可以使用await语法糖。但是需要注意的是,像我在文章C# 5.0 Async函数的提示和技巧中所提到的那样,该函数中的未捕获异常会导致服务器崩溃,需要catch所有异常,我个人并不建议这么用,直接使用普通的void函数,调用另外一个可以使用await语法糖的async Task函数即可。
message)
{
.Delay(3000);
}
最后需要说明的是,虽然单向通知可以加快响应速度,但同时由于其不关注返回结果,远程处理出错时也是感知不到的(异常本身也是一个返回值),在使用的时候需要考虑到这一点。