使用 WS-MetadataExchange 为外部客户端和 WcfTestClient 公开来自 Service Fabric 的 WCF/TCP 个端点
Exposing WCF/TCP Endpoints from Service Fabric with WS-MetadataExchange for external clients and WcfTestClient
我有一个无状态服务,我正在将一些 CloudService WCF 端点迁移到该服务。这些点是公开可用的,并且要求我能够使用 WS-MetadataExchange 通过 References > Add Service Reference 从 Visual Studio 项目以及来自 WCFTestClient.
我已经学习了一些教程并设置了测试端点:
<Endpoint Protocol="tcp" Name="WcfServiceEndpoint" Type="Input" Port="8081" />
以及服务合同
[ServiceContract]
public interface ITestContract
{
[OperationContract]
int TestMethod(int value1, int value2);
}
方法:
public class TestService : ITestContract
{
public int TestMethod(int value1, int value2)
{
var result = value1 + value2;
return result;
}
}
还有一个服务侦听器覆盖:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[] { new ServiceInstanceListener((context) =>
new WcfCommunicationListener<ITestContract>(
this.Context,
new TestService(),
WcfUtility.CreateTcpClientBinding(),
"WcfServiceEndpoint"
)
)};
在我以前的项目(我正在从中迁移)中,我设置了自定义 ServiceHost 对象并且能够自定义它们的 bindings/Urls。我能够让客户很好地发现这些服务。我需要能够以相同的方式公开此服务,以便 WcfTestClient 以及 References > Add Service Reference 可以使用 WS-MetadataExchange。就目前而言,我什至无法控制服务路径!
理想情况下,我仍想使用 ServiceHost:
var host = new ServiceHost(ITestContract);
host.AddServiceEndpoint(TestService, new NetTcpBinding(SecurityMode.None), "net.tcp://...", new Uri("net.tcp://..."));
host.Description.Behaviors.Remove(typeof(ServiceDebugBehavior));
host.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
host.Open();
更新
根据VipulM-MSFT的建议(下)我现在先创建通信监听器:
var testCommunicationListener = new WcfCommunicationListener<ITestContract>(
this.Context,
new TestService(),
WcfUtility.CreateTcpClientBinding(),
"WcfServiceEndpoint"
);
然后修改 ServiceHost 对象以允许 MetadataExchange 行为:
ServiceMetadataBehavior metaDataBehavior = new ServiceMetadataBehavior();
testCommunicationListener.ServiceHost.Description.Behaviors.Add(metaDataBehavior);
以及允许故障中的异常详细信息:
testCommunicationListener.ServiceHost.Description.Behaviors.Remove(typeof(ServiceDebugBehavior));
testCommunicationListener.ServiceHost.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
然后我创建一个服务端点(使用我想要的服务路径):
testCommunicationListener.ServiceHost.AddServiceEndpoint(typeof(ITestContract), new NetTcpBinding(SecurityMode.None), "net.tcp://localhost:8081/Services/Tests", new Uri("net.tcp://localhost:8081/Services/Tests"));
以及 MexEndpoint(以允许通过 TCP 进行 MetaExchange 绑定):
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
testCommunicationListener.ServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, "net.tcp://localhost:8081/Services/Tests/mex", new Uri("net.tcp://localhost:8081/Services/Tests/mex"));
最后我将侦听器分配给无状态服务:
return new[] { new ServiceInstanceListener((context) => testCommunicationListener)};
当我将其推送到我的本地集群时,出现以下错误:
The Service contains multiple ServiceEndpoints with different ContractDescriptions which each have Name='ITestContract' and Namespace='http://tempuri.org/'.
Either provide ContractDescriptions with unique Name and Namespaces, or ensure the ServiceEndpoints have the same ContractDescription instance.
我想也许我需要删除默认端点以避免这种冲突,所以我尝试了:
testCommunicationListener.ServiceHost.Description.Endpoints.RemoveAt(0);
调用之前:
testCommunicationListener.ServiceHost.AddServiceEndpoint(typeof(ITestContract), new NetTcpBinding(SecurityMode.None), "net.tcp://localhost:8081/Services/Tests", new Uri("net.tcp://localhost:8081/Services/Tests"));
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
testCommunicationListener.ServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, "net.tcp://localhost:8081/Services/Tests/mex", new Uri("net.tcp://localhost:8081/Services/Tests/mex"));
这给了我以下错误:
Replica had multiple failures in API call: IStatelessServiceInstance.Open(); Error =
System.NullReferenceException (-2147467261)
Object reference not set to an instance of an object.
at Microsoft.ServiceFabric.Services.Communication.Wcf.Runtime.WcfCommunicationListener1.b__0(IAsyncResult
ar)
at System.Threading.Tasks.TaskFactory
1.FromAsyncCoreLogic(IAsyncResult
iar, Func2 endFunction, Action
1 endAction, Task`1 promise, Boolean
requiresSynchronization)
我已经尝试了其他一些具有相似结果的变体...
我还尝试在默认绑定上允许 MetadataExchange 行为(不创建任何其他端点)。但在这种情况下,我怎么知道我的端点 url 是什么?我尝试使用 net.tcp://localhost:8081/TestService ( 应该默认值)但我无法从控制台应用程序或 WcfTestClient 连接到它。
更新 2
我能够根据需要托管我的 WCF 端点,只需将 MetadataExchangeBinding 添加为附加端点并在以下范围内分配我所需的服务路径:
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
testCommunicationListener.ServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, "net.tcp://localhost:8081/Services/Tests/mex", new Uri("net.tcp://localhost:8081/Services/Tests/mex"));
您可以通过访问主机属性在打开通信监听器之前自定义ServiceHost。
默认情况下,代码会添加一些行为,包括服务调试和限制行为,因此如果您删除 SDK 中提供的 WCF 客户端堆栈,则可能无法正常运行。
我有一个无状态服务,我正在将一些 CloudService WCF 端点迁移到该服务。这些点是公开可用的,并且要求我能够使用 WS-MetadataExchange 通过 References > Add Service Reference 从 Visual Studio 项目以及来自 WCFTestClient.
我已经学习了一些教程并设置了测试端点:
<Endpoint Protocol="tcp" Name="WcfServiceEndpoint" Type="Input" Port="8081" />
以及服务合同
[ServiceContract]
public interface ITestContract
{
[OperationContract]
int TestMethod(int value1, int value2);
}
方法:
public class TestService : ITestContract
{
public int TestMethod(int value1, int value2)
{
var result = value1 + value2;
return result;
}
}
还有一个服务侦听器覆盖:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[] { new ServiceInstanceListener((context) =>
new WcfCommunicationListener<ITestContract>(
this.Context,
new TestService(),
WcfUtility.CreateTcpClientBinding(),
"WcfServiceEndpoint"
)
)};
在我以前的项目(我正在从中迁移)中,我设置了自定义 ServiceHost 对象并且能够自定义它们的 bindings/Urls。我能够让客户很好地发现这些服务。我需要能够以相同的方式公开此服务,以便 WcfTestClient 以及 References > Add Service Reference 可以使用 WS-MetadataExchange。就目前而言,我什至无法控制服务路径!
理想情况下,我仍想使用 ServiceHost:
var host = new ServiceHost(ITestContract);
host.AddServiceEndpoint(TestService, new NetTcpBinding(SecurityMode.None), "net.tcp://...", new Uri("net.tcp://..."));
host.Description.Behaviors.Remove(typeof(ServiceDebugBehavior));
host.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
host.Open();
更新
根据VipulM-MSFT的建议(下)我现在先创建通信监听器:
var testCommunicationListener = new WcfCommunicationListener<ITestContract>(
this.Context,
new TestService(),
WcfUtility.CreateTcpClientBinding(),
"WcfServiceEndpoint"
);
然后修改 ServiceHost 对象以允许 MetadataExchange 行为:
ServiceMetadataBehavior metaDataBehavior = new ServiceMetadataBehavior();
testCommunicationListener.ServiceHost.Description.Behaviors.Add(metaDataBehavior);
以及允许故障中的异常详细信息:
testCommunicationListener.ServiceHost.Description.Behaviors.Remove(typeof(ServiceDebugBehavior));
testCommunicationListener.ServiceHost.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
然后我创建一个服务端点(使用我想要的服务路径):
testCommunicationListener.ServiceHost.AddServiceEndpoint(typeof(ITestContract), new NetTcpBinding(SecurityMode.None), "net.tcp://localhost:8081/Services/Tests", new Uri("net.tcp://localhost:8081/Services/Tests"));
以及 MexEndpoint(以允许通过 TCP 进行 MetaExchange 绑定):
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
testCommunicationListener.ServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, "net.tcp://localhost:8081/Services/Tests/mex", new Uri("net.tcp://localhost:8081/Services/Tests/mex"));
最后我将侦听器分配给无状态服务:
return new[] { new ServiceInstanceListener((context) => testCommunicationListener)};
当我将其推送到我的本地集群时,出现以下错误:
The Service contains multiple ServiceEndpoints with different ContractDescriptions which each have Name='ITestContract' and Namespace='http://tempuri.org/'. Either provide ContractDescriptions with unique Name and Namespaces, or ensure the ServiceEndpoints have the same ContractDescription instance.
我想也许我需要删除默认端点以避免这种冲突,所以我尝试了:
testCommunicationListener.ServiceHost.Description.Endpoints.RemoveAt(0);
调用之前:
testCommunicationListener.ServiceHost.AddServiceEndpoint(typeof(ITestContract), new NetTcpBinding(SecurityMode.None), "net.tcp://localhost:8081/Services/Tests", new Uri("net.tcp://localhost:8081/Services/Tests"));
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
testCommunicationListener.ServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, "net.tcp://localhost:8081/Services/Tests/mex", new Uri("net.tcp://localhost:8081/Services/Tests/mex"));
这给了我以下错误:
Replica had multiple failures in API call: IStatelessServiceInstance.Open(); Error = System.NullReferenceException (-2147467261) Object reference not set to an instance of an object. at Microsoft.ServiceFabric.Services.Communication.Wcf.Runtime.WcfCommunicationListener
1.b__0(IAsyncResult ar) at System.Threading.Tasks.TaskFactory
1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action
1 endAction, Task`1 promise, Boolean requiresSynchronization)
我已经尝试了其他一些具有相似结果的变体...
我还尝试在默认绑定上允许 MetadataExchange 行为(不创建任何其他端点)。但在这种情况下,我怎么知道我的端点 url 是什么?我尝试使用 net.tcp://localhost:8081/TestService ( 应该默认值)但我无法从控制台应用程序或 WcfTestClient 连接到它。
更新 2
我能够根据需要托管我的 WCF 端点,只需将 MetadataExchangeBinding 添加为附加端点并在以下范围内分配我所需的服务路径:
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
testCommunicationListener.ServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, "net.tcp://localhost:8081/Services/Tests/mex", new Uri("net.tcp://localhost:8081/Services/Tests/mex"));
您可以通过访问主机属性在打开通信监听器之前自定义ServiceHost。
默认情况下,代码会添加一些行为,包括服务调试和限制行为,因此如果您删除 SDK 中提供的 WCF 客户端堆栈,则可能无法正常运行。