INNVTV
INNVTV

Reputation: 3377

Service Fabric Service Remoting

I've been migrating from Cloud Services to Service Fabric the last few weeks and have been running into a few stumbling blocks using Remoting between 2 services.

I've been using the official documentation and sample code on Service Remoting and in particular I'm trying to get the sample outlined here to work:

https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-remoting

I have 2 services. One is named "RemoteService" and the other is named "CallerService". Both are derived from a default Stateless Service project.

In both the "RemoteService" and "CallerService" projects I have added the following Interface to describe the service contract between them:

public interface IMyService : IService
{
    Task<string> HelloNameAsync(string name);
}

In the "RemoteService" I've created asociated method within the RemoteService class

public Task<string> HelloNameAsync(string name)
{
    return Task.FromResult("Hello " + name + "!");
}

I also override CreateServiceInstanceListeners with the following

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    return new[] { new ServiceInstanceListener(context => this.CreateServiceRemotingListener(context)) };
}

In my "CallerService" when I attempt to connect make the call to the "RemoteService" with the following:

IMyService helloNameClient = ServiceProxy.Create<IMyService>(new Uri("fabric:/Application/RemoteService"));
string message = await helloNameClient.HelloNameAsync("Luke");

I get this exception

InnerException = {"Interface id '1994370306' is not implemented by object 'RemoteService.RemoteService'"}

I've gone over this sample with a fine tooth comb and am sure that I have everything in place as it should be. I've read about setting up endpoints and registering your services into a service directory, but from what I understand those are for external services and the Remoting documentation does not mention requiring this.

UPDATE:

Here is how the RemoteService class is declared:

internal sealed class RemoteService : StatelessService, IMyService

UPDATE 2

Here is what the Settings.xml looks like for both services. These are the default settings that come out of the box with the project. I did not add or remove anything. I also want to note that I am running all of this on my local service fabric.

<?xml version="1.0" encoding="utf-8" ?>
<Settings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2011/01/fabric">
  <!-- Add your custom configuration sections and parameters here -->
  <!--
  <Section Name="MyConfigSection">
    <Parameter Name="MyParameter" Value="Value1" />
  </Section>
  -->
</Settings>

Upvotes: 5

Views: 4943

Answers (1)

yoape
yoape

Reputation: 3335

The assembly the service interface is declared in needs to be shared with the client, you cannot recreate an identical interface on the client side. When Service Fabric sets up the communication it builds up a map of the interface and it's methods from the actual assembly used by the service.

Based on your description, it looks like you are declaring an identical interface in both service and client project? If so, then this is the fix.

From SO: Calling services from other application in the cluster: The only tricky part is how do you get the interface from the external service to your calling service? You could simply reference the built .exe for the service you wish to call or you could package the assembly containing the interface as a NuGet package and put on a private feed.

If you don't do this and you instead just share the code between your Visual Studio solutions the Service Fabric will think these are two different interfaces, even if they share the exact same signature. If you do it for a Service you get an NotImplementedException saying "Interface id '{xxxxxxxx}' is not implemented by object '{service}'" and if you do it for an Actor you get an KeyNotfoundException saying "No MethodDispatcher is found for interface id '-{xxxxxxxxxx}'".

So, to fix your problem, make sure you reference the same assembly that is in the application you want to call in the external application that is calling.

Upvotes: 5

Related Questions