A cloud-native app needs a frontend for your users to work with. Here’s how to configure an Azure App Service and then create and deploy an ASP.NET Core server-side frontend to that App Service using Visual Studio code.
In previous posts, I’ve created a Web Service (Part 5) that securely accessed an Azure SQL database. The next obvious step is to create a frontend for that Web Service and then secure access between that frontend and the Web Service.
In this post, I’m going to cover creating a server-side frontend in ASP.NET Core in Visual Studio Code and deploying it to an Azure App Service (there’s a companion post to this one that does the same for a client-side JavaScript/TypeScript frontend using React (Part 7a). In a follow-on post, I’ll restrict the Web Service to only talk to this authorized frontend.
If you’re interested in this post, I’m going to assume that you have downloaded both .NET 8 and Visual Studio Code.
To initialize a Razor Pages project and open it in Visual Studio:
<name of your frontend app>
with the name you want to give your frontend app (I used WarehouseManagementFrontend
):dotnet new razor -o <name of your project> -f net8.0
cd <name of your project>
code .
Visual Studio Code will probably prompt you to install the extensions for the C# and C# Dev Kit extensions (assuming you don’t already have them installed). If so, let Visual Studio Code install them.
If you don’t have those extensions installed and aren’t prompted, then you’ll need to install them. To do that:
Your next step is to write the code to access your Web Service. In Visual Studio Code, in the Explorer pane on the left, expand the Pages node and double click on the Index.cshtml.cs file to open it. In that file:
public class Product
{
public int productId {get; set;}
public string name {get; set;}
public decimal listPrice {get; set;}
}
private readonly ILogger<IndexModel> …
, add this line: public List<Product> Products = new();
OnGet
method and replace it with this code:public async Task OnGetAsync()
{
HttpClient hc = new();
HttpResponseMessage resp = await hc.GetAsync(<URL for your Web Service>);
if (resp.IsSuccessStatusCode)
{
Products = await resp.Content.ReadFromJsonAsync<List<Product>>();
}
}
}
<div>
element and everything inside it. Replace it with this code (changing the property names on the prd
variable with your own property names):@{ foreach (var prd in Model.Products)
{
<p>
Product Id: @prd.productId <br/>
Product Name: @prd.name <br/>
Product Price: @prd.listPrice <br/>
</p>
}
}
Now you need to build your app. Save your code (unless you have auto-save turned on in Visual Studio Code, in which case, your code is already saved). From Visual Studio Code’s Terminal menu, select New Terminal to open a terminal pane below your code pane. In the newly opened Terminal pane, type dotnet build to check that you don’t have any coding errors.
After cleaning up any coding errors (and saving your file after making those changes), you’re ready to deploy your app.
The first step in deploying your app to Azure is to create an App Service. You can do this from within Visual Studio Code, but I think using Azure Portal’s UI helps understand what’s going on. So what follows is a cut-down version of the steps from my earlier post on creating an App Service (Part 3) that uses the Azure Portal.
After surfing to the App Services page in the Azure portal, click on the + Create at the left end of the menu at the top of the page and select Web App to start the Create Web App wizard.
As with any Azure resource, you’ll need to assign your App Service to a resource group and give it a name (the App Service’s name gets rolled into a URL so you can’t use spaces, though this page will let you use upper case letters).
By default, the Wizard will automatically tack a random string at the end of the name so that the resulting URL is unique, but you can turn that off using the toggle switch right below your App Service’s name (I called my service WarehouseMgmtFrontEnd
, for example, which turned out to be unique).
To support my frontend, I set the Code/Container radio button to Code (check out that earlier post for a discussion around picking the Container choice). Picking the Code option displays the Runtime stack dropdown that lets you pick what support for your application will be loaded into the App Service. I picked ASP.NET Core 8 because it matched the version of ASP.NET that I was using. For the operating system, I picked Windows because that was the platform I was developing on (and also lets me use Remote Debugging).
I set the Region to the same region as the Azure SQL database I created in my previous post, Coding Azure 2: Configuring an Azure SQL Database, to avoid any cross-region charges (that’s Canada Central, in my case).
Following those selections are the choices that let you set how much processing power you’ll get (and, as a result, how much you’ll pay). Under Pricing Plan, I clicked on Create New and, in the resulting dialog, gave my plan a name.
When you return from assigning your plan a name, you’ll have a dropdown list of available plans. For this case study application I selected the Free F1 plan which gives me 60 processing minutes a day to play with. In real life, you’ll probably need more processing power than that.
On the Monitoring + secure Tab, I disabled Application Insights because I didn’t want to pay for it.
With those changes made, I clicked the Review + Create button and then the Create button to create my App Service.
Back in Visual Studio Code, you need to add some extensions to support deploying your app to an Azure App Service.
To add those extensions, in Visual Studio Code, click on the Extensions icon again. In the Search box at the top of the panel, search for the Azure App Service extension and install it. (This should also install the Azure Resources extension, but you might want to search for it in the Extensions pane and confirm that it is installed). A new Azure icon will be added to the panel on the left side of Visual Studio.
You’re now ready to deploy your app:
As your deployment is processing, you’ll be asked if you want to always deploy your project to this App Service. Pick the “Yes” option.
If your deployment succeeds, you’ll get a button that will allow you to Browse Website. Click that button to try viewing your app (you can also right-click on your App Service in the Azure panel on the left and select Browse Website).
Your browser should display the information returned from your Web service. If it doesn’t—don’t panic! It’s entirely possible that your database didn’t respond in time because it was in idle mode. Try some refreshes over a couple of minutes before debugging.
If you picked the “always want to deploy” option on your first deploy, then, when you have the Azure icon selected in Visual Studio Code’s far left menu, you’ll see a Workspace bar displayed in the Azure pane. If you hover your mouse over that bar, you’ll see an App Service icon displayed at the right end of the bar. Clicking that icon will re-execute your deployment so that you don’t have to find your App Service in the Azure pane (you’ll still have to click “Deploy” in the “are you sure” dialog, though).
And since you are deploying from your app’s bin/publish folder, you have to remember to do a build before deploying to get the latest version of your code.
Given all of those steps, it’s worth noting that you don’t have to deploy to Azure in order to test your app, using the dotnet run command in Visual Studio Code’s terminal window (or pressing F5 in Visual Studio) will let you run your app on your local computer.
As long as we’re working on our frontend, we should spend a little time thinking about maintainability.
Our frontend will be passing business transactions to a more complex system probably consisting of multiple steps and/or microservices. When things go wrong in production (and they will), you’ll need to be able to track those transactions through the various microservices that process that transaction.
It makes sense, at this point, to generate a correlation id for every transaction submitted by your frontend that you can hand off to all subsequent processes. Those processes can then incorporate that correlation id in their logs and/or error messages. Having a correlation id for a business transaction be very helpful in figuring out what actually happened to that transaction.
The only real requirement for the correlation id is that it must be unique for each transaction. You could assemble a correlation id from parts of the information associated with the transaction (e.g., date and time down to the millisecond), but, for this case study, I’m going to generate a unique identifier using the .NET Core Guid object and pass it to my Web Service in the X-Correlation-ID header of my request:
string correlationId = Guid.NewGuid().ToString();
hc.DefaultRequestHeaders.Add("X-Correlation-ID",
new string[] { correlationId });
In the Web Service, to retrieve the header, you need to accept (as a parameter to your API method) the HttpRequest object that represents the request made to the service. Within your API method, you can use the HttpRequest object’s Headers collection to retrieve the header by name (in this case, the name you want is “X-Correlation-ID”). Once you’ve retrieved the correlation id, it’s up to you how you want to use it.
That means the start of a typical Web API method (with a sample log message that takes advantage of the correlation ID) would look something like this:
app.MapGet("/products", (HttpRequest req) =>
{
string correlationId = req.Headers["X-Correlation-ID"].ToString();
app.Logger.LogInformation("Request received, Correlation Id: " + correlationId);
Your next step is to secure the access between your frontend and your Web Service. That’s my next post (assuming you skip over the “creating a JavaScript/TypeScript frontend in React (Part 7a)” post).
Peter Vogel is both the author of the Coding Azure series and the instructor for Coding Azure in the Classroom. Peter’s company provides full-stack development from UX design through object modeling to database design. Peter holds multiple certifications in Azure administration, architecture, development and security and is a Microsoft Certified Trainer.