WCF使用AddressHeader.CreateAddressHeader()方法添加标题问题

时间:2016-09-29 14:45:22

标签: c# wcf

我尝试通过WCF向每个传出请求消息添加自定义标头。

我创建了这样的标题对象:

EndpointAddressBuilder eab = new EndpointAddressBuilder(combinedService.Endpoint.Address);
AddressHeader addressHeader = AddressHeader.CreateAddressHeader("HeaderData", String.Empty, "String data");
eab.Headers.Add(addressHeader);
combinedService.Endpoint.Address = eab.ToEndpointAddress();

我在代码中的两个位置使用这个确切的代码,一个很好但另一个不好。 问题出现在以下代码行中:

AddressHeader addressHeader = AddressHeader.CreateAddressHeader("HeaderData", String.Empty, "String data");

当它工作时(成功传递标题数据),创建的对象如下所示: enter image description here

但是当它不起作用时,创建的对象看起来像这样: enter image description here

完全相同的方法可以做到这一点,但是两个位置代码调用会产生不同的结果。

我是否应该在addressHeader对象上执行任何强制序列化对象的方法?可能是这样的:Flush()

我知道我可以使用几种众所周知的添加自定义标题的模式,例如:"自定义行为","客户端消息检查器"等...但我要求在发送消息之前将其添加到特定点。

1 个答案:

答案 0 :(得分:1)

我终于得到了解决方案。

我只是按照thisthis优秀,详细和简单文章中的步骤进行了操作。

虽然这段代码似乎很长并且很复杂,但这是在WCF中处理标头数据的最佳方式。所以它最终值得。

您只需配置自定义行为即可处理WCF标头。

这是怎么回事:

客户端:

public class FillHeaderDataBehaviourExtension : BehaviorExtensionElement, IEndpointBehavior
{
    #region BehaviorExtensionElement Implementation
    public override Type BehaviorType
    {
        get
        {
            return typeof(FillHeaderDataBehaviourExtension);
        }
    }
    protected override object CreateBehavior()
    {
        return this;
    }
    #endregion

    #region IServiceBehaviour Implementation
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
    }
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {

    }
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }

    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(new MessageInspector());
    }
    #endregion
}

public class MessageInspector : IClientMessageInspector
{
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        MessageHeader header = MessageHeader.CreateHeader("HeaderData", String.Empty, HeaderDataVM.GetInstance().GetBaseInstance());
        request.Headers.Add(header); // There is no need for checking if exist before adding. Every request has it's own headers.

        return null;
    }
    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
    }
}

服务器端:

public class ExtractHeadersBehaviourExtension : BehaviorExtensionElement, IServiceBehavior
{
    #region BehaviorExtensionElement Implementation
    public override Type BehaviorType
    {
        get
        {
            return typeof(ExtractHeadersBehaviourExtension);
        }
    }
    protected override object CreateBehavior()
    {
        return this;
    }
    #endregion

    #region IServiceBehavior Implementation
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
    }
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++)
        {
            ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher;
            if (channelDispatcher != null)
            {
                foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
                {
                    MessageInspector inspector = new MessageInspector();
                    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
                }
            }
        }
    }
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
    #endregion
}

public class MessageInspector : IDispatchMessageInspector
{
    public void BeforeSendReply(ref Message reply, object correlationState)
    {
    }
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        HeaderData headerData = request.Headers.GetHeader<HeaderData>("HeaderData", String.Empty);

        if(headerData != null)
        {
            OperationContext.Current.IncomingMessageProperties.Add("HeaderData", headerData);
        }

        return null;
    }
}

最后,不要忘记在app.config文件(客户端和服务器端)中进行配置,如下所示:

<behaviors>
  <endpointBehaviors>
    <behavior name="NewBehavior">
      <fillHeaderDataBehaviourExtension/>
    </behavior>
  </endpointBehaviors>
</behaviors>
<bindings>

您还可以通过WCF配置编辑器添加这些行。为此,请查看this answer。

重要:请注意,在添加以下配置代码后,您将在应用配置中收到错误消息:

enter image description here

不要担心这一点,您的应用程序将正常运行。这是因为GAC(全局程序集缓存)文件夹不包含此行为(因为它是自定义行为)。您可以通过手动将此行为添加到计算机上的GAC文件夹来解决此问题。 但是,此错误可能会阻止您更新服务引用。如果您尝试,则会收到以下错误消息:

enter image description here

因此,只需在更新服务参考时注释掉此行(<extractHeadersBehaviourExtension/>)(在客户端和服务器端)。