1
votes

I'm hosting an IIS application under the Azure development fabric.

When an application is deployed to the Azure compute emulator, a temporary IIS application is created that listens on a port around 5100. Incoming requests from the public endpoint are redirected to this port.

It seems, though, that the Azure development fabric does not always use the public port that has been declared in the project configuration. So, for instance, our application should expose a public port 80 -- but when I run this it's almost always port 81, but sometimes port 82, and so on.

So I can ensure that URLs created in my application are correct, I'd like to know what this external port is.

Unfortunately I can't simply look at Request.Url.Port, as this is the port number of the temporary application -- typically 5100. RoleEnvironment.CurrentRoleInstance.InstanceEndpoints, doesn't work either as that also returns the ports as seen from the server, 5100 and following.

4

4 Answers

1
votes

Figured this out by using Reflector to look into csrun.exe.

It seems that the SDK DLL Microsoft.ServiceHost.Tools.DevelopmentFabric is the key to this, in particular the methods FabricClient.GetServiceDeployments() and FabricClient.GetServiceInformation(). So:

using System; using Microsoft.ServiceHosting.Tools.DevelopmentFabric;

class Program
{
    static void Main(string[] args)
    {
        FabricClient client = FabricClient.CreateFabricClient();

        foreach (string tenantName in client.GetServiceDeployments())
        {
            var information = client.GetServiceInformation(tenantName);
            foreach (var item in information)
            {
                Console.WriteLine(string.Format("{0} {1} {2} {3}", item.ContractName, item.InterfaceName, item.UrlSpecification, item.Vip));
            }
        }

        Console.ReadLine();
    }
}

What I'm after is returned as the item.Vip.

Note, obviously, that this will only work in the development fabric ... but that's what I was looking for here, anyway.

0
votes

Did you try using

RoleEnvironment.CurrentRoleInstance.InstanceEndpoints

I am not sure atm, as I am not behind my pc, but will double check soon. Anyway, on each endpoint there is a property IPEndPoint which has Port as well. If you get the public endpoint as well (which I think you do for current role instance) you should be able to get the address from there.

Hope it helps...

0
votes

I think the reason for the "wrong" port, like 81/82, etc is that the desired port is busy.

Probably you have some other app listening to port 80, so it is never available. Also, I've seen several times when the Azure compute instance in emulator does not shutdown quicky enough, so if you start a new instance it gets next port, etc. If I kill it, wait a bit and start again - it gets desired port.

It should never be a problem in production, which is probably why it is not exposed via API. And during testing just make sure you don't have conflicts with other apps, and that you allow some time to let compute notes shutdown cleanly and release ports.

0
votes

I was unable to get the dev fabric assembly to work for me (looks like API has changed), so I resorted to parsing the output of "csrun /status" to find the IP address of a given role name. Here's some code for getting the IP, but you'd have to do a small amount of extra work to grab the ports.

public static string GetEmulatorIPAddress(string roleName)
    {
        var psi = new ProcessStartInfo();
        psi.FileName = @"C:\Program Files\Microsoft SDKs\Windows Azure\Emulator\csrun.exe";
        psi.Arguments = "/status";
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardError = true;
        psi.RedirectStandardInput = true;
        psi.UseShellExecute = false;
        psi.CreateNoWindow = true;

        StringBuilder sb = new StringBuilder();

        DataReceivedEventHandler errorHandler = (object sender, DataReceivedEventArgs e) =>
            {

            };

        string lastIPAddress = null;
        string foundIPAddress = null;

        DataReceivedEventHandler dataHandler = (object sender, DataReceivedEventArgs e) =>
        {
            string line = e.Data;
            if (line != null && foundIPAddress == null)
            {
                if (line.StartsWith("EndPoint: http://"))
                {
                    int ipStart = line.IndexOf("://") + "://".Length;
                    int ipEnd = line.IndexOf(":", ipStart);
                    lastIPAddress = line.Substring(ipStart, ipEnd - ipStart);
                }

                if (line.Trim() == roleName)
                {
                    foundIPAddress = lastIPAddress;
                }
            }
        };

        Process p = new Process();
        p.StartInfo = psi;
        p.ErrorDataReceived += errorHandler;
        p.OutputDataReceived += dataHandler;
        p.EnableRaisingEvents = true;
        p.Start();
        p.BeginOutputReadLine();
        p.BeginErrorReadLine();

        p.WaitForExit();

        return foundIPAddress;
    }