我正在使用以编程方式配置的WCF客户端(System.ServiceModel.ClientBase)。此WCF客户端使用CustomBinding进行配置,该默认情况下具有TextMessageEncodingBindingElement。
现在,当我尝试切换到Mtom编码时,我更改了Client的Endpoint.Binding属性,该工作正常。 Endpoint.Binding属性显示它已更改。
不幸的是,当我执行WCF服务公开的方法之一时,它仍然使用TextMessageEncoding,我无法弄清楚原因。
我已经完成了它,通过构造一个新的ClientBase并在构造函数中传递新的EndPointBinding:
socialProxy = new SocialProxyClient(SocialProxyClientSettings.SocialProxyMTomEndPointBinding, new EndpointAddress(SocialProxyClientSettings.SocialProxyEndPointAddress));
但是当我尝试这个时它不起作用:
socialProxy.Endpoint.Binding = SocialProxyClientSettings.SocialProxyMTomEndPointBinding;
这些是我对EndPointBindings的定义:
public static TextMessageEncodingBindingElement TextMessageEncodingBindingElement
{
get
{
if (_textMessageEncodingBindingElement == null)
{
_textMessageEncodingBindingElement = new TextMessageEncodingBindingElement() { MessageVersion = MessageVersion.Soap11 };
_textMessageEncodingBindingElement.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
{
MaxDepth = 32,
MaxStringContentLength = 5242880,
MaxArrayLength = 204800000,
MaxBytesPerRead = 5242880,
MaxNameTableCharCount = 5242880
};
}
return _textMessageEncodingBindingElement;
}
}
public static MtomMessageEncodingBindingElement MtomMessageEncodingBindingElement
{
get
{
if (_mtomMessageEncodingBindingElement == null)
{
_mtomMessageEncodingBindingElement = new MtomMessageEncodingBindingElement();
_mtomMessageEncodingBindingElement.MaxReadPoolSize = TextMessageEncodingBindingElement.MaxReadPoolSize;
_mtomMessageEncodingBindingElement.MaxWritePoolSize = TextMessageEncodingBindingElement.MaxWritePoolSize;
_mtomMessageEncodingBindingElement.MessageVersion = TextMessageEncodingBindingElement.MessageVersion;
_mtomMessageEncodingBindingElement.ReaderQuotas.MaxDepth = TextMessageEncodingBindingElement.ReaderQuotas.MaxDepth;
_mtomMessageEncodingBindingElement.ReaderQuotas.MaxStringContentLength = TextMessageEncodingBindingElement.ReaderQuotas.MaxStringContentLength;
_mtomMessageEncodingBindingElement.ReaderQuotas.MaxArrayLength = TextMessageEncodingBindingElement.ReaderQuotas.MaxArrayLength;
_mtomMessageEncodingBindingElement.ReaderQuotas.MaxBytesPerRead = TextMessageEncodingBindingElement.ReaderQuotas.MaxBytesPerRead;
_mtomMessageEncodingBindingElement.ReaderQuotas.MaxNameTableCharCount = TextMessageEncodingBindingElement.ReaderQuotas.MaxNameTableCharCount;
}
return _mtomMessageEncodingBindingElement;
}
}
有人可以解释为什么以编程方式更改Endpoint.Binding不起作用吗?
答案 0 :(得分:2)
我相信在构建ClientBase期间,原始的Binding用于创建一些辅助对象。稍后更改绑定不会更改这些帮助程序对象。
要在构造之后进行任何调整,您可能需要一个自定义绑定行为,您可以根据需要调整绑定的内部。在构造中使用它,以便为以后的更改准备好所有帮助程序对象。像往常一样,你想要的只是一个简单的行为改变,但你还需要编写辅助助手类来支持你的一个行为改变。
参见SO帖子:ONVIF Authentication in .NET 4.0 with Visual Studio 2010 有关CustomBinding问题的讨论。
请参阅博文:Supporting the WS-I Basic Profile Password Digest in a WCF Client Proxy 有关自定义行为的示例,可让您动态更改用户名令牌。
也许可以做类似的事情让你动态控制本地端点绑定。
更新:在StackOverflow中更多阅读,以及链接到的页面,我相信我找到了您正在寻找的答案。
对于PasswordDigestBehavior: 见:ONVIF Authentication in .NET 4.0 with Visual Studios 2010 并且:http://benpowell.org/supporting-the-ws-i-basic-profile-password-digest-in-a-wcf-client-proxy/
对于本地NIC绑定: 见:Specify the outgoing IP address to use with WCF client
// ASSUMPTIONS:
// 1: DeviceClient is generated by svcutil from your WSDL.
// 1.1: DeviceClient is derived from
// System.ServiceModel.ClientBase<Your.Wsdl.Device>
// 2: serviceAddress is the Uri provided for your service.
//
private static DeviceClient CreateDeviceClient(IPAddress nicAddress,
Uri serviceAddress,
String username,
String password)
{
if (null == serviceAddress)
throw new ArgumentNullException("serviceAddress");
//////////////////////////////////////////////////////////////////////////////
// I didn't know how to put a variable set of credentials into a static
// app.config file.
// But I found this article that talks about how to set up the right kind
// of binding on the fly.
// I also found the implementation of PasswordDigestBehavior to get it all to work.
//
// from: https://stackoverflow.com/questions/5638247/onvif-authentication-in-net-4-0-with-visual-studios-2010
// see: http://benpowell.org/supporting-the-ws-i-basic-profile-password-digest-in-a-wcf-client-proxy/
//
EndpointAddress serviceEndpointAddress = new EndpointAddress(serviceAddress);
HttpTransportBindingElement httpBinding = new HttpTransportBindingElement();
if (!String.IsNullOrEmpty(username))
{
httpBinding.AuthenticationScheme = AuthenticationSchemes.Digest;
}
else
{
httpBinding.AuthenticationScheme = AuthenticationSchemes.Anonymous;
}
var messageElement = new TextMessageEncodingBindingElement();
messageElement.MessageVersion =
MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None);
CustomBinding bind = new CustomBinding(messageElement, httpBinding);
////////////////////////////////////////////////////////////////////////////////
// from: https://stackoverflow.com/questions/3249846/specify-the-outgoing-ip-address-to-use-with-wcf-client
// Adjust the serviceEndpointAddress to bind to the local NIC, if at all possible.
//
ServicePoint sPoint = ServicePointManager.FindServicePoint(serviceAddress);
sPoint.BindIPEndPointDelegate = delegate(
System.Net.ServicePoint servicePoint,
System.Net.IPEndPoint remoteEndPoint,
int retryCount)
{
// if we know our NIC local address, use it
//
if ((null != nicAddress)
&& (nicAddress.AddressFamily == remoteEndPoint.AddressFamily))
{
return new System.Net.IPEndPoint(nicAddress, 0);
}
else if (System.Net.Sockets.AddressFamily.InterNetworkV6 == remoteEndPoint.AddressFamily)
{
return new System.Net.IPEndPoint(System.Net.IPAddress.IPv6Any, 0);
}
else // if (System.Net.Sockets.AddressFamily.InterNetwork == remoteEndPoint.AddressFamily)
{
return new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0);
}
};
/////////////////////////////////////////////////////////////////////////////
DeviceClient client = new DeviceClient(bind, serviceEndpointAddress);
// Add our custom behavior
// - this requires the Microsoft WSE 3.0 SDK file: Microsoft.Web.Services3.dll
//
PasswordDigestBehavior behavior = new PasswordDigestBehavior(username, password);
client.Endpoint.Behaviors.Add(behavior);
return client;
}