Azure compute emulator port mapping issue
Development | Igor Drazic

Azure compute emulator port mapping issue

Monday, May 5, 2014 • 2 min read
How I've dealt with Azure compute port mapping issue when running a WebRole application in Azure compute emulator with two or more instances.

Intro

The problem manifests itself when running a WebRole application inside Azure compute emulator with two or more instances. Opening up the application inside the web browser shows some of the links having different port number (those with full URLs):

Compute ports

Narutally, clicking on these URLs will not work since our application is bound to the port we set in the “Endpoint” setting.

URL Resolving

Since the application I’m working on is powered by MonoX, many of the links on the site are resolved using "MonoSoftware.Web.UrlFormatter.ResolveServerUrl" which resolves the URL using "HttpContext.Current.Request.Url" at its core.

Many of the solutions on the web suggest a modified “resolver” method for this problem, but unfortunately for me, changing the framework is out of the question.

Cause of the issue

When you run an application through Visual Studio you will see a message in the output window similar to this: "Windows Azure Tools: Warning: Remapping private port 80 to 81 in role 'Portal' to avoid conflict during emulation." This is a normal behavior and will not happen inside the real Azure environment.

Also worth mentioning is that port will be different if you have full IIS running an application bound to port 80; again this is normal and is not the cause of the problem.

My understanding of the problem is that ASP.NET builds the request URL using the server variable SERVER_PORT taken from the receiving port of the role instance and not from the load balancer and since my two application instances are running at different ports, resolved URLs will not work half the time.

127.0.0.1:80 VIP 
127.255.0.0:81 DIP Instance 1
127.255.0.1:81 DIP Instance 2

Connections

Compute

IIS

Not so clean solution

The earliest time to change SERVER_PORT variable is at "Application_BeginRequest", BUT Request.Url is already initialized here and can’t be changed - well, not without a hack.

Going through the decompiled source of HttpRequest shows that _url is the private varible for lazy loading the URL. My dirty solution is to change SERVER_PORT to that of HTTP_HOST and force reload of Request.Url using reflection. Going through the decompiled source of HttpRequest shows that _url is the private varible for lazy loading the URL. My dirty solution is to change SERVER_PORT to that of HTTP_HOST and force reload of Request.Url using reflection.

Code

/// <summary>
/// Fixes port issue in Request.Url when using azure compute with multi-instance of Role/application.
/// </summary>
/// <param name="application">Http application.</param>
private void AzureComputeLocalPortFix(HttpApplication application)
{
    Uri host = new Uri(application.Request.Url.Scheme + Uri.SchemeDelimiter + 
        application.Request.ServerVariables["HTTP_HOST"]);
    int oldPort = Convert.ToInt32(application.Request.ServerVariables["SERVER_PORT"]);
    application.Request.ServerVariables["SERVER_PORT"] = host.Port.ToString();
    // Force reload Request.Url
    application.Request.GetType().GetField("_url", BindingFlags.Instance | BindingFlags.NonPublic)
        .SetValue(application.Request, null);

    if (application.Request.Url.Port == oldPort)
        throw new ApplicationException("Port hack failed!");
}

protected void Application_BeginRequest(Object sender, EventArgs e)
{
    #if DEBUG
    AzureComputeLocalPortFix((HttpApplication)sender);
    #endif
}

Conclusion

The provided fix should never go into production, it’s only for local testing and development. I hoped that there would be a better solution for this but I couldn’t find any - please comment if you know of a better solution.