Updates from October, 2011 Toggle Comment Threads | Keyboard Shortcuts

  • Richard 8:37 am on October 21, 2011 Permalink |
    Tags: ASP.NET   

    Machine Key Generator 

    Very useful:

    http://www.orcsweb.com/articles/aspnetmachinekey.aspx

    Advertisements
     
  • Richard 7:46 am on October 18, 2011 Permalink |  

    Web roles, endpoints and IIS bindings 

    You add endpoints to a role in Visual Studio using this editor:

    The Service Definition file will be automatically set to this:

    <?xml version="1.0" encoding="utf-8"?>
    <ServiceDefinition name="WindowsAzureProject1" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
      <WebRole name="WCFServiceWebRole1" vmsize="Small">
        <Sites>
          <Site name="Web">
            <Bindings>
              <Binding name="Endpoint1" endpointName="Endpoint1" />
              <Binding name="Endpoint2" endpointName="Endpoint2" />          
            </Bindings>
          </Site>
        </Sites>
        <Endpoints>
          <InputEndpoint name="Endpoint1" protocol="http" port="80" />
          <InputEndpoint name="Endpoint2" protocol="http" port="9000" />
        </Endpoints>
      </WebRole>
    </ServiceDefinition>

    Notice how both endpoints are bound to the website. This results in the website in IIS having bindings set up for both port numbers. However, you can remove the binding, the port will now be free for you to use for whatever you want. The interesting thing is that once un-bound, you can set the protocol to TCP.

    <?xml version="1.0" encoding="utf-8"?>
    <ServiceDefinition name="WindowsAzureProject1" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
      <WebRole name="WCFServiceWebRole1" vmsize="Small">
        <Sites>
          <Site name="Web">
            <Bindings>
              <Binding name="Endpoint1" endpointName="Endpoint1" />
            </Bindings>
          </Site>
        </Sites>
        <Endpoints>
          <InputEndpoint name="Endpoint1" protocol="http" port="80" />
          <InputEndpoint name="Endpoint2" protocol="tcp" port="9000" />
        </Endpoints>
      </WebRole>
    </ServiceDefinition>

    This allows you to provision a second site (or application) on an alternative port number on the same box. You would just need to unpack your application and copy it somewhere using a startup task.

    This is the command to create a new site in IIS:

    appcmd add site /name: sitename /id:2 /physicalPath: %systemdrive%\inetpub\wwwroot /bindings:http/*:9000:MYAPP.cloudapp.net
     
  • Richard 12:21 pm on October 14, 2011 Permalink |  

    BACPAC Import/Export now available for SQL Azure 

     

     

    It is now possible to backup and restore your SQL Azure database using the BACPAC format, from inside the Azure Management Portal. The portal allows you to select a database and export it to a blob. Restoring is a mater of choosing which blob should restore to which database. Backups do not have transactional consistency, so it may be best to back up a copy of your live database.

    You can copy a database with this command:

    CREATE DATABASE destination_database_name
        AS COPY OF [source_server_name.]source_database_name

     

     
  • Richard 2:35 pm on October 13, 2011 Permalink |  

    Windows Azure Data Sync UI 

    I quite like the user interface of the Data Sync feature in Azure (currently CTP).

    Very visual, and easy to see what’s going on.

     
  • Richard 1:29 pm on October 13, 2011 Permalink |  

    Using IIS Application Request Routing to load balance on Azure 

    As previously discussed, cloud applications should be written to be stateless, and use the standard Azure round-robin load balancer. However, some applications need a sticky session, in which case, one option you have is to roll your own software load balancer. However the Application Request Routing (a software load balancer) module of IIS presents you with another option. The advantages of using ARR are

    1. It’s standard, well tested code doing the balancing.
    2. There are a number of load balancing strategies available.
    3. Client affinity (sticky sessions) is an option.

    The topology of your deployment will look something like this:

    The ARR Role will have ARR and the Web Farm Framework installed, and expose a public facing endpoint. It will be responsible for routing traffic to the Web Role instances. The Web Role will have an internal endpoint, but is otherwise unchanged.

    Installing ARR

    Download ARR and The Web Farm Framework IIS modules:

    http://www.iis.net/download/ApplicationRequestRouting
    http://www.iis.net/download/WebFarmFramework

    Create a Web Role project in your solution, copy the MSI files you downloaded into the solution, and set them to ‘copy if newer’. This will ensure they are packaged up with your application.

    Add an elevated startup task (see how here) which will install these components. Your Startup.cmd file should contain these lines:

    webfarm_amd64_en-US.msi /quiet
    requestRouter_amd64_en-US.msi /quiet

    Configuring ARR

    In your service definition file, set your role to run elevated (see how here).

    In your WebRole class (which inherits from RoleEntryPoint) add an override to the ‘Run’ method. The first thing to do is to update the binding configuration of the virtual directory to include the correct host name, and change the physical path of the default site to wwwroot, instead of the web pages packaged with your role. This can be done using the Microsoft.Web.Administration namespace:

    using (ServerManager serverManager = new ServerManager())
    {
    	bool voteCommit = false;
    	Configuration config = serverManager.GetApplicationHostConfiguration();
    	ConfigurationSection sitesSection = config.GetSection("system.applicationHost/sites");
    	ConfigurationElementCollection sitesCollection = sitesSection.GetCollection();
    	ConfigurationElement siteElement = sitesCollection[0];
    	ConfigurationElementCollection bindingsCollection = siteElement.GetCollection("bindings");
    	ConfigurationElement bindingElement = FindElement(bindingsCollection, "binding", "protocol", @"http");
    	if (bindingElement["bindingInformation"] as string != @"*:80:yourservice.cloudapp.net")
    	{
    		bindingElement["bindingInformation"] = @"*:80:yourservice.cloudapp.net";
    	}
    	ConfigurationElementCollection siteCollection = siteElement.GetCollection();
    	ConfigurationElement applicationElement = FindElement(siteCollection, "application", "path", @"/");
    	ConfigurationElementCollection applicationCollection = applicationElement.GetCollection();
    	ConfigurationElement virtualDirectoryElement = FindElement(applicationCollection, "virtualDirectory", "path", @"/");
    	if (virtualDirectoryElement["physicalPath"] as string != @"%SystemDrive%\inetpub\wwwroot")
    	{
    		virtualDirectoryElement["physicalPath"] = @"%SystemDrive%\inetpub\wwwroot";
    	}
    	serverManager.CommitChanges();
    }

    You then need to create a web farm, and add the redirection rule to point incoming requests to your farm. The web farm in this case is configured to use client affinity (sticky sessions).

    using (ServerManager serverManager = new ServerManager())
    {
    	// create the server farm
    	Configuration config = serverManager.GetApplicationHostConfiguration();
    	ConfigurationSection webFarmsSection = config.GetSection("webFarms");
    	ConfigurationElementCollection webFarmsCollection = webFarmsSection.GetCollection();
    	var el = FindElement(webFarmsCollection, "webFarm", "name", farmName);
    	if (null != el) return;
    	ConfigurationElement webFarmElement = webFarmsCollection.CreateElement("webFarm");
    	webFarmElement["name"] = farmName;
    	webFarmsCollection.Add(webFarmElement);
    	ConfigurationElement applicationRequestRoutingElement = webFarmElement.GetChildElement("applicationRequestRouting");
    	ConfigurationElement affinityElement = applicationRequestRoutingElement.GetChildElement("affinity");
    	affinityElement["useCookie"] = true;
    
    	// create the rewrite rule
    	Configuration config = serverManager.GetApplicationHostConfiguration();
    	ConfigurationSection globalRulesSection = config.GetSection("system.webServer/rewrite/globalRules");
    	ConfigurationElementCollection globalRulesCollection = globalRulesSection.GetCollection();
    	ConfigurationElement ruleElement = globalRulesCollection.CreateElement("rule");
    	ruleElement["name"] = serverFarm;
    	ruleElement["patternSyntax"] = @"Wildcard";
    	ruleElement["stopProcessing"] = true;
    	ConfigurationElement matchElement = ruleElement.GetChildElement("match");
    	matchElement["url"] = "*";
    	matchElement["ignoreCase"] = true;
    	ConfigurationElement actionElement = ruleElement.GetChildElement("action");
    	actionElement["type"] = @"Rewrite";
    	actionElement["url"] = string.Concat(@"http://", serverFarm, @"/{R:0}");
    	globalRulesCollection.Add(ruleElement);
    	serverManager.CommitChanges();
    }

    These tasks need only to be run once.

    You should then set up a simple loop, which will inspect the instances running, and modify the farm according to changes in the topology. Adding a server is straight forward, and can be done with some code like this:

    public static void AddServer(string farmName, string ipAddress, int portNumber)
    {
    	using (ServerManager serverManager = new ServerManager())
    	{
    		Configuration config = serverManager.GetApplicationHostConfiguration();
    		ConfigurationSection webFarmsSection = config.GetSection("webFarms");
    		ConfigurationElementCollection webFarmsCollection = webFarmsSection.GetCollection();
    		ConfigurationElement webFarmElement = FindElement(webFarmsCollection, "webFarm", "name", farmName);
    		ConfigurationElementCollection webFarmCollection = webFarmElement.GetCollection();
    		var server = FindElement(webFarmCollection, "server", "address", ipAddress);
    		if (null != server)
    		{
    			// server already exists
    			return;
    		}
    		ConfigurationElement serverElement = webFarmCollection.CreateElement("server");
    		serverElement["address"] = ipAddress;
    		ConfigurationElement applicationRequestRoutingElement = serverElement.GetChildElement("applicationRequestRouting");
    		applicationRequestRoutingElement["httpPort"] = portNumber;
    		webFarmCollection.Add(serverElement);
    		serverManager.CommitChanges();
    	}
    }

    You would need additional code to for servers being, removed, and IP address changes.

    Simple!

     
  • Richard 10:21 am on October 13, 2011 Permalink |  

    Setting the date on an Azure instance is futile 

    You can set the date on an Azure instance, however, it quickly sets it back again. See this console output as an example:

    E:\>date 12/10/2004
    
    E:\>date /t
    Fri 12/10/2004
    
    E:\>date /t
    Thu 10/13/2011

    Even stopping the Windows Time service has no effect.

    It looks like Azure always wants to keep up-to-date.

     
  • Richard 12:44 pm on October 11, 2011 Permalink |  

    Web role = Worker role + IIS 

    It surprised me to find that the ‘Run’ method on your implementation of  ‘RoleEntryPoint’ gets called on Azure Web Roles, in just the same way as Worker Roles.

    public class WebRole : RoleEntryPoint
    {
      public override void Run()
      {
          // Do something
      }
    }

    This means that if you have currently have separate web roles and worker roles, you could combine these into a single role. The advantage with this approach is that load will then be spread evenly across all of your instances, and you make better use of the compute time you’ve purchased.

    What is also interesting, is that run is called on a copy of your assembly in this folder:

    e:\approot\bin

    Whereas IIS is pointing to another copy of your application in this folder:

    e:\siteroot\0
     
  • Richard 3:26 pm on October 4, 2011 Permalink |  

    Get the name of the default web site 

    On Azure, the name of the default website changes according to the name and number of the instance. If you need to include the name of the site in any appcmd scripts, you can get it in a bat file like this:

    %systemroot%\system32\inetsrv\appcmd list sites /text:site.name > temp.txt
    set /p sitename= < temp.txt
    echo %sitename%
     
c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel