Contents
data/authors/Paul Logan.json

Evolution of Application Deployment techniques

Manual Deployment to local web server

My first procedure for getting the new bits onto the relevant domain IIS webserver were:

  • VS Code terminal: dotnet publish –configuration Release

  • Browse to \LegacyDatabaseMaintenanceApp\bin\Release\net7.0\publish

    • Sort files by date modified.
    • Copy the files that have just been updated.
  • Remote onto the IIS webserver and stop the application’s app pool.

  • Browse to the application folder on the web server and paste the files, overwriting those already there.

  • Start the AppPool for the app in IIS Manager.

Migrating from On-Premise App to Azure App Service

Our app was being hosted on an on-prem IIS server, displaying and updating data from our on-prem SQL Server database.

The app is now going to be moved into the Azure cloud. I only want some developers and managers to have access to this app, so I need to somehow authenticate who the user is. Being hosted in Azure, allows me to seamlessly use Entra ID (formerly Active Directory) to wrap authentication around my app.

Accessing internal Database from Azure

As an on-premise IIS hosted web app, connecting to the SQL Server over the LAN is pretty straightforward. However, when the app is moved to Azure and the database remains on-prem, another method of accessing the database is required.

Azure Relay and Azure Hybrid Connections provide an easy access option.

Download and install Hybrid Connection Manager.

Create the hybrid connection in your app with these instructions

Not Connected
The first time this is done, the Hybrid Connection Manager UI displayed a “Not Connected” warning message. Restarting the HybridConnectionManager windows service could resolve this.

Configure access to On-prem SQL Server from Azure Function

  • Function App resource => Networking (in Settings section) => Outbound Traffic => Hybrid Connections => Add Hybrid Connection => Select existing hybrid connection
  • Function App resource => Configuration => New connection string Server=tcp:MySqlServer,1433;Initial Catalog=master;Persist Security Info=False;User ID=[user];Password=[password];MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;

Initial Deployment to Azure

  1. Install & Enable(Workspace) Azure Resources extension for VS Code.
  2. Install & Enable(Workspace) Azure App Service extension for VS Code.
  3. Select the new Azure menu item (Ctrl+Shift+A).
  4. Expand the App Services dropdown.
  5. Right click the App Services dropdown, select Add New App and enter the details requested by the wizard.
  6. After the wizard completes, you should get a toast alert asking if you want to deploy the app - click Deploy, selecting the suggested folder to deploy.
  7. Click “Add config” button that is displayed - this will create a settings.json file containing the details for deployment to the app service.
  8. Another toast alert will ask you to “Always deploy the workspace “your app’s workspace” to “your new app service” - click yes.
  9. Azure Portal => App Service => Environment Variables => Connection Strings => Add connection strings to any referenced databases.
  10. After the deployment is completed, you will get another toast asking you if you would like to “Browse Website” - yes please (it could take more than the suggested 5 minutes for the site to show - i re-deployed from VS Code and coincidentally it worked soon after).

If you already have a settings.json file, then the deployment details will be appended to it after clicking “Add Config”, lines 7 and 8. After deployment and choosing to always deploy to the app service, line 9 is then added.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "diffEditor.ignoreTrimWhitespace": false,
    "window.title": "${folderName}",
    "workbench.editor.labelFormat": "short",
    "workbench.colorTheme": "Tomorrow Night Blue",
    "playwright.reuseBrowser": true,
    "appService.preDeployTask": "publish-release",
    "appService.deploySubpath": "bin/Release/net8.0/publish",
    "appService.defaultWebAppToDeploy": "/subscriptions/123-456-789/resourceGroups/YourResourceGroup/providers/Microsoft.Web/sites/YourSiteNameHere"
}

Subsequent Deployments to Azure

Right-click the App Service for the maintenance app, Deploy to Web App Click the Deploy button in the pop-up warning.

Deploying app to app service
Deploy app

Microsoft guidance

Subsequent Deployments to Azure - Keyboard Shortcuts

F1 button Type aasdwa and select “Azure App Service: Deploy to Web App” Microsoft guidance

Development & Live Databases

While in development, the app is (hopefully) interacting with a test database, as defined in the appSettings.json file:

{
  "ConnectionStrings": {
    "LegacyDbConnectionString": "SERVER=LegacyServer;DATABASE=LegacyDb_TEST;User ID=userID;PASSWORD=userPassword;Encrypt=False;"
  },
  "AllowedHosts": "*"
}

In Azure portal, in the App Servive for the app, go to the Environment Variables screen and click Connection Strings. Add a new setting here, using the same name as the connection string in the appsettings file and point it towards your live database.

App Service Connection String
App Service Connection String

Authentication - The Easy Way

I cannot believe how simple this was!

Follow these steps to simply and quickly add Azure AD authentication to the app.

And then to restrict access to the app to only those in the AD that should have access, I use the oh so easy approach described here

Authentication - The Hard Way

Based on these Microsoft tutorials.

I updated the existing appsettings.json file according to this:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "[Enter the tenantId here]",

    // Client ID (application ID) obtained from the Azure portal
    "ClientId": "[Enter the Client Id here]",
    "CallbackPath": "/signin-oidc",
    "SignedOutCallbackPath": "/signout-oidc"
  }
}

Then update the Program.cs with this initialization code. It shows the code using the old Startup.cs and Program.cs setup, so here it is in the new solo Program.cs format:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using PaulLogan.QualityDataMaintenance;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<QualityDbCtx>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("QualityDbConnectionString")));

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
   .AddMicrosoftIdentityWebApp(builder.Configuration, "AzureAd");

// Add services to the container.
builder.Services.AddRazorPages().AddMvcOptions(options =>
  {
      var policy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
      options.Filters.Add(new AuthorizeFilter(policy));
  }).AddMicrosoftIdentityUI();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();
app.Run();

I create the _LoginPartial.cshtml file in the \Pages\Shared folder, and copy its content as detailed here.

Then inject it into the _Layout.cshtml as explained in step 2.

This may be all taken care of for new projects by using the guidance here