How to call a service fabric service from a Winform application?

允我心安 提交于 2020-01-05 04:19:15

问题


We have two Service Fabric stateless services. We have upgraded our service fabric runtime to the latest version and now want to use the latest V2(V2_1) runtime for communication. We have also upgraded the Service Fabric SDK to the latest version.

  1. MathService. It has two endpoints exposed to communication.
  2. EvilMathTeacherService. It calls those two endpoints to do some things. It also has an endpoint exposed.

These two services can talk to each other using the latest V2(V2_1) runtime. We have another application, a WinForm application, that wants to call the EvilMathTeacherService to make it do something evil. Problem is when we use the V2(V2_1) runtime to make the call to the service fabric service/s from this Winform application which resides outside the fabric cluster, it does not work. It does not do anything.

So my question would be- is there anything I can do to make it happen? Or is there no way to communicate to the services from outside in the latest V2(V2_1) runtime? We are able to do this using the V1 runtime and it's perfectly fine in the old V1 runtime.

Code sample: (Relevant portion)

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

ServiceManifest:

<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>

Service 2: EvilMathTeacherService.cs

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

          }),
        "Questionnaire_v2")
   };
}

In the RunAsync Method:

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

This is the Questionnaire.cs class that's making the call to the MathService

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

This is working as expected. But when I make a similar call from my winform application to the EvilMathTeacherService or the MathService itself, the call doesn't seem to make it to the services.

Winform application portion: 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());
  }
}

I am following this link from their official documentation- https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-remoting#how-to-use-remoting-v2-stack

Please point out anything I am missing here. To assert again - I am having the problem when calling the services from a Winform application outside the fabric cluster using the Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime.

Or this cannot be done using the V2 runtime anymore? Because we are doing the same thing successfully using the V1 runtime.

Sample code project:

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


回答1:


Just to clear up a little confusion first, there is no "V1 Service Fabric runtime" or "V2 Service Fabric runtime". What you're seeing refers to Service Remoting, which is a .NET RPC implementation for Service Fabric (Microsoft.ServiceFabric.Services.Remoting namespace and ServiceProxyFactory on the client).

Service remoting by default only works between services within a cluster because it uses randomly assigned ports from the ephemeral range, which assumes direct connectivity between client-server. If you have a NAT device like a load balancer in between that requires explicitly opening ports, this won't work.

Service remoting is completely optional in Service Fabric and you don't have to use it. For client communication, I strongly recommend you don't use it, as it will tightly couple your client application to your back-end services (with shared assemblies even) and versioning your APIs later will be a nightmare. I recommend using ASP.NET Core in your SF services to expose an HTTP API to your WebForms application instead.



来源:https://stackoverflow.com/questions/52860308/how-to-call-a-service-fabric-service-from-a-winform-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!