【问题标题】:How to pass username and password to the SOAP header of a Web Service Call from C#?如何从 C# 将用户名和密码传递给 Web 服务调用的 SOAP 标头?
【发布时间】:2014-11-20 13:04:34
【问题描述】:

我想编写一个 C# 代码来调用另一台机器上的(远程)Web 服务。为此,我必须在调用的 SOAP 标头中传递用户名和密码。

我想知道一个用 C# 编写的代码示例。

生成的 XML 应该是这样的:

<env:Header>
    <ns1:Security>
        <ns1:UsernameToken>
            <ns1:Username>XXXXXXXXXXXXXXXX</ns1:Username>
            <ns1:Password>YYYYYYYYYYYYYYYY</ns1:Password>
        </ns1:UsernameToken>
    </ns1:Security>
</env:Header>

提前致谢 J.

【问题讨论】:

    标签: c# web-services soap soap-client


    【解决方案1】:

    有很多方法可以做到这一点。 CustomBinding 更灵活,因为它允许更多控制,为此我建议您这样做。将标头传递到端点是一种简单的方法:

    // binding
    var binding = new CustomBinding();
    binding.Elements.Clear();
    binding.Elements.Add(new TextMessageEncodingBindingElement{MessageVersion = MessageVersion.Soap12});
    binding.Elements.Add(new HttpTransportBindingElement{MaxReceivedMessageSize = 20000000,});
    // endpoint
    var endpoint = new EndpointAddress(new Uri(listeningUri), new MySecurityHeader())
    var client = new Client(binding, endpoint);
    client.SomeMethod();
    

    其中 MySecurityHeader 是 AddressHeader,例如:

        public class MySecurityHeader : AddressHeader
        {
            public override string Name
            {
                get { return "Security"; }
            }
    
            public override string Namespace
            {
                get { return "<provide the appropiate namespace>"; }
            }
    
            protected override void OnWriteAddressHeaderContents(System.Xml.XmlDictionaryWriter writer)
            {
                // here you do what you want
                writer.WriteRaw(String.Format(@"
                 <UsernameToken xmlns=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"">
                 <Username>user</Username>
                 <Password Type=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"">pass</Password>
                 </UsernameToken>").Trim());
            }
        }
    

    【讨论】:

    • 我还有很多其他方法可以做到这一点,如果您需要,请告诉我。
    • 如果你能建议我一些替代方案,这对我很有帮助
    • 你在看什么?,因为使用端点非常简单。
    • 使用 BeforeSendRequest 修改soap标头
    • 好的,这是一个 IEndpointBehavior,让我给你展示一个如何使用它的示例
    【解决方案2】:

    这是一个使用 IEndpointAdress 的示例

        var customBinding = new CustomBinding();
        customBinding.Elements.Add(new TextMessageEncodingBindingElement { MessageVersion = MessageVersion.Soap12, });
        customBinding.Elements.Add(new HttpTransportBindingElement { MaxReceivedMessageSize = 20000000, });
    
        var endpointAddres = new EndpointAddress(listeningUri);
    
        var client = new Client(customBinding, endpointAddres);
        // add my own IEndpointBehavior
        client.ChannelFactory.Endpoint.Behaviors.Add(new CustomBehavior());
        client.SomeMethod();
    

    这是自定义行为定义

    public class CustomBehavior : IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {}
    
        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            var inspector = new CustomMessageInspector();
            clientRuntime.MessageInspectors.Add(inspector);
        }
    
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {}
    
        public void Validate(ServiceEndpoint endpoint)
        {}
    }
    
    public class CustomMessageInspector : IClientMessageInspector
    {
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {}
    
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            request.Headers.Add(new MyMessageHeader());
            return null;
        }
    }
    
    public class MyMessageHeader : MessageHeader
    {
    
        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            writer.WriteRaw(String.Format(@"
            <UsernameToken xmlns=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"">
            <Username>user</Username>
            <Password Type=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"">pass</Password>
            </UsernameToken>").Trim());
        }
    
        public override string Name
        {
            get { return "MyHeaderName"; }
        }
    
        public override string Namespace
        {
            get { return "MyHeaderNamespace"; }
        }
    }
    

    请注意,您可以在发送请求之前和收到回复之后进行控制。
    我希望这能解决您的问题,如果您对此有任何问题可以问我。

    【讨论】:

    • 我在这一行有错误: var client = new Client(customBinding, endpointAddres);即:找不到命名空间客户端的类型...
    • 您需要通过您的代理客户端(自动生成用于消费网络服务的类)更改您的客户端,然后调用它的方法,好吗?
    • System.InvalidOperationException 未处理 HResult=-2146233079 Message=Path 属性必须在调用 Send 方法之前设置。源 = System.Web.Services StackTrace:在 System.Web.Services.Protocols.WebClientProtocol.GetWebRequest(Uri uri) 在 System.Web.Services.Protocols.HttpWebClientProtocol.GetWebRequest(Uri uri) 在 System.Web.Services.Protocols。 SoapHttpClientProtocol.GetWebRequest(Uri uri) at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters) at
    • 哪一行抛出异常?
    • 使用fiddler(或sniffer)查看你通过http发送的soap消息是什么。如果消息与您期望的一致,则服务器必须正确响应。
    猜你喜欢
    • 2013-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 2020-02-15
    相关资源
    最近更新 更多