我尝试通过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");
完全相同的方法可以做到这一点,但是两个位置代码调用会产生不同的结果。
我是否应该在addressHeader
对象上执行任何强制序列化对象的方法?可能是这样的:Flush()
?
我知道我可以使用几种众所周知的添加自定义标题的模式,例如:"自定义行为","客户端消息检查器"等...但我要求在发送消息之前将其添加到特定点。
答案 0 :(得分:1)
我终于得到了解决方案。
我只是按照this和this优秀,详细和简单文章中的步骤进行了操作。
虽然这段代码似乎很长并且很复杂,但这是在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。
重要:请注意,在添加以下配置代码后,您将在应用配置中收到错误消息:
不要担心这一点,您的应用程序将正常运行。这是因为GAC(全局程序集缓存)文件夹不包含此行为(因为它是自定义行为)。您可以通过手动将此行为添加到计算机上的GAC文件夹来解决此问题。 但是,此错误可能会阻止您更新服务引用。如果您尝试,则会收到以下错误消息:
因此,只需在更新服务参考时注释掉此行(<extractHeadersBehaviourExtension/>
)(在客户端和服务器端)。