6

I have two web roles and one of them runs the service layer consisting of 3 WCF services connected with net.tcp, each deployed as a website on port 808, 810, and 811.

Now I want the service layer to only be open to my other web role.

So I tried to make one of the services endpoint internal and to give access for my front web role.

Like this:

<ServiceDefinition name="MagnusAzureCloudService" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6"> <WebRole name="Core.Services" vmsize="Small"> <Runtime executionContext="elevated" /> <Startup> <Task commandLine="Startup/startup.cmd" executionContext="elevated" taskType="background" /> </Startup> <Sites> <Site name="Core" physicalDirectory="C:\CoreServices"> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" /> </Bindings> </Site> <Site name="Store" physicalDirectory="C:\StoreServices"> <Bindings> <Binding name="Endpoint3" endpointName="Endpoint3" /> </Bindings> </Site> <Site name="Users" physicalDirectory="C:\UserServices"> <Bindings> <Binding name="Endpoint4" endpointName="Endpoint4" /> </Bindings> </Site> </Sites> <ConfigurationSettings> <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" /> </ConfigurationSettings> <Endpoints> <InputEndpoint name="Endpoint1" protocol="http" port="8282" /> <InputEndpoint name="Endpoint3" protocol="http" port="81" /> <InputEndpoint name="Endpoint4" protocol="http" port="8181" /> <InputEndpoint name="Endpoint2" protocol="tcp" port="808" localPort="808" /> <InputEndpoint name="Endpoint5" protocol="tcp" port="810" localPort="810" /> <InternalEndpoint name="Endpoint6" protocol="tcp" port="811" /> </Endpoints> <Certificates> </Certificates> <Imports> <Import moduleName="RemoteAccess" /> <Import moduleName="RemoteForwarder" /> </Imports> </WebRole> <WebRole name="UIWeb" vmsize="Small"> <Runtime executionContext="elevated" /> <Startup> <Task commandLine="Startup/startup.cmd" executionContext="elevated" taskType="background" /> </Startup> <Sites> <Site name="Web"> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" /> </Bindings> </Site> </Sites> <ConfigurationSettings> <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" /> </ConfigurationSettings> <Endpoints> <InputEndpoint name="Endpoint1" protocol="http" port="80" /> </Endpoints> <Imports> <Import moduleName="RemoteAccess" /> </Imports> </WebRole> <NetworkTrafficRules> <OnlyAllowTrafficTo> <Destinations> <RoleEndpoint endpointName="Endpoint6" roleName="Core.Services" /> </Destinations> <WhenSource matches="AnyRule"> <FromRole roleName="UIWeb"/> </WhenSource> </OnlyAllowTrafficTo> </NetworkTrafficRules> </ServiceDefinition>

But when the UserService is attempted it seems to time out.

Server Error in '/' Application.

Connecting to via net.tcp://myservicename.cloudapp.net:811/UserTypeService.svc timed out after 00:00:00. Connection attempts were made to 0 of 1 available addresses (). Check the RemoteAddress of your channel and verify that the DNS records for this endpoint correspond to valid IP Addresses. The time allotted to this operation may have been a portion of a longer timeout.

I have also tried to set <AllowAllTraffic/> instead of <WhenSource ...> but that has no effect.

Second attempt: After some feedback I have tried some variations to set a FixedPort and PortRange to 811 and the role listening to port="*".

<InternalEndpoint name="Endpoint6" protocol="tcp" port="*" >
      <FixedPortRange min="811" max="811"></FixedPortRange>
  </InternalEndpoint>

I have kept the NetworkTrafficRules as in previous attempts.

I also added the following code to make sure there is a listener for a dynamic port. In my WebRole.cs file:

    public class WebRole : RoleEntryPoint
{
    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public override bool OnStart()
    {
        Trace.TraceInformation("OnStart method called. Updating information on IIS.");

        try
        {
            // Initialize method-wide variables
            var epName = "Endpoint6";
            var roleInstance = RoleEnvironment.CurrentRoleInstance;

            // Identify direct communication port
            var myPublicEp = roleInstance.InstanceEndpoints[epName].PublicIPEndpoint;
            Trace.TraceInformation("IP:{0}, Port:{1}", myPublicEp.Address, myPublicEp.Port);

            // Identify public endpoint
            var myInternalEp = roleInstance.InstanceEndpoints[epName].IPEndpoint;

            // Create socket listener
            var listener = new Socket(
              myInternalEp.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            // Bind socket listener to internal endpoint and listen
            listener.Bind(myInternalEp);
            listener.Listen(10);
            Trace.TraceInformation("Listening on IP:{0},Port: {1}",
              myInternalEp.Address, myInternalEp.Port);

            while (true)
            {
                // Block the thread and wait for a client request
                Socket handler = listener.Accept();
                Trace.TraceInformation("Client request received.");

                // Define body of socket handler
                var handlerThread = new Thread(
                  new ParameterizedThreadStart(h =>
                  {
                      var socket = h as Socket;
                      Trace.TraceInformation("Local:{0} Remote{1}",
              socket.LocalEndPoint, socket.RemoteEndPoint);

                      // Shut down and close socket
                      socket.Shutdown(SocketShutdown.Both);
                      socket.Close();
                  }
                ));

                // Start socket handler on new thread
                handlerThread.Start(handler);
            }
        }
        catch (Exception e)
        {
            Trace.TraceError("Caught exception in run. Details: {0}", e);
        }
        // Set the maximum number of concurrent connections 
        ServicePointManager.DefaultConnectionLimit = 12;

        return base.OnStart();
    }
}

Another note is that the calling service uses port 811 to find the right service since the service runs three different WCF project sites. And the service I'm calling also uses a specified port number which I think can be a problem if it all of a sudden should be dynamic. The calling service looks like this:

<endpoint address="net.tcp://myservicename.cloudapp.net:811/UserTypeService.svc"
      behaviorConfiguration="ClientContextEndpointBehavior" binding="netTcpBinding"
      bindingConfiguration="NetTcpBinding_FrameworkService" contract="Users.Services.IPersonTypeService"
      name="Tcp">
    <identity>
      <dns value="The Certificate Name" />
    </identity>
  </endpoint>

And on the receiving(Internal) WebRole sites I have the following types of configurations.

<service name="Core.Services.Logging.LoggingService" behaviorConfiguration="coreServiceBehavior">
<endpoint address="net.tcp://localhost:808/LoggingService.svc" 
              behaviorConfiguration="ContextEndpointBehavior" 
              binding="netTcpBinding"
              bindingConfiguration="NetTcpBinding1" 
              contract="Core.Logging.ILoggingService">
      <identity>
        <dns value="The Certificate Name" />
      </identity>
    </endpoint>

And the other WCF site on port 811:

<service name="Users.Services.PersonTypeService">
<endpoint address="net.tcp://localhost:811/UserTypeService.svc" binding="netTcpBinding" bindingConfiguration="NetTcpServiceBinding1" behaviorConfiguration="ServerContextEndpointBehavior" contract="Users.Services.IUserTypeService">
  <identity>
    <dns value="The Certificate Name" />
  </identity>
</endpoint>

<endpoint address="mex" binding="mexTcpBinding" kind="mexEndpoint">
  <identity>
    <dns value="localhost" />
  </identity>
</endpoint>

Magnus Karlsson
  • 3,549
  • 3
  • 31
  • 57

1 Answers1

0

You could use the internal endpoint IP-addresses and instead of the external address. Here is an example:

foreach (RoleInstance roleInst in RoleEnvironment.CurrentRoleInstance.Role.Instances)
{
    // Skip local role instance
    if (RoleEnvironment.CurrentRoleInstance.Id == roleInst.Id) continue;

    if (roleInst.Role.Name == "My Cool Role")
    {
        foreach (RoleInstanceEndpoint roleInstEndpoint in roleInst.InstanceEndpoints.Values)
        {
            // Get endpoint address using the internal endpoint's IP address
            if (roleInstEndpoint.Protocol == "tcp")
                SendRequest(roleInstEndpoint.IPEndpoint.Address.ToString(), command);

        }
    }
}
  • I'm not sure I'm following? What is it you suggest I do and why? – Magnus Karlsson Sep 13 '15 at 19:00
  • @MagnusKarlsson You are attempting to connect to an _internal_ endpoint using the *external* address myservicename.cloudapp.net to your service, _Input endpoints_ are used to communicate with role instances from *outside* of Azure. _Internal endpoints_ are used for *internal* role communication and then you need IP addresses for the internal IP-range which is what my coded sample does, See this for more info https://msdn.microsoft.com/en-us/library/azure/hh180158.aspx –  Sep 13 '15 at 19:41
  • I think Azure internal DNS will handle my cloud service address and resolve it to the right IP-address. Since the two roles are within the same cloud service they should be able to talk to each other without a work around? I just added a fixed port as of this example and gonna try that out now. Or am I missing something? https://msdn.microsoft.com/en-us/library/azure/hh180158.aspx – Magnus Karlsson Sep 13 '15 at 20:11
  • I have updated the question after implementing the binding part. I think it was like that you suggested. Used the code from the documentation page instead. I also have some considerations about how my services are set up towards specific ports. – Magnus Karlsson Sep 14 '15 at 07:29