1

我们有两个 Service Fabric 无状态服务。我们已将 Service Fabric 运行时升级到最新版本,现在想使用最新的 V2(V2_1) 运行时进行通信。我们还将 Service Fabric SDK 升级到了最新版本。

  1. 数学服务。它有两个暴露于通信的端点。
  2. EvilMathTeacherService。它调用这两个端点来做一些事情。它还暴露了一个端点。

这两个服务可以使用最新的 V2(V2_1) 运行时相互通信。我们有另一个应用程序,一个 WinForm 应用程序,它想要调用 EvilMathTeacherService 来让它做一些坏事。问题是当我们使用 V2(V2_1) 运行时从位于结构集群外部的这个 Winform 应用程序调用服务结构服务时,它不起作用。它不做任何事情。

所以我的问题是——我能做些什么来实现它吗?或者在最新的 V2(V2_1) 运行时中是否无法从外部与服务进行通信?我们可以使用 V1 运行时来做到这一点,而且在旧的 V1 运行时中它完全没问题。

代码示例:(相关部分)

服务 1:MathService.cs

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
  return new[]
 {
     new ServiceInstanceListener(
      context => new FabricTransportServiceRemotingListener(
        context,
        _mathCalculator_v2,
        new FabricTransportRemotingListenerSettings()
        {
            EndpointResourceName = "MathCalculator_v2"
        }),
      "MathCalculator_v2"),
     new ServiceInstanceListener(
      context => new FabricTransportServiceRemotingListener(
        context,
        _textManipulator_v2,
        new FabricTransportRemotingListenerSettings()
        {
            EndpointResourceName = "TextManipulator_v2"
        }),
      "TextManipulator_v2")
 };
}

服务清单:

<Resources>
<Endpoints>
  <!-- This endpoint is used by the communication listener to obtain the port on which to 
       listen. Please note that if your service is partitioned, this port is shared with 
       replicas of different partitions that are placed in your code. -->
  <Endpoint Name="ServiceEndpointV2_1" />
</Endpoints>

服务 2:EvilMathTeacherService.cs

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
  return new[]
 {
       new ServiceInstanceListener(
        context => new FabricTransportServiceRemotingListener(
          context,
          _questionnaire,
          new FabricTransportRemotingListenerSettings()
          {
              EndpointResourceName = "Questionnaire_v2"

          }),
        "Questionnaire_v2")
   };
}

在 RunAsync 方法中:

protected override async Task RunAsync(CancellationToken cancellationToken)
{
  // TODO: Replace the following sample code with your own logic 
  //       or remove this RunAsync override if it's not needed in your service.

  long iterations = 0;
  while (true)
  {
    cancellationToken.ThrowIfCancellationRequested();
    ServiceEventSource.Current.ServiceMessage(this.Context, "Evil teacher is coming to get you!-{0}", ++iterations);

    Random r = new Random();
    int first = r.Next(0, 100);
    var second = r.Next(200, 400);


    try
    {
      var sum = await _questionnaire.AddTwoNumbers(first, second);

      ServiceEventSource.Current.ServiceMessage(this.Context, "Evil Math teacher says - Sum-{0}", sum);

      var ifEqual = await _questionnaire.CheckIfTwoNumbersAreEqual(first, second);
      ServiceEventSource.Current.ServiceMessage(this.Context, "Evil Math teacher says - If Equal-{0}", ifEqual);

    }
    catch (Exception ex)
    {

      throw;
    }
    await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
  }
}

这是调用 MathService 的 Questionnaire.cs 类

public async Task<int> AddTwoNumbers(int a, int b)
{
  var uri = new Uri("fabric:/SampleSFV2/MathService");
  var proxyFactory = new ServiceProxyFactory((c) =>
  {
    var settings = new FabricTransportRemotingSettings();
    return new FabricTransportServiceRemotingClientFactory(settings);
  });

  var service = proxyFactory.CreateServiceProxy<IMathCalculator>(uri, listenerName: "MathCalculator_v2");

  return await service.Add(a, b);
}

public async Task<bool> CheckIfTwoNumbersAreEqual(int a, int b)
{
  var text1 = a.ToString();
  var text2 = b.ToString();

  var uri = new Uri("fabric:/SampleSFV2/MathService");
  var proxyFactory = new ServiceProxyFactory((c) =>
  {
    var settings = new FabricTransportRemotingSettings();
    return new FabricTransportServiceRemotingClientFactory(settings);
  });

  var service = proxyFactory.CreateServiceProxy<ITextManipulator>(uri, listenerName: "TextManipulator_v2");

  return await service.IfEqual(text1, text2);
}

这按预期工作。但是,当我从我的 winform 应用程序对 EvilMathTeacherService 或 MathService 本身进行类似调用时,该调用似乎并没有到达服务。

Winform应用部分:Form1.cs

private async void button_AddNumbers_Click(object sender, EventArgs e)
{
  //int number1 = int.Parse(textBox_Number1.Text);
  //int number2 = int.Parse(textBox_Number2.Text);

  //var uri = _evilMathServiceUri;

  int number1 = 10;
  int number2 = 100;

  var uri = new Uri("fabric:/SampleSFV2/EvilMathTeacherService");

  ServiceProxyFactory proxyFactory = new ServiceProxyFactory((c) =>
  {
    FabricTransportRemotingSettings settings = new FabricTransportRemotingSettings();
    return new FabricTransportServiceRemotingClientFactory(settings);
  });

  try
  {
    IQuestionnaire service = proxyFactory.CreateServiceProxy<IQuestionnaire>(uri, listenerName: "Questionnaire_v2");
    int result = await service.AddTwoNumbers(number1, number2);

    MessageBox.Show("Result= " + result);
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.ToString());
  }
}

我从他们的官方文档中关注这个链接- https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-remoting#how-to-use-remoting- v2 堆栈

请指出我在这里遗漏的任何内容。再次断言 - 我在使用 Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime 从结构集群外部的 Winform 应用程序调用服务时遇到问题。

或者这不能再使用 V2 运行时完成?因为我们正在使用 V1 运行时成功地做同样的事情。

示例代码项目:

https://github.com/nirjash13/azure-service-fabric

4

1 回答 1

0

首先澄清一点困惑,没有“V1 Service Fabric 运行时”或“V2 Service Fabric 运行时”。您看到的是 Service Remoting,它是 Service Fabric 的 .NET RPC 实现(客户端上的 Microsoft.ServiceFabric.Services.Remoting 命名空间和 ServiceProxyFactory)。

默认情况下,服务远程处理仅适用于集群内的服务之间,因为它使用临时范围内随机分配的端口,这假定客户端-服务器之间的直接连接。如果您有一个像负载平衡器这样的 NAT 设备,需要明确打开端口,这将不起作用。

服务远程处理在 Service Fabric 中是完全可选的,您不必使用它。对于客户端通信,我强烈建议您不要使用它,因为它会将您的客户端应用程序与您的后端服务(甚至共享程序集)紧密耦合,并且稍后对您的 API 进行版本控制将是一场噩梦。我建议在您的 SF 服务中使用 ASP.NET Core 来将 HTTP API 公开给您的 WebForms 应用程序。

于 2018-10-19T19:30:04.873 回答