Home Closet Azure.Debugging applications on port 80

Azure.Debugging applications on port 80

by admin

When developing an application on the Windows Azure platform we had to put up with the peculiarity of running debugbuilds on different ports. But when we started actively debugging cross-domain AJAX, thisproblem became particularly acute. Because the scripts required to use absolute URL in the js-script text. We had to write the port number in the URL: http://127.0.0.1:81/bla-bla-bla. Whenever the port was changed on restarting the application, we had to restart devfabric to make the build start on port 81. Restarting took precious time, increasing annoyance.
At some pointwe exhausted our patience and decided to create a tool to debug the application on a single port. It’s an ASPX application that receives requests and forwards them to a running Azure instance. This allows us to not have to worry about what port Azure is running on right now.

Presetting

During development, the idea was to write something like Reverse Proxy to make an Azure instance accessible from azureproxy.com For thiswe use IIS 7.5, which is still spinning on the machine.
In the IIS service manager we addthe AzureProxyapplication pool
Azure.Debugging applications on port 80
Specify version4 of the .Net Framework.
And we add the website
Azure.Debugging applications on port 80
Here you need to specify site name"AzureProxy", application pool "AzureProxy", physical path – any (here D:AzureProxy). You should also specify the binding: IP address – 127.0.0.1, Port – 80, Host name- azureproxy.com
Also we need Url Rewrite module for IIS. If you don’t have it installed yet – you need to visit www.iis.net/download/URLRewrite and install it.
The next step is to add azureproxy.com to the hosts file.
In the editor we open file C:{WindowsSystem32driversetchosts and add there the following line
127.0.0.1 azureproxy.com
Preliminary stage is over.

Programming

It’s time to open Visual Studio 2010.
Create a newproject
Azure.Debugging applications on port 80
The project typeis ASP .NET Empty Web Application, the rest is optional.
Edit the Web.Config file

<? xml version ="1.0" ? >
< configuration >
< system.web >
< compilation debug ="true" targetFramework ="4.0" />
< pages enableViewStateMac ="false" />
</ system.web >
< system.webServer >
< modules runAllManagedModulesForAllRequests ="true" >
< add name ="AzureProxyModule" type ="AzureProxy.AzureProxyModule, AzureProxy" />
</ modules >
< rewrite >
< rules >
< rule name ="All" stopProcessing ="true" >
< match url ="^(.*)$" />
< action type ="Rewrite" url ="/Default.aspx?url={HtmlEncode:{R:0}}" />
</ rule >
</ rules >
</ rewrite >
</ system.webServer >
</ configuration >
* This source code was highlighted with Source Code Highlighter

Adding a newweb form
named Default.aspx
And we leave only
<%@ Page Language="C#"AutoEventWireup="true"CodeBehind="Default.aspx.cs"Inherits="AzureProxy.Default"%>

Then we add a newclass
Azure.Debugging applications on port 80
with the name AzureProxyModule.cs as follows

using System;
using System.Net;
using System.IO;
using System.Configuration;
using System.Collections. Generic ;
using System.Linq;
using System.Web;
using System.Threading;
namespace AzureProxy
{
public class AzureProxyModule : IHttpModule
{
const string Domain = "127.0.0.1" ;
const int MaxPort =110;
public static string Port = "" ;
public Queue< int > ports = new Queue< int > ();
public List <Thread> threads = new List <Thread> ();
public bool ThreadsLive = false ;
public AzureProxyModule()
{
}
public String ModuleName
{
get { return AzureProxyModule" ; }
}
public void Init(HttpApplication httpApp)
{
httpApp.BeginRequest +=
new EventHandler( this OnBeginRequest);
httpApp.EndRequest +=
new EventHandler( this OnEndRequest);
}
public void OnBeginRequest( object o, EventArgs ea)
{
}
public void OnEndRequest( object o, EventArgs ea)
{
HttpApplication httpApp = (HttpApplication)o;
if (Port.Length == 0)
{
SearchPort();
}
DoRequest();
}
public void DoRequest()
{
byte [] buffer = new byte [4096];
HttpContext ctx;
ctx = HttpContext Current;
if (ctx.Request.QueryString[ "url" ] == null ) return ;
HttpWebRequest myHttp = (HttpWebRequest)HttpWebRequest.Create( "http://" + Domain+ ":" + Port + ctx.Request.RawUrl.ToString());
myHttp.AllowAutoRedirect = false ;
myHttp.KeepAlive = true ;
myHttp.CookieContainer = new CookieContainer();
myHttp.UserAgent = ctx.Request.UserAgent;
foreach ( string CookieName in ctx.Request.Cookies.AllKeys)
{
if (ctx.Request.Cookies[CookieName].Domain != null )
{
myHttp.CookieContainer.Add( new Cookie(ctx.Request.Cookies[CookieName].Name, ctx.Request.Cookies[CookieName].Value, ctx.Request.Cookies[CookieName].Path, ctx.Request.Cookies[CookieName].Domain));
}
else
{
myHttp.CookieContainer.Add( new Cookie(ctx.Request.Cookies[CookieName].Name, ctx.Request.Cookies[CookieName].Value, ctx.Request.Cookies[CookieName].Path, Domain));
}
}
myHttp.ContentType = ctx.Request.ContentType;
if (ctx.Request.HttpMethod == "POST" )
{
myHttp.Method = "POST" ;
myHttp.AllowWriteStreamBuffering = true ;
myHttp.ContentLength = ctx.Request.InputStream.Length;
Stream requestStream= myHttp.GetRequestStream();
int length = 0;
while ((length = ctx.Request.InputStream.Read(buffer, 0, buffer.Length))>0)
{
requestStream.Write(buffer, 0, length);
}
}
try
{
WebResponse response = myHttp.GetResponse();
if (response.Headers[ "Location" ] != null )
{
ctx.Response.Redirect(response.Headers[ "Location" ]);
}
using ( Stream stream = response.GetResponseStream())
{
using (MemoryStream memoryStream = new MemoryStream())
{
int count = 0;
do
{
count = stream.Read(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, count);
} while (count != 0);
ctx.Response.ContentType = response.ContentType;
foreach ( string HeaderKey in response.Headers.Keys)
{
ctx.Response.AddHeader(HeaderKey, response.Headers[HeaderKey]);
}
ctx.Response.BinaryWrite(memoryStream.ToArray());
}
}
}
catch (WebException code)
{
switch (code.Message)
{
case "Unable to connect to the remote server" :
SearchPort();
DoRequest();
break ;
case "The remote server returned an error:(404) Not Found." :
ctx.Response.Status = "404 File Not Found" ;
break ;
}
return ;
}
}
public void SearchPort()
{
Port = "" ;
for ( int port = 81;port <MaxPort;port++)
{
ports.Enqueue(port);
threads.Add( new Thread( new ThreadStart(PortTest)));
}
threads.ForEach( new Action<Thread> (ThreadStart));
while (TreadsIsLive() (Port.Length == 0))
{
//waiting for a response from the trades
}
//completing all trades
threads.ForEach( new Action<Thread> (ThreadAbort));
}
public void Dispose() {}
public bool TreadsIsLive()
{
ThreadsLive = false ;
threads.ForEach( new Action<Thread> (ThreadTest));
return true ;
}
public void ThreadTest(Thread t)
{
ThreadsLive =ThreadsLive || t.IsAlive;
}
protected void ThreadStart(Thread t)
{
try
{
ThreadsLive = true ;
if (!t.IsAlive) t.Start();
}
catch {}
}
protected void ThreadAbort(Thread t)
{
t.Abort();
}
protected void PortTest()
{
int port;
try
{
port = ports.Dequeue();
HttpWebRequest myHttpWebRequest =
(HttpWebRequest)HttpWebRequest.Create( "http://" + Domain + ":" + port.ToString());
try
{
HttpWebResponse myHttpWebResponse =
(HttpWebResponse)myHttpWebRequest.GetResponse();
Port = port.ToString();
return ;
}
catch { }
}
catch { }
}
}
}
* This source code was highlighted with Source Code Highlighter

Build the application and publish it in IIS
Azure.Debugging applications on port 80
The Azure instance is now available at azureproxy.com.

Conclusion

The technique used allows proxying requests to running Azure instances from a single address. The search for an available port is done in child trades in parallel, which allows you to quickly find the port. Both GET and POST requests are proxied, the incoming stream is completely passed to the Azure instance, allowing files to be downloaded.
P.S. This article is an abridged step-by-step guide to creating AzureProxy. If needed, we can go into more detail about the problematic areas that arose while writing the application.

You may also like