3
votes

Basic Idea - I have a stateless service that implements an Owin communication Listener over http to service WebApi based public clients. I want to add a second listener that will receive requests within the cluster over Rpc using the built in ServiceRemotingListener(). The reason is that I don't want this listener to be public as it implements a non-public management interface for the stateless service. Here is the setup...:

        protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return new[]
        {
            new ServiceInstanceListener(initParams => new OwinCommunicationListener("MyWebService", new Startup(_options, this), initParams),"MyServiceHttp"),
            new ServiceInstanceListener(initParams => new ServiceRemotingListener<Interfaces.IConfig>(initParams, this),"MyServiceRpc")           
        };
    }

When I add the second listener, I get an exception starting the app...

                 this.serverHandle = WebApp.Start(this.listeningAddress, appBuilder => this.startup.Configuration(appBuilder));

Exception thrown: 'System.Net.Sockets.SocketException' in System.dll Exception thrown: 'System.ServiceModel.CommunicationException' in System.ServiceModel.dll Exception thrown: 'System.ServiceModel.CommunicationException' in System.ServiceModel.dll Exception thrown: 'System.ServiceModel.CommunicationException' in System.ServiceModel.Internals.dll --multiple repeats--- Exception thrown: 'System.ServiceModel.CommunicationException' in System.Fabric.dll

(not sure how to get the exception details. My "try {} " surrounding did not trap an exception.)

Once in this state, I get subsequent exceptions as the service attempts to auto-restart - the errors are about port sharing.

Anything I can do to make WebApi communication listeners work alongside ServiceRemotingListener? I am assuming at this point that under the hood, ServiceRemotingListener is using http as well and they don't play nicely together.

1
It looks like I was using a port blocked by the firewall. I get the same exception but now I also get a CommunicationException with the same error but it identifies the port as 0.0.0.0:8080. " A TCP error (10013: An attempt was made to access a socket in a way forbidden by its access permissions) occurred while listening on IP Endpoint=0.0.0.0:8080."MarkD
ServiceRemotingListener doesn't use HTTP. Can you get ServiceRemotingLIstener to work on its own, without the OwinCommunicationListener?Vaclav Turecek
I'll give it a go and report back tomorrow. Thanks!MarkD
When I set up the ServiceRemotingListener on its own, the node reports {"Endpoints":{"MyRpc":"net.tcp:\/\/localhost:8083\/2c44446c-4c4e-479a-ac48-13c5b664b8c6\/0b91d2a3-80c3-4c30-b9b4-490672a8c077-130979017853872413"}}. Looking into why this decided to use tcp....MarkD
..and when I add the IOwinCommunicationListener back using a listening address "http://+:8083/bc35bdfc-c488-473e-aaa2-5bdc6b763b9f/130979290464827805/99d163c8-e462-4a8f-8bfa-821d9308790e", I get the "An attempt was made to access a socket in a way forbidden by its access permissions" error again.MarkD

1 Answers

8
votes

ok, the solution turned out to be straight forward but not obvious. The docs seem to encourage port sharing approach even though the TCP/RPC and HTTP don't play together.

Basically, I added a second endpoint to the service manifest even though the docs say that each service can only listen on one port.

I left the default / first endpoint for the ServiceRemotingListener to register and added a second that listened specifically to port 8083.

<Endpoint Name="ServiceEndpoint" Protocol="http" Type ="Input"/>
<Endpoint Name="ServiceEndpoint2" Protocol="http" Port="8083" Type ="Input"/>

Then in the IOwinCommunicationsListener, I specified the second endpoint which picked up the alternative port number (I assumed the ServiceInstanceListener would use the default/first end point).

var codePackageActivationContext = this.serviceInitializationParameters.CodePackageActivationContext;
var port = codePackageActivationContext.GetEndpoint("ServiceEndpoint2").Port;

The CreateServiceInstanceListeners were left without any extra config. As above, I wonder if I could use the ServiceRemoteListenerSettings to force the ServiceRemotinglistener to use the alternative port instead of the IOwinCommunicationsListener above)

        return new[]
        {
            new ServiceInstanceListener(initParams => new ServiceRemotingListener<Interfaces.IConfig>(initParams, this),"MyRpc"),
            new ServiceInstanceListener(initParams => new OwinCommunicationListener("ShopifyWebService", new Startup(_options, this), initParams),"MyOwin")
               };

Hope this helps save someone else a lot of time.