我目前正在查看一些代码,这些代码基本上从文件中逐行读取数据,并在WCF客户端上为每一行调用适当的方法。我的代码问题是为每个操作创建了一个新的客户端,即:
function CallSomeOp(line)
{
using (var client = new Client()
{
client.SomeOp(line);
}
}
这似乎使客户端关闭连接并为文件中的每一行重新打开一个新的连接,这似乎是一个很大的开销。我想要做的是将客户端的创建移到函数之外并进入初始化,以便在一个客户端上调用多个操作,即:
using (var client = new Client())
{
for(var line in lines)
{
CallSomeOp(line, client);
}
}
但我不确定这是否合适。在客户端上调用多个操作是否有问题,即我最终会耗尽内存还是什么?
答案 0 :(得分:2)
操作通常是无状态的,因此这是预期的行为。您可以更改InstanceContextMode。这确定是否在每次调用时创建新实例,或者是否存在单个实例。问题是,你呢?就像我说的,一次通话通常是无国籍的。只有一个实例也不能很好地扩展。我建议将InstanceContextMode
保持为PerCall,这样,对于网络服务器创建单个实例的每次调用,我都不会过多担心开销。如果开销确实成为问题,那么服务可能不是您所需要的。
然后是ConcurrencyMode,它允许您指定要创建的多个线程。
就客户而言,每次要调用操作时都不需要重新创建它。或者,如果客户端和服务器都知道合同,您还可以查看ChannelFactory。 This answer提供了一些细节。
答案 1 :(得分:2)
在多个调用中重用WCF客户端绝对是一个好主意,因为在创建新实例时确实存在成本,即使that's been improved in later versions也是如此。
重用WCF客户端时最重要的一点是如果服务操作失败,整个客户端将被置于faulted state和不能再使用。
您必须在客户端代码中考虑这一点。根据您的要求,处理这种情况的一种方法是在出现故障时重新创建客户端代理并继续处理输入,如下例所示:
var client = new ServiceClient();
foreach (var line in lines)
{
try
{
client.DoSomething(line);
}
catch
{
client.Abort();
client = new ServiceClient()
}
}
请注意,您可能还希望跟踪服务调用失败的次数以及异常类型,因为在某些情况下,完全中止更有意义操作而不是继续尝试,例如何时无法访问远程服务。