C# WCF 服务参考 - 无法创建 UserNameToken
C# WCF Service Reference - can not create UserNameToken
在我的桌面应用程序(C#、WPF、WCF、.NET4.0)中,我添加了一个服务引用。
这是在 Soap 信封中使用证书和 UserNameToken 的 Web 服务 (SOAP) Header。
我使用此 Web 服务的 WSDL 添加服务引用(解决方案 -> 服务引用 -> 添加服务引用)。
在我的 app.config 中,我有:
<customBinding>
<binding name="tmsIntegrationServiceSOAP">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'urn:CDM/tmsIntegrationService/': -->
<!-- <wsdl:binding name='tmsIntegrationServiceSOAP'> -->
<!-- <sp:SupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">..</sp:SupportingTokens> -->
<mtomMessageEncoding messageVersion="Soap11" />
<httpsTransport />
</binding>
</customBinding>
<endpoint address="https://XXX/CDM/tmsIntegrationService"
binding="customBinding" bindingConfiguration="tmsIntegrationServiceSOAP"
contract="RABEN.GS1.tmsIntegrationService" name="tmsIntegrationServiceSOAP" />
我像这样传递用户名和密码:
var ssc = new GS1.tmsIntegrationServiceClient();
ssc.ClientCredentials.UserName.UserName = "test";
ssc.ClientCredentials.UserName.Password = "testPassword";
ssc.Endpoint.Behaviors.Add(new InspectorBehavior());
当我收到请求 XML(使用消息检查器)时,我发现 soap 中没有 UserNameToken header
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:CDM/tmsIntegrationService/importTransportInstruction</Action>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPoy3hcoBMqQ5Kme7yqEiHKs0AAAAAyxy+QnWD8U60kqJZWaGfvYD8RN14nUVIjC0RuEyVBa8ACQAA</VsDebuggerCausalityData>
</s:Header>
<s:Body ...
我尝试使用 basicHttpBinding:
<binding name="secured">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
<endpoint address="https://XXX/CDM/tmsIntegrationService"
binding="basicHttpBinding" bindingConfiguration="secured" contract="RABEN.GS1.tmsIntegrationService"
name="tmsIntegrationServiceSOAP" />
结束结果:
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:CDM/tmsIntegrationService/importTransportInstruction</Action>
</s:Header>
当我尝试使用 wsHttpBinding 时:
<wsHttpBinding>
<binding name="RabenBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
<endpoint address="https://XXX/CDM/tmsIntegrationService"
binding="wsHttpBinding" bindingConfiguration="RabenBinding"
contract="RABEN.GS1.tmsIntegrationService" name="tmsIntegrationServiceSOAP" />
结果:
<s:Header>
<a:Action s:mustUnderstand="1">urn:CDM/tmsIntegrationService/importTransportInstruction</a:Action>
<a:MessageID>urn:uuid:701a0fff-c4aa-4f37-a299-ec6d272e51e7</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
</s:Header>
谁能告诉我我做错了什么?
编辑 - 2017-06-21 20:00
证书安装在我的本地机器上
<behaviors>
<endpointBehaviors>
<behavior name="RabenBehavior">
<clientCredentials>
<clientCertificate findValue="this is footprint of certificate"
storeLocation="CurrentUser" storeName="My" x509FindType="FindByThumbprint" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
我在端点附加此行为:
<endpoint address="https://XXX/CDM/tmsIntegrationService"
behaviorConfiguration="RabenBehavior" binding="wsHttpBinding"
bindingConfiguration="RabenBinding" contract="RABEN.GS1.tmsIntegrationService"
name="tmsIntegrationServiceSOAP" />
编辑 2017-06-21 20:58
我尝试使用 <mtomMessageEncoding messageVersion="Soap11" />
<binding name="myCustomBindingConfig">
<security defaultAlgorithmSuite="Default"
authenticationMode="UserNameOverTransport"
requireDerivedKeys="true"
includeTimestamp="false" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" />
<mtomMessageEncoding messageVersion="Soap11" />
<httpsTransport maxReceivedMessageSize="2000000000" />
</binding>
但是header仍然不包含用户名令牌
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:CDM/tmsIntegrationService/importTransportInstruction</Action>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo0OlG2DVOLdKniJmYU2kvwUAAAAAujMM+x53aEWJYYd4GKyk+PlCKXIih9xLrE0V5TayKhQACQAA</VsDebuggerCausalityData>
</s:Header>
编辑 2017-06-21 21:36
尝试在 VS
的自定义绑定生成中使用 <textMessageEncoding messageVersion="Soap11" />
<binding name="tmsIntegrationServiceSOAP">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'urn:CDM/tmsIntegrationService/': -->
<!-- <wsdl:binding name='tmsIntegrationServiceSOAP'> -->
<!-- <sp:SupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">..</sp:SupportingTokens> -->
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport />
</binding>
但它没有任何作用 - 请求中没有用户名标记 XML:
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:CDM/tmsIntegrationService/importTransportInstruction</Action>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo0wJNixU4QRBhGEUAC3pw50AAAAA/fPJ+e50KUSGbYXwcmoGwgqymCvLXJZIhKg/nKdV97cACQAA</VsDebuggerCausalityData>
</s:Header>
但是,如果您通过单击解决方案资源管理器添加服务引用来添加,会发生什么,它告诉您什么?。或者你没有这个选项。
要修改 SOAP Header,您需要实施 IClientMessageInspector
interface.To 执行此操作创建新的 class MessageInspector 并添加
其中嵌套了以下三个 classes:
public class CustomMessageHeader : MessageHeader
{
private const string NAMESPACE_SECURITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
public CustomMessageHeader()
{
}
public override string Name
{
get { return "wsse:Security"; }
}
public override string Namespace
{
get { return ""; }
}
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteAttributeString("xmlns", "wsse", null, NAMESPACE_SECURITY);
writer.WriteStartElement("wsse:UsernameToken");
writer.WriteElementString("wsse:Username", "YOUR_USERNAME");
writer.WriteElementString("wsse:Password", "YOUR_PASSWORD");
writer.WriteEndElement();
}
}
public class ClientMessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
CustomMessageHeader header = new CustomMessageHeader();
request.Headers.RemoveAt(0);
request.Headers.Add(header);
return request;
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
}
public class CustomEndpointBehavior : IEndpointBehavior
{
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new ClientMessageInspector());
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
要触发此 class 被调用,请在 Main class
中添加新的端点行为
serviceClient.Endpoint.EndpointBehaviors.Add(new CustomEndpointBehavior());
在我的桌面应用程序(C#、WPF、WCF、.NET4.0)中,我添加了一个服务引用。
这是在 Soap 信封中使用证书和 UserNameToken 的 Web 服务 (SOAP) Header。
我使用此 Web 服务的 WSDL 添加服务引用(解决方案 -> 服务引用 -> 添加服务引用)。 在我的 app.config 中,我有:
<customBinding>
<binding name="tmsIntegrationServiceSOAP">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'urn:CDM/tmsIntegrationService/': -->
<!-- <wsdl:binding name='tmsIntegrationServiceSOAP'> -->
<!-- <sp:SupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">..</sp:SupportingTokens> -->
<mtomMessageEncoding messageVersion="Soap11" />
<httpsTransport />
</binding>
</customBinding>
<endpoint address="https://XXX/CDM/tmsIntegrationService"
binding="customBinding" bindingConfiguration="tmsIntegrationServiceSOAP"
contract="RABEN.GS1.tmsIntegrationService" name="tmsIntegrationServiceSOAP" />
我像这样传递用户名和密码:
var ssc = new GS1.tmsIntegrationServiceClient();
ssc.ClientCredentials.UserName.UserName = "test";
ssc.ClientCredentials.UserName.Password = "testPassword";
ssc.Endpoint.Behaviors.Add(new InspectorBehavior());
当我收到请求 XML(使用消息检查器)时,我发现 soap 中没有 UserNameToken header
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:CDM/tmsIntegrationService/importTransportInstruction</Action>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPoy3hcoBMqQ5Kme7yqEiHKs0AAAAAyxy+QnWD8U60kqJZWaGfvYD8RN14nUVIjC0RuEyVBa8ACQAA</VsDebuggerCausalityData>
</s:Header>
<s:Body ...
我尝试使用 basicHttpBinding:
<binding name="secured">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
<endpoint address="https://XXX/CDM/tmsIntegrationService"
binding="basicHttpBinding" bindingConfiguration="secured" contract="RABEN.GS1.tmsIntegrationService"
name="tmsIntegrationServiceSOAP" />
结束结果:
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:CDM/tmsIntegrationService/importTransportInstruction</Action>
</s:Header>
当我尝试使用 wsHttpBinding 时:
<wsHttpBinding>
<binding name="RabenBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
<endpoint address="https://XXX/CDM/tmsIntegrationService"
binding="wsHttpBinding" bindingConfiguration="RabenBinding"
contract="RABEN.GS1.tmsIntegrationService" name="tmsIntegrationServiceSOAP" />
结果:
<s:Header>
<a:Action s:mustUnderstand="1">urn:CDM/tmsIntegrationService/importTransportInstruction</a:Action>
<a:MessageID>urn:uuid:701a0fff-c4aa-4f37-a299-ec6d272e51e7</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
</s:Header>
谁能告诉我我做错了什么?
编辑 - 2017-06-21 20:00 证书安装在我的本地机器上
<behaviors>
<endpointBehaviors>
<behavior name="RabenBehavior">
<clientCredentials>
<clientCertificate findValue="this is footprint of certificate"
storeLocation="CurrentUser" storeName="My" x509FindType="FindByThumbprint" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
我在端点附加此行为:
<endpoint address="https://XXX/CDM/tmsIntegrationService"
behaviorConfiguration="RabenBehavior" binding="wsHttpBinding"
bindingConfiguration="RabenBinding" contract="RABEN.GS1.tmsIntegrationService"
name="tmsIntegrationServiceSOAP" />
编辑 2017-06-21 20:58
我尝试使用 <mtomMessageEncoding messageVersion="Soap11" />
<binding name="myCustomBindingConfig">
<security defaultAlgorithmSuite="Default"
authenticationMode="UserNameOverTransport"
requireDerivedKeys="true"
includeTimestamp="false" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" />
<mtomMessageEncoding messageVersion="Soap11" />
<httpsTransport maxReceivedMessageSize="2000000000" />
</binding>
但是header仍然不包含用户名令牌
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:CDM/tmsIntegrationService/importTransportInstruction</Action>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo0OlG2DVOLdKniJmYU2kvwUAAAAAujMM+x53aEWJYYd4GKyk+PlCKXIih9xLrE0V5TayKhQACQAA</VsDebuggerCausalityData>
</s:Header>
编辑 2017-06-21 21:36 尝试在 VS
的自定义绑定生成中使用<textMessageEncoding messageVersion="Soap11" />
<binding name="tmsIntegrationServiceSOAP">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'urn:CDM/tmsIntegrationService/': -->
<!-- <wsdl:binding name='tmsIntegrationServiceSOAP'> -->
<!-- <sp:SupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">..</sp:SupportingTokens> -->
<textMessageEncoding messageVersion="Soap11" />
<httpsTransport />
</binding>
但它没有任何作用 - 请求中没有用户名标记 XML:
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:CDM/tmsIntegrationService/importTransportInstruction</Action>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo0wJNixU4QRBhGEUAC3pw50AAAAA/fPJ+e50KUSGbYXwcmoGwgqymCvLXJZIhKg/nKdV97cACQAA</VsDebuggerCausalityData>
</s:Header>
但是,如果您通过单击解决方案资源管理器添加服务引用来添加,会发生什么,它告诉您什么?。或者你没有这个选项。
要修改 SOAP Header,您需要实施 IClientMessageInspector interface.To 执行此操作创建新的 class MessageInspector 并添加 其中嵌套了以下三个 classes:
public class CustomMessageHeader : MessageHeader
{
private const string NAMESPACE_SECURITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
public CustomMessageHeader()
{
}
public override string Name
{
get { return "wsse:Security"; }
}
public override string Namespace
{
get { return ""; }
}
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteAttributeString("xmlns", "wsse", null, NAMESPACE_SECURITY);
writer.WriteStartElement("wsse:UsernameToken");
writer.WriteElementString("wsse:Username", "YOUR_USERNAME");
writer.WriteElementString("wsse:Password", "YOUR_PASSWORD");
writer.WriteEndElement();
}
}
public class ClientMessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
CustomMessageHeader header = new CustomMessageHeader();
request.Headers.RemoveAt(0);
request.Headers.Add(header);
return request;
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
}
public class CustomEndpointBehavior : IEndpointBehavior
{
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new ClientMessageInspector());
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
要触发此 class 被调用,请在 Main class
中添加新的端点行为serviceClient.Endpoint.EndpointBehaviors.Add(new CustomEndpointBehavior());