【问题标题】:How to programmatically add soap header when calling a WCF Service from .NET?从.NET调用WCF服务时如何以编程方式添加soap标头?
【发布时间】:2021-05-27 01:54:42
【问题描述】:

app.config 中的服务配置包含此设置:

<client>
  <endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_GenerateAndConvert" contract="GenerateAndConvert.MyPortType" name="MyGenerateAndConvert" >
    <headers>
      <AuthHeader>
        <username>abc</username>
        <password>xyz</password>
      </AuthHeader>
    </headers>
  </endpoint>
</client>

序列化为:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:MyServer">
   <soapenv:Header>
       <AuthHeader>
            <username>abc</username>
            <password>xyz</password>
          </AuthHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:Convert>
      </urn:Convert>
   </soapenv:Body>
</soapenv:Envelope>

我的问题是如何在 .NET 应用程序中使用服务引用时以编程方式添加 SOAP 标头(而不是在配置文件中定义用户名和密码)。

我尝试了https://stackoverflow.com/a/53208601/255966 之类的解决方案,但出现了异常,即作用域被设置在另一个线程上,可能是因为我调用了 WCF 服务 Async。

【问题讨论】:

  • 你看到this了吗?

标签: c# wcf soap header message


【解决方案1】:

您可以通过实现IClientMessageInspector接口在实现类中添加soap头。

     public class ClientMessageLogger : IClientMessageInspector
{
    public void AfterReceiveReply(ref Message reply, object correlationState)
    {

    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        MessageHeader header = MessageHeader.CreateHeader("MySoapHeader", "http://my-namespace.com", "asdas");
        request.Headers.Add(header);
        return null;
    }
}

将客户端消息记录器添加到客户端运行时:

    [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = false)]
public class CustContractBehaviorAttribute : Attribute, IContractBehavior, IContractBehaviorAttribute
{
    public Type TargetContract => throw new NotImplementedException();

    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        return;
    }

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(new ClientMessageLogger());
    }

    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
    {
    }

    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
    {
        return;
    }
}

向接口添加属性:

 [CustContractBehavior]
    public interface IService {
    }

这是服务器收到的soap消息:

想了解更多关于IClientMessageInspector,请参考以下link

【讨论】:

    【解决方案2】:

    感谢有关此问题的 cmets/answers 和这些额外资源,我得到了它的工作:

    我的解决方法如下:

    AuthHeader

    创建扩展 MessageHeader 的 AuthHeader 类以使用用户名和密码创建 AuthHeader:

    public class AuthHeader : MessageHeader
    {
        private readonly string _username;
        private readonly string _password;
    
        public AuthHeader(string username, string password)
        {
            _username = username ?? throw new ArgumentNullException(nameof(username));
            _password = password ?? throw new ArgumentNullException(nameof(password));
        }
    
        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            writer.WriteStartElement("username");
            writer.WriteString(_username);
            writer.WriteEndElement();
    
            writer.WriteStartElement("password");
            writer.WriteString(_password);
            writer.WriteEndElement();
        }
    
        public override string Name => "AuthHeader";
    
        public override string Namespace => string.Empty;
    }
    

    HttpHeaderMessageInspector

    创建一个 HttpHeaderMessageInspector,可用于将MessageHeader 添加到请求消息中。

    public class HttpHeaderMessageInspector : IClientMessageInspector
    {
        private readonly MessageHeader[] _headers;
    
        public HttpHeaderMessageInspector(params MessageHeader[] headers)
        {
            _headers = headers;
        }
    
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            foreach (var header in _headers)
            {
                request.Headers.Add(header);
            }
    
            return null;
        }
    
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
        }
    }
    

    AddHttpHeaderMessageEndpointBehavior

    创建一个使用 HttpHeaderMessageInspector 的特定 EndpointBehavior。

    public class AddHttpHeaderMessageEndpointBehavior : IEndpointBehavior
    {
        private readonly IClientMessageInspector _httpHeaderMessageInspector;
    
        public AddHttpHeaderMessageEndpointBehavior(params MessageHeader[] headers)
        {
            _httpHeaderMessageInspector = new HttpHeaderMessageInspector(headers);
        }
    
        public void Validate(ServiceEndpoint endpoint)
        {
        }
    
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }
    
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
        }
    
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.ClientMessageInspectors.Add(_httpHeaderMessageInspector);
        }
    }
    

    客户

    创建一个添加自定义 EndpointBehavior 的客户端,以在 Soap 消息中插入 MessageHeader。

    private MyTestPortTypeClient CreateAuthenticatedClient()
    {
        var client = new MyTestPortTypeClient(_settings.EndpointConfigurationName, _settings.EndpointAddress);
        client.Endpoint.EndpointBehaviors.Clear();
    
        var authHeader = new AuthHeader(_settings.UserName, _settings.Password);
        client.Endpoint.EndpointBehaviors.Add(new AddHttpHeaderMessageEndpointBehavior(authHeader));
    
        return client;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-23
      • 1970-01-01
      • 1970-01-01
      • 2020-12-06
      • 2020-10-28
      • 1970-01-01
      相关资源
      最近更新 更多