如何确保WCF ChannelFactory使用xml配置中的Binding设置(MaxArrayLength被忽略)
如何确保 WCF ChannelFactory 使用 xml 配置中的绑定设置(忽略 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 服务)。恶意的配置是 '安全模式=“无”' 当我把这个拿出来时,它起作用了。如果我更改 readerQuotas maxArrayLength,则会按我的要求应用它。我的代码之所以有效,是因为我没有将安全模式设置为无。感谢您的评论和帮助。
How to ensure that the WCF ChannelFactory uses Binding settings in xml configuration (MaxArrayLength is ignored)
Hi, I am new to Wcf and and writing my first Wcf service and client. I prefer not to use
tools to generate config; I would rather write the config myself. The problem I am trying
to solve is of a client communicating with a service over netTcp. The service can
potentially return very large payloads (greather than the default
readerQuotas.maxArrayLength). The components I have initially developed work fine when the
byte stream payloads are relatively low (ie less than the default which it think is about 16K).
I can solve this problem programmicatically by creating a binding and setting MaxArrayLength
to a sufficiently large value. However, I need to be able to perform the equivalent in the
xml configuration.
My app.config (client) is:
<?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>
The code to create the client proxy is as follows:
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 ...
}
Note that the code is linked to the config by the variable 'endpointName'.
Service side config (I don't think this is relevant but included for completeness):
<?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>
When I run the client in a scenario in which a large byte stream is returned by the service,
an exception is thrown and the message inside the exception is:
Communication Error occured: The socket connection was aborted. This could be caused
by an error processing your message or a receive timeout being exceeded by the remote host,
or an underlying network resource issue. Local socket timeout was '00:00:59.9687494'
(This is not a timeout as the error occurs immediately.)
As previously stated, I can fix this programmatically as follows:
var binding = new NetTcpBinding
{
ReaderQuotas = { MaxArrayLength = 10000000 }
};
return new ChannelFactory<IRemoteDataRequester>(binding);
this works ok, but I need to do it via config for testing purposes.
I have also tried the following:
var binding = new NetTcpBinding("unsecureNetTcpBinding");
return new ChannelFactory<IRemoteDataRequester>(binding);
But this makes no difference.
So my question is why, when I create the channel from the endpoint config which includes a binding with
MaxArrayLength set to a suitable value, is this value ignored?
Many regards.
Ok, I have found the solution. The configuration was working all along. However, the config that I provided ("unsecureNetTcpBinding") which I found from a code sample illustrating http services (not net tcp service which is what I'm designing). The rogue piece of config was
'security mode="None"'
When I took this out, it worked. If I change readerQuotas maxArrayLength this is applied as I require. The reason why my code worked is because I was not setting the security mode to none. Thanks for your comments and assistance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为问题可能是在配置中你的数字只有 6 个零,而在代码中你有 7 个零。或许?
I think the problem could be that in config your number only has 6 zeros, while in code you have 7 zeros. Maybe?
也许 MaxArrayLength 不是正确设置的属性。
尝试“maxBufferSize”和“MaxBufferPoolSize”:
但真正的问题是:如果您有大量数据,为什么不使用 WCF 流式传输?这正是它的设计目的。
http://www.haveyougotwoods.com/archive/ 2008/04/14/wcf-message-streaming.aspx
maxBufferSize 等大小故意设置为相当小的值 - 以避免拒绝服务攻击。只要将它们提高到 MaxInt 级别,您的服务器就容易受到这些 DOS 攻击。
更新:
尝试这样做:
- 创建一个新的控制台应用程序
- 添加对 System.Runtime.Serialization 和 System.ServiceModel 的引用
- 添加一个 app.config,其中包含您的客户端配置所包含的内容
- 将这些代码行放入控制台应用程序中:
WCF 确实可以识别并使用配置中的这些设置 - 120% 保证。您的应用程序中一定还有其他可疑的事情发生......
Maybe the MaxArrayLength isn't the right property to set.
Try "maxBufferSize" and "MaxBufferPoolSize":
But the real question is: if you have large amounts of data, why aren't you making use of WCF streaming?? That's exactly what it's designed for.
http://www.haveyougotwoods.com/archive/2008/04/14/wcf-message-streaming.aspx
The maxBufferSize etc. sizes are set to a fairly small value on purpose - to avoid denial of service attacks. Just cranking those up to MaxInt levels makes your server vulnerable to these DOS attacks.
UPDATE:
Try doing this:
- create a new console app
- add references to
System.Runtime.Serialization
andSystem.ServiceModel
- add an app.config which contains exactly what your client side config contains
- put these lines of code in your console app:
binding.ReaderQuotas.MaxArrayLength
, "2147483647" for binding.MaxReceivedMessageSize.WCF does recognize and use those settings from config - 120% guaranteed. There must be something else fishy going on in your app.....