简体   繁体   English

从 Z303CB0EF9EDB9082D61BBBE572 调用 WCF 服务时,如何以编程方式添加 soap header?

[英]How to programmatically add soap header when calling a WCF Service from .NET?

The service configuration in the app.config contains this setting: 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>

which is serialized as:序列化为:

<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>

My question is how to programmatically add the SOAP Header (instead defining the username and password in the config file) when using a Service Reference in a .NET application.我的问题是在 .NET 应用程序中使用服务参考时,如何以编程方式添加 SOAP Header(而不是在配置文件中定义用户名和密码)。

I tried a solution like https://stackoverflow.com/a/53208601/255966 , but I got exceptions that scope was disposed on another thread, probably because I call the WCF service Async.我尝试了像https://stackoverflow.com/a/53208601/255966这样的解决方案,但我遇到了 scope 被配置在另一个线程上的异常,可能是因为我调用了 ZFB608Z936129FECB2BB59B67 服务。

You can add soap header in the implementation class by implementing IClientMessageInspector interface.您可以通过实现 IClientMessageInspector 接口在实现 class 中添加 soap header。

     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;
    }
}

Add clientmessagelogger to clientruntime:将 clientmessagelogger 添加到 clientruntime:

    [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;
    }
}

Add Attribute to Interface:向接口添加属性:

 [CustContractBehavior]
    public interface IService {
    }

This is the soap message received by the server:这是服务器收到的 soap 消息:

在此处输入图像描述

To learn more about IClientMessageInspector, please refer to the following link .要了解有关 IClientMessageInspector 的更多信息,请参阅以下链接

I got it working thanks to the comments/answers on this question and these additional resources:由于对此问题的评论/答案以及这些附加资源,我得到了它的工作:

My solution is as follows:我的解决方案如下:

AuthHeader验证头

Create AuthHeader class which extends MessageHeader to create the AuthHeader with username and password:创建 AuthHeader class 扩展 MessageHeader 以使用用户名和密码创建 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

Create a HttpHeaderMessageInspector which can be used to add a MessageHeader to the request message.创建一个 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 AddHttpHeaderMessageEndpointBehavior

Create a specific EndpointBehavior which uses the HttpHeaderMessageInspector.创建一个使用 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);
    }
}

Client客户

Create a Client which adds a custom EndpointBehavior to insert the MessageHeader in the Soap message.创建一个添加自定义 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM