使用 WS-MetadataExchange 为外部客户端和 WcfTestClient 从 Service Fabric 公开 WCF/TCP 终结点

Posted

技术标签:

【中文标题】使用 WS-MetadataExchange 为外部客户端和 WcfTestClient 从 Service Fabric 公开 WCF/TCP 终结点【英文标题】:Exposing WCF/TCP Endpoints from Service Fabric with WS-MetadataExchange for external clients and WcfTestClient 【发布时间】:2017-08-05 07:54:18 【问题描述】:

我有一个无状态服务,我正在将一些 CloudService WCF 端点迁移到该服务。这些端点是公开可用的,并且要求我能够通过 Visual Studio 项目的 References > 添加服务参考 以及 WS-MetadataExchange 发现它们的属性。 strong>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 对象,并且能够自定义它们的绑定/网址。我能够让客户很好地发现这些服务。我需要能够以相同的方式公开此服务,以便 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);

当我将它推送到我的本地集群时,我收到以下错误:

服务包含多个具有不同 ContractDescriptions 的 ServiceEndpoint,每个都有 Name='ITestContract' 和 Namespace='http://tempuri.org/'。 要么为 ContractDescriptions 提供唯一的名称和命名空间,要么确保 ServiceEndpoints 具有相同的 ContractDescription 实例。

我想也许我需要删除默认端点以避免这种冲突,所以我尝试了:

 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"));

这给了我以下错误:

副本在 API 调用中有多个失败:IStatelessServiceInstance.Open();错误 = System.NullReferenceException (-2147467261) 你调用的对象是空的。 在 Microsoft.ServiceFabric.Services.Communication.Wcf.Runtime.WcfCommunicationListener1.b__0(IAsyncResult ar) at System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task`1 承诺, 布尔 需要同步)

我已经尝试了其他一些具有相似结果的变体...

我还尝试在默认绑定上允许 MetadataExchange 行为(不创建任何其他端点)。但在这种情况下,我怎么知道我的端点 url 是什么?我尝试使用 net.tcp://localhost:8081/TestService应该 是默认设置),但我无法从控制台应用程序或 WcfTestClient。


更新 2

只需将 MetadataExchangeBinding 添加为附加端点并在其中分配所需的服务路径,我就能够根据需要托管我的 WCF 端点:

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"));

【问题讨论】:

【参考方案1】:

您可以通过访问主机属性在打开通信侦听器之前自定义 ServiceHost。

https://docs.microsoft.com/en-us/dotnet/api/microsoft.servicefabric.services.communication.wcf.runtime.wcfcommunicationlistener-1#Microsoft_ServiceFabric_Services_Communication_Wcf_Runtime_WcfCommunicationListener_1_ServiceHost

默认情况下,代码添加了一些行为,包括服务调试和限制行为,因此如果您删除 SDK 中提供的 WCF 客户端堆栈可能无法正常运行。

【讨论】:

谢谢!我尝试自定义 ServiceHost,但仍然遇到一些问题。我已更新我的问题以包含这些尝试。 再次感谢 VipulM - 感谢您的建议,我最终解决了这个问题。将更新我的发现。我确实遇到了一个新问题。你能看看这里吗:***.com/questions/42845939/…

以上是关于使用 WS-MetadataExchange 为外部客户端和 WcfTestClient 从 Service Fabric 公开 WCF/TCP 终结点的主要内容,如果未能解决你的问题,请参考以下文章

为啥 InnoDB 为外键列添加索引

RestKit:为外键关系创建存根

Django 会自动为外键列生成索引吗?

将主键修改为外键时出错

Django将登录的登录用户保存为外键

将登录用户的外键保存为外键