[英]WCF discovery with service hosts using net.tcp://0.0.0.0:0/blah announces net.tcp://0.0.0.0:0/blah
我想要一个可发现的服务,它将监听所有接口并发布每个接口的发现公告。 我希望最终能够使用tcp://0.0.0.0:0 / blah作为服务端点在配置文件中配置它。 但是当我运行下面的代码时,它发出的通知使用tcp://0.0.0.0:0 / blah作为对客户端无用的EndpointAddress。
我想收到从tcp派生的每个端点的公告://0.0.0.0:0 / blah我更喜欢使用配置文件而不是下面的程序化服务主机设置。 任何解决方法的想法?
[TestFixtureSetUp]
public void SetUp()
{
service1 = new MyContract();
EndpointDiscoveryBehavior discoveryBehavior = new EndpointDiscoveryBehavior();
ServiceDiscoveryBehavior serviceDiscoveryBehavior = new ServiceDiscoveryBehavior(discoveryUri);
serviceDiscoveryBehavior.AnnouncementEndpoints.Add(new UdpAnnouncementEndpoint(announcementUri));
serviceHost1 = new ServiceHost(service1,
new Uri[] {new Uri("net.pipe://localhost"), new Uri("net.tcp://0.0.0.0:0")});
ServiceEndpoint localEndpoint1 = serviceHost1.AddServiceEndpoint(typeof (IContract),
new NetNamedPipeBinding(),
"/Pipe");
ServiceEndpoint localEndpoint2 = serviceHost1.AddServiceEndpoint(typeof (IContract),
new NetTcpBinding(),
"/Tcp");
localEndpoint2.Behaviors.Add(discoveryBehavior);
serviceHost1.Description.Behaviors.Add(serviceDiscoveryBehavior);
serviceHost1.AddServiceEndpoint(new UdpDiscoveryEndpoint(discoveryUri));
serviceHost1.Open();
}
虽然我的解决方案可能不是“正确的”,严格来说(如果你问我,这应该在WCF本身中确定),它可以工作,并且足以达到我的目的。
首先,声明一个新的端点行为,如下所示:
public class WcfDiscoveryAddressFixEndpointBehavior : IEndpointBehavior, IDispatchMessageInspector
{
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
// Attach ourselves to the MessageInspectors of reply messages
clientRuntime.CallbackDispatchRuntime.MessageInspectors.Add(this);
}
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
object messageProperty;
if (!OperationContext.Current.IncomingMessageProperties.TryGetValue(RemoteEndpointMessageProperty.Name, out messageProperty)) return null;
var remoteEndpointProperty = messageProperty as RemoteEndpointMessageProperty;
if (remoteEndpointProperty == null) return null;
// Extract message body
string messageBody;
using (var oldMessageStream = new MemoryStream())
{
using (var xw = XmlWriter.Create(oldMessageStream))
{
request.WriteMessage(xw);
xw.Flush();
messageBody = Encoding.UTF8.GetString(oldMessageStream.ToArray());
}
}
// Replace instances of 0.0.0.0 with actual remote endpoint address
messageBody = messageBody.Replace("0.0.0.0", remoteEndpointProperty.Address);
// NOTE: Do not close or dispose of this MemoryStream. It will be used by WCF down the line.
var newMessageStream = new MemoryStream(Encoding.UTF8.GetBytes(messageBody));
XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(newMessageStream, new XmlDictionaryReaderQuotas());
// Create a new message with our modified endpoint address and
// copy over existing properties and headers
Message newMessage = Message.CreateMessage(xdr, int.MaxValue, request.Version);
newMessage.Properties.CopyProperties(request.Properties);
newMessage.Headers.CopyHeadersFrom(request.Headers);
request = newMessage;
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
}
此端点行为将原始WCF发现回复消息替换为一个副本,其中0.0.0.0
实例已替换为接收消息的地址,可在RemoteEndpointMessageProperty
的Address
属性中找到。
要使用它,只需在创建DiscoveryClient
时将新端点行为添加到UdpDiscoveryEndpoint
:
var udpDiscoveryEndpoint = new UdpDiscoveryEndpoint();
udpDiscoveryEndpoint.EndpointBehaviors.Add(new WcfDiscoveryAddressFixEndpointBehavior());
_discoveryClient = new DiscoveryClient(udpDiscoveryEndpoint);
// Proceed as usual.
我找到了另一种解决方案,无需更改消息。
我注意到端点有一个address
和一个listening address
。 我们的想法是为每个IP地址创建一个端点,并只共享一个监听地址(0.0.0.0或使用机器名称来获取ipv6)。
在发现方面,将收到所有地址,有人可以尝试连接以查找哪些地址可以到达。
Ther服务器部件如下所示:
var listenUri = new Uri("net.tcp://<Environment.MachineName>:<port>/IServer";
var binding = new NetTcpBinding(SecurityMode.None);
foreach (ip address)
{
var addr = new Uri("net.tcp://<ip>:<port>/IServer");
Host.AddServiceEndpoint(typeof(IService), binding, addr, listenUri)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.