为什么这个WCF服务一次只能处理一个请求?

4

我看到了几个类似的问题,但是我无法根据它们的答案解决这个问题。

我有一个用于在同一服务器上运行的两个应用程序之间通信的WCF服务,注意设置了ConcurrencyModeMultiple

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
internal class MyService : ServiceBase, IMyService
{
    ...
}

我们有一个WPF应用程序,在其中我们以下列方式创建服务实例:
var serv = new MyService();

var servHost = new ServiceHost(serv, new Uri("..."));

servHost.AddServiceEndpoint(typeof(IMyService), ServiceBase.DefaultInterProcessBinding, string.Empty);

servHost.Open();

在这里,ServiceBase.DefaultInterProcessBinding 是以下内容:

public static readonly Binding DefaultInterProcessBinding = new NetNamedPipeBinding()
{
    CloseTimeout = TimeSpan.FromHours(1),
    OpenTimeout = TimeSpan.FromHours(1),
    ReceiveTimeout = TimeSpan.MaxValue,
    SendTimeout = TimeSpan.FromHours(1),
    HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
    MaxBufferSize = 1073741824,
    MaxBufferPoolSize = 524288,
    MaxReceivedMessageSize = 1073741824,
    TransferMode = TransferMode.Buffered,
    ReaderQuotas = new XmlDictionaryReaderQuotas()
    {
            MaxDepth = 32,
            MaxStringContentLength = 8192,
            MaxArrayLength = 16384,
            MaxBytesPerRead = 4096,
            MaxNameTableCharCount = 16384
    }
};

当我们并行向此服务发送多个请求时,由于某种原因,它只会一次处理一个请求。(因为我们有相当长的运行时间,所以很容易进行确定性测试,可以清楚地看到在客户端同时调用了3个请求,在服务器端却依次被处理。)

这可能是什么原因呢?我应该检查哪些其他配置参数?

(更新:我从客户端调用服务的代码类似于此:

Task.Factory.StartNew(() =>
    {
        serviceClient.Foo();
    });
Task.Factory.StartNew(() =>
    {
        serviceClient.Bar();
    });
Task.Factory.StartNew(() =>
    {
        serviceClient.Baz();
    });

通过调试我可以看到,所有三个请求都立即被调用,但它们在服务器上一个接一个地处理。更新2:问题可能不在服务器上,而是在客户端上。如果我为这些调用创建一个新的客户端对象,那么它们就会正确地并行处理。我是通过以下方式创建客户端的:
var factory = new ChannelFactory<IMyService>(ServiceBase.DefaultInterProcessBinding, new EndpointAddress("..."));

serviceClient = factory.CreateChannel();

我应该在工厂或通道上配置其他内容吗?
1个回答

6
我发现问题并不在服务器上,而是在客户端。
如果您使用ChannelFactory创建一个通道,则必须显式调用Open()。否则,框架将在每次调用请求时调用EnsureOpened()EnsureOpened()将阻塞直到前一个请求完成,因此实际上只会发送一个请求。
(详细信息请参见:http://blogs.msdn.com/b/wenlong/archive/2007/10/26/best-practice-always-open-wcf-client-proxy-explicitly-when-it-is-shared.aspx
因此,更改此代码:
var factory = new ChannelFactory<IMyService>(ServiceBase.DefaultInterProcessBinding, new EndpointAddress("..."));

serviceClient = factory.CreateChannel();

转换为:

var factory = new ChannelFactory<IMyService>(ServiceBase.DefaultInterProcessBinding, new EndpointAddress("..."));

serviceClient = factory.CreateChannel();
((IClientChannel)serviceClient).Open();

问题已解决,现在请求可以正常并行发送。

顺便说一下,我需要进行大量谷歌搜索才能找到这个解决方案,我觉得很奇怪为什么这个问题在MSDN上没有更强烈的宣传。


你尝试过在你的ChannelFactory上调用“Open”吗? - Aron
+1 好的,谢谢马克。这非常有帮助。另一个快速问题。您是否在每个线程中使用不同的通道实例?通道应该很容易制作。 - Aron
不,这种方法可以在多个线程中使用单个通道对象。我想多个通道也可以工作(例如,我考虑使用带有“ThreadStaticAttribute”的静态字段,或使用“ThreadLocal<T>”对象)。 - Mark Vincze
2
确保缓存通道工厂。这是一个昂贵的操作。我真希望他们在 MSDN 上更详细地介绍某些对象的生命周期... - Aron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接