以编程方式将自定义 WCF 标头添加到端点以实现可靠会话
我正在构建一个 WCF 路由器,我的客户端使用可靠会话。在这种情况下,当客户端打开通道时,会发送一条消息(建立可靠会话?)。其内容如下:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-rx/wsrm/200702/CreateSequence</a:Action>
<a:MessageID>urn:uuid:1758f794-c5d3-4573-b252-7a07344cc257</a:MessageID>
<a:To s:mustUnderstand="1">http://localhost:8010/RouterService</a:To>
</s:Header>
<s:Body>
<CreateSequence xmlns="http://docs.oasis-open.org/ws-rx/wsrm/200702">
<AcksTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</AcksTo>
<Offer>
<Identifier>urn:uuid:64a12658-71d9-4967-88ec-9bb0610f7ecb</Identifier>
<Endpoint>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</Endpoint>
<IncompleteSequenceBehavior>DiscardFollowingFirstGap</IncompleteSequenceBehavior>
</Offer>
</CreateSequence>
</s:Body>
</s:Envelope>
这里的问题是标头不包含任何我可以用来查找将消息路由到哪个服务的信息。在 Busatmante 的路由器示例代码中,她通过向端点添加标头来解决此问题:
<client>
<endpoint address="http://localhost:8010/RouterService" binding="ws2007HttpBinding"
bindingConfiguration="wsHttp"
contract="localhost.IMessageManagerService" >
<headers>
<Route xmlns="http://www.thatindigogirl.com/samples/2008/01" >http://www.thatindigogirl.com/samples/2008/01/IMessageManagerService</Route>
</headers>
</endpoint>
</client>
当打开可靠会话时,消息包含此自定义标头。
<Route a:IsReferenceParameter="true" xmlns="http://www.thatindigogirl.com/samples/2008/01">http://www.thatindigogirl.com/samples/2008/01/IMessageManagerService</Route>
这太棒了;但是,我需要以编程方式配置客户端。我认为 ChannelFactory Endpoint 将有一个 Header 对象,我可以手动添加自定义标头。不幸的是事实并非如此。因此,我做了一些搜索,发现了一些通过实现 IClientMessageInspector 来添加我的标头并将其作为行为添加到我的端点来扩展 WCF 的建议。
public class ContractNameMessageInspector : IClientMessageInspector {
private const string HEADER_NAME = "ContractName";
private readonly string _ContractName;
public ContractNameMessageInspector(string contractName) {
_ContractName = contractName;
}
#region IClientMessageInspector Members
public void AfterReceiveReply(ref Message reply, object correlationState) { }
public object BeforeSendRequest(ref Message request, IClientChannel channel) {
HttpRequestMessageProperty httpRequestMessage;
object httpRequestMessageObject;
if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject)) {
httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
if (httpRequestMessage != null && string.IsNullOrEmpty(httpRequestMessage.Headers[HEADER_NAME])) {
httpRequestMessage.Headers[HEADER_NAME] = this._ContractName;
}
}
else {
httpRequestMessage = new HttpRequestMessageProperty();
httpRequestMessage.Headers.Add(HEADER_NAME, this._ContractName);
request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
}
return null;
}
#endregion
}
因此,当我的客户端进行服务调用时,消息包含自定义标头,但建立可靠会话的消息仍然不包含。
所以我的问题是;如何以编程方式将自定义标头添加到端点,以便可靠会话消息包含它?
非常感谢
I'm building a WCF router and my client uses Reliable Sessions. In this scenario when the client opens a channel a message is sent (establishing a Reliable Session?). Its contents is as follows:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-rx/wsrm/200702/CreateSequence</a:Action>
<a:MessageID>urn:uuid:1758f794-c5d3-4573-b252-7a07344cc257</a:MessageID>
<a:To s:mustUnderstand="1">http://localhost:8010/RouterService</a:To>
</s:Header>
<s:Body>
<CreateSequence xmlns="http://docs.oasis-open.org/ws-rx/wsrm/200702">
<AcksTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</AcksTo>
<Offer>
<Identifier>urn:uuid:64a12658-71d9-4967-88ec-9bb0610f7ecb</Identifier>
<Endpoint>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</Endpoint>
<IncompleteSequenceBehavior>DiscardFollowingFirstGap</IncompleteSequenceBehavior>
</Offer>
</CreateSequence>
</s:Body>
</s:Envelope>
The problem here is that the headers do not contain any information I can use to look up what service to route the message to. In Busatmante's router sample code she gets around this by adding a header to the endpoint:
<client>
<endpoint address="http://localhost:8010/RouterService" binding="ws2007HttpBinding"
bindingConfiguration="wsHttp"
contract="localhost.IMessageManagerService" >
<headers>
<Route xmlns="http://www.thatindigogirl.com/samples/2008/01" >http://www.thatindigogirl.com/samples/2008/01/IMessageManagerService</Route>
</headers>
</endpoint>
</client>
When the reliable session is opened the message contains this custom header.
<Route a:IsReferenceParameter="true" xmlns="http://www.thatindigogirl.com/samples/2008/01">http://www.thatindigogirl.com/samples/2008/01/IMessageManagerService</Route>
This is great; however, I have a requirement to configure the client programatically. I figured that the ChannelFactory Endpoint would have a Header object to which I could manually add my custom header. Unfortunately it does not. So I did some searching and found some recomendations to extend WCF by implementing an IClientMessageInspector to add my header and adding it as a behavior to my endpoint.
public class ContractNameMessageInspector : IClientMessageInspector {
private const string HEADER_NAME = "ContractName";
private readonly string _ContractName;
public ContractNameMessageInspector(string contractName) {
_ContractName = contractName;
}
#region IClientMessageInspector Members
public void AfterReceiveReply(ref Message reply, object correlationState) { }
public object BeforeSendRequest(ref Message request, IClientChannel channel) {
HttpRequestMessageProperty httpRequestMessage;
object httpRequestMessageObject;
if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject)) {
httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
if (httpRequestMessage != null && string.IsNullOrEmpty(httpRequestMessage.Headers[HEADER_NAME])) {
httpRequestMessage.Headers[HEADER_NAME] = this._ContractName;
}
}
else {
httpRequestMessage = new HttpRequestMessageProperty();
httpRequestMessage.Headers.Add(HEADER_NAME, this._ContractName);
request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
}
return null;
}
#endregion
}
So when my client makes a service call the message contains the custom header but the message establishing the Reliable Sessions still does not.
So my question is; how do I add a custom header to the Endpoint programatically in such a way that the reliable session message contains it?
Many Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
想通了。尽管没有属性或方法可以将标头添加到 EndpointAddress,但构造函数上有一个可选参数。
现在,当我收到建立可靠会话的消息时,它实际上包含我的自定义标头。这是有道理的,因为消息检查器很可能只对分派的消息进行操作,而建立可靠会话的消息是由较低级别的 WCF 代码生成的。
Figured it out. Although there is no property or method to add a header to an EndpointAddress there is an optional parameter on the constructor.
Now when I receive the message establishing the reliable session it actually does contain my custom header. This kinda makes sense as the message inspector most likely only operates on dispatched messages while the message establishing the reliable session is generated by lower level WCF code.
这对我有用
This works for me
要以编程方式添加地址标头,请参阅 MSDN 的 地址标头 其中可以以编程方式添加标头,例如:
To programmatically add address headers see MSDN's Address Headers where one can programmatically add a header such as: