6

如何确保 WCF ChannelFactory 使用 xml 配置中的 Binding 设置(忽略 MaxArrayLength)

嗨,我是 Wcf 新手,正在编写我的第一个 Wcf 服务和客户端。我不喜欢使用工具来生成配置;我宁愿自己编写配置。我要解决的问题是客户端通过 netTcp 与服务通信。该服务可能会返回非常大的有效负载(大于默认的 readerQuotas.maxArrayLength)。我最初开发的组件在字节流有效负载相对较低(即小于它认为的默认值约 16K)时工作正常。我可以通过创建绑定并将 MaxArrayLength 设置为足够大的值以编程方式解决此问题。但是,我需要能够在 xml 配置中执行等效操作。

我的 app.config(客户端)是:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>

        <client>
            <endpoint address="net.tcp://localhost:9000/WcfDataService/RemoteDataRequesterService/"
                binding="netTcpBinding" bindingConfiguration="unsecureNetTcpBinding"
                contract="WcfDataServiceLib.IRemoteDataRequester"
                name="DataRequesterEndpoint" />
        </client>

        <bindings>
            <netTcpBinding>
                <binding name="unsecureNetTcpBinding" maxReceivedMessageSize="2147483647">
                    <readerQuotas maxArrayLength="1000000" />
                    <security mode="None" />
                </binding>
            </netTcpBinding>
        </bindings>

    </system.serviceModel>
</configuration>

创建客户端代理的代码如下:

private void Init()
{
    var address = new EndpointAddress(@"net.tcp://localhost:9000/WcfDataService/RemoteDataRequesterService/");
    const string endpointName = "DataRequesterEndpoint";

    ChannelFactory<IRemoteDataRequester> factory = new ChannelFactory<IRemoteDataRequester>(
        endpointName);

    IRemoteDataRequester proxy = factory.CreateChannel(address);

    // call business methods on proxy ...
}

请注意,代码通过变量“endpointName”链接到配置。

服务端配置(我认为这无关紧要,但为了完整性而包含在内):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <services>
            <service name="WcfDataServiceLib.RemoteDataRequesterService" behaviorConfiguration="WcfDataServiceLib.RemoteDataRequesterServiceBehavior">
                <host>
                    <baseAddresses>
                        <add baseAddress = "net.tcp://localhost:9000/WcfDataService/RemoteDataRequesterService" />
                        <add baseAddress="http://localhost:8731/Design_Time_Addresses/WcfDataService/RemoteDataRequesterService/"/>
                    </baseAddresses>
                </host>
                <endpoint address ="" binding="netTcpBinding" bindingConfiguration="netTcpBindingConfig" contract="WcfDataServiceLib.IRemoteDataRequester">
                    <identity>
                        <dns value="localhost"/>
                    </identity>
                </endpoint>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="WcfDataServiceLib.RemoteDataRequesterServiceBehavior">
                    <serviceMetadata httpGetEnabled="False"/>
                    <serviceDebug includeExceptionDetailInFaults="True" />
                </behavior>
            </serviceBehaviors>
        </behaviors>

        <bindings>
            <netTcpBinding>
                <binding name="netTcpBindingConfig" receiveTimeout="00:00:30">
                    <readerQuotas maxArrayLength="1000000"/>
                </binding>
                <binding name="netTcpReliableSession" receiveTimeout="00:00:30" >
                    <reliableSession enabled="true"/>
                </binding>
            </netTcpBinding>
        </bindings>

    </system.serviceModel>
</configuration>

当我在服务返回大字节流的场景中运行客户端时,会抛出异常,异常内部的消息是:

发生通信错误:套接字连接被中止。这可能是由于处理您的消息时出错或远程主机超出接收超时,或者是潜在的网络资源问题造成的。本地套接字超时为 '00:00:59.9687494'

(这不是超时,因为错误会立即发生。)

如前所述,我可以通过编程方式解决此问题,如下所示:

var binding = new NetTcpBinding
{
    ReaderQuotas = { MaxArrayLength = 10000000 }
};

return new ChannelFactory<IRemoteDataRequester>(binding);

这工作正常,但我需要通过配置来进行测试。

我还尝试了以下方法:

var binding = new NetTcpBinding("unsecureNetTcpBinding");
return new ChannelFactory<IRemoteDataRequester>(binding);

但这没有什么区别。

所以我的问题是,为什么当我从包含 MaxArrayLength 设置为合适值的绑定的端点配置创建通道时,会忽略该值?

许多问候。

好的,我找到了解决方案。配置一直在工作。但是,我提供的配置(“unsecureNetTcpBinding”)是我从说明 http 服务的代码示例中找到的(不是我正在设计的 net tcp 服务)。配置的流氓部分是 'security mode="None"' 当我把它拿出来时,它起作用了。如果我更改 readerQuotas maxArrayLength 这将根据我的需要应用。我的代码工作的原因是因为我没有将安全模式设置为无。感谢您的意见和帮助。

4

2 回答 2

1

我认为问题可能是在配置中你的数字只有 6 个零,而在代码中你有 7 个零。也许?

于 2009-12-03T15:06:06.853 回答
0

也许 MaxArrayLength 不是要设置的正确属性。

试试“maxBufferSize”和“MaxBufferPoolSize”:

<bindings>
        <netTcpBinding>
            <binding name="unsecureNetTcpBinding" 
                     maxBufferSize="2147483647"
                     maxBufferPoolSize="2147483647"
                     maxReceivedMessageSize="2147483647">
                <readerQuotas maxArrayLength="1000000" />
                <security mode="None" />
            </binding>
        </netTcpBinding>
    </bindings>

但真正的问题是:如果您有大量数据,为什么不使用WCF 流?这正是它的设计目的。

http://www.haveyougotwoods.com/archive/2008/04/14/wcf-message-streaming.aspx

故意将 maxBufferSize 等大小设置为一个相当小的值 - 以避免拒绝服务攻击。只需将它们提高到 MaxInt 级别,您的服务器就会容易受到这些 DOS 攻击。

更新:尝试这样做: - 创建一个新的控制台应用程序 - 添加对的
引用 - 添加一个 app.config ,其中包含您的客户端配置所包含的内容 - 将这些代码行放在您的控制台应用程序中:System.Runtime.SerializationSystem.ServiceModel

   class Program
   {
        static void Main(string[] args)
        {
            NetTcpBinding binding = new NetTcpBinding("unsecureNetTcpBinding");
            int maxArrayLength = binding.ReaderQuotas.MaxArrayLength;
            long maxReceivedMessageSize = binding.MaxReceivedMessageSize;
        }
    }
  • 运行和调试 - 你得到什么值?我得到了您输入的内容:“1000000”表示binding.ReaderQuotas.MaxArrayLength“2147483647”表示 binding.MaxReceivedMessageSize。

WCF 确实识别并使用配置中的这些设置 - 保证 120%。您的应用程序中一定有其他可疑的事情发生......

于 2009-12-03T15:09:00.127 回答