Migrating a static web site using custom HTTP modules to Azure App Service

Developer Support

App Dev Manager Steve Keeler migrates a static web site using custom HTTP modules to an Azure App Service.


I was asked recently about migrating a local Internet Information Server (IIS) static web application to an Azure App Service. For this type of question, resources like the App Service Migration tool are usually a good place to start. In this case the App Service Migration tool reported issues based on the presence of location tags related to a custom HTTP module used by the web application.

Here is the web.config file for the local web application running on IIS that caused the “location tag” issue for the migration tool:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="DemoHttpModule" type="DemoHttpModule.DemoHttpModule"/>
    </modules>
  </system.webServer>
</configuration>

Fortunately, it is relatively straightforward to move this type of content into an Azure App Service. The source code for the this simple static web site and custom HTTP module is available in this GitHub repository.

To make it a little more interesting, we’ll setup build and release pipelines in an Azure DevOps project to automatically deploy committed source changes to an Azure App Service. If you’d like to replicate these steps in your own environment, you can follow along and start by Creating a project in Azure DevOps if you don’t already have one. Once you have an Azure DevOps project, use the Import a Git repo documentation to import the sample GitHub repository mentioned above into your Azure DevOps project repository.

The sample repository code is a very basic static web application. It primarily consists of a single main page, index.html and a CSS file site.css. The HTML for the main page is simply:

<body>
     <div class="main-container">
         <div class="content-body">
            <div class="success-text">Success!</div>
                <div class="description"> Your static HTML app is running on Azure</div>
            </div>
        </div>
    </div>
</body>

Another element in the repository is a custom HTTP module named DemoHttpModule. The key parts of the implementation for this module is:

public class DemoHttpModule : IHttpModule
    {
        public void Init(HttpApplication application)
        {
            application.BeginRequest +=
                (new EventHandler(this.Application_BeginRequest));
            application.EndRequest +=
                (new EventHandler(this.Application_EndRequest));
        }

        private void Application_BeginRequest(Object source, EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            context.Response.Write("<h1><font color=red>" +
                "DemoHttpModule: Beginning of Request" +
                "</font></h1><hr>");
        }

        private void Application_EndRequest(Object source, EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            context.Response.Write("<hr><h1><font color=red>" +
                "DemoHttpModule: End of Request</font></h1>");
        }
    }

The sample custom HTTP module prepends and appends HTML to every static web page request. The compiled assembly for DemoHttpModule is output into the \bin folder of the root directory for proper placement when the web application is deployed to the Azure App Service.

The final piece required is an XDT transformation to dynamically generate the configuration bindings for the DemoHttpModule in the Azure App Service. The XDT transformation is located in the applicationHost.xdt source file and has the following contents:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="DemoHttpModule" type="DemoHttpModule.DemoHttpModule"/>
    </modules>
  </system.webServer>
</configuration>

With the source code in place, we are ready to create build and release pipeline definitions to package and deploy the web application automatically. For more information on Azure DevOps pipelines, refer to the article Getting started with Azure Pipelines.

Two tasks are used for the build pipeline: Archive Files and Publish Build Artifacts. The YAML fragment for the build job tasks is:

pool:
  name: Default
steps:
- task: ArchiveFiles@2
  displayName: 'Archive files'
  inputs:
    rootFolderOrFile: '$(Build.Repository.LocalPath)'
    includeRootFolder: false

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: drop'

In the designer, the build definition appears visually as follows:

Build pipeline

Build pipeline

The release pipeline consumes the artifact published by the build pipeline and is configured to trigger whenever a new build artifact becomes available. It is represented visually as follows:

Release pipeline

Release pipeline

One task is used for the release pipeline: Azure App Service Deploy. The YAML fragment for the release job task is:

steps:
- task: AzureRmWebAppDeployment@3
  displayName: 'Deploy Azure App Service'
  inputs:
    azureSubscription: 'static-webapp-free'
    WebAppName: 'static-webapp-free'
    Package: '$(System.DefaultWorkingDirectory)\**\*.zip'
    TakeAppOfflineFlag: true
    UseWebDeploy: true
    RenameFilesFlag: true

In the designer, the release definition task appears visually as follows:

Release pipeline tasks

Release pipeline tasks

Once you have created your build (CI) and release (CD) pipelines, deploying the static web application with custom HTTP module is as easy as committing a change in the code repository.

After the build and release pipelines complete, loading the web application in a browser displays our test page:

web application

web application

The Beginning of Request banner at the top of the page and End of Request banner at the bottom of the page are injected into the page by the DemoHttpModule custom HTTP module.

0 comments

Discussion is closed.

Feedback usabilla icon