Nothing works the first time and everything breaks. You need to enable your App Service to support both debugging and logging
Let’s face it: The code you load into your App Service won’t work the first time (unless, of course, you’re following along with this column and are just copying-and-pasting code from my post Coding Azure 5: Securing a Web Service in an App Service to an Azure SQL Database on creating a Web Service … which seems unlikely). Alternatively, your code will have been working just fine in production and then, suddenly, stops working “just fine.” Either way, you have a problem you need to examine.
Sometimes, the problem will be what I call a “blunder”—just reviewing your code reveals the problem, enabling you to make a change and carry on. Sometimes, while you’ll need to step through your code (i.e., what most developers refer to when they say they’re “debugging”), you’ll be able to run your application from within your development environment (i.e., Visual Studio or Visual Studio Code)—that’s possible with frontend client-side apps as you’ll see in a later post.
But, more often than not, the problem with the code running in your App Service won’t be obvious and it won’t be possible to reproduce the problem even if you can run it from within your development environment. In this post, I’m going to look at two tools to support tracking down problems in your code running in an App Service: remote debugging and logging.
Remote debugging is probably the most satisfying choice for working through your code running in an App Service, but it’s not available for every combination of development tool, development platform and operating system. I’m going to assume that, while you may be using Visual Studio Code for developing both TypeScript/JavaScript/Node.js and .NET frontends, you would use Visual Studio exclusively for .NET backend applications (e.g., a Web Service).
And I should also specify that this is the state of the technology “as of” January 2025 and using .NET 8 and Node.js 20, so stuff may have changed since I wrote this:
Assuming that your App Service operating system and stack supports debugging from your chosen development tool, you first must enable remote debugging. For .NET apps, you can enable remote debugging through the Azure Portal. For Node.js apps running on Linux, you must enable it from Visual Studio Code.
For .NET apps, in the Azure portal, surf to your App Service and, from the menu on the left, select Settings | Configuration to open the Configuration panel on the right. Scroll down to the Debugging section (it’s waaaay down—it might be faster to use CTRL+F to do a search for “debugging”).
Under the Debugging heading, find the Remote Debugging radio button and set it to On. That will cause a dropdown list with the label Remote Visual Studio version to display. From the dropdown list, pick the version of Visual Studio that you’re using (I had only one choice: 2022).
Click the Save button to save your changes. If your App Service is currently running (and, if you’re setting up to debug, it probably is) you’ll probably get a message that your service will start and restart. Click the Continue button.
Now that you’ve got your App Service configured, return to your project in Visual Studio and make sure that Visual Studio is configured correctly. From the Tools menu, select Options to display the Options dialog. In the treeview on the dialog’s left, click on the Debugging node and, in the panel that appears on the right, check the Enable Just My Code checkbox (this will speed up stepping through your code immeasurably).
If you haven’t set your Publish profile to deploy a debug version of your code, you should do that now (I described that in a previous post, Coding Azure 3: Creating an App Service for a Web Service, ideally to the Deploying to Your App Service from Visual Studio subhead).
Now that your App Service and your Visual Studio project are configured, you can debug your Web Service. It wouldn’t hurt to republish your Web Service to your App Service just to make sure that the source code you’re stepping through in Visual Studio matches the compiled code in the service (especially if you’ve changed your publish settings).
To enable debugging:
Now, in your code, you can set a breakpoint on some code that will be hit when your Web Service is called. To actually run your code, open a browser window, and surf to your Web Service’s URL (or, if you already have a browser window open at that URL, click the browser’s Refresh button). Switch back to Visual Studio and wait for your breakpoint to be hit.
Once you find your problem, you’ll want to update your code, which will require you to stop debugging before making your changes and republishing your app. If your change doesn’t solve your problem (or if your fix just lets you move on to the next problem in your app), you’ll have to reattach to your app service to resume debugging.
Fortunately, you should also find that Visual Studio’s Debug menu has a new choice: Reattach to w3wp.exe (or Reattach to process if you haven’t attached in this session). Picking that option will shorten the process to reconnecting to the App Service—but not by much. You’ll still get the dialog with the list of processes but you can reconnect to the process just by double-clicking on the process in the list.
One other note about reconnecting: If you get a dialog box that asks for your credentials, in my experience, you can just click the Cancel button and continue.
To debug from Visual Studio Code, you need to install the Azure App Service extension from Visual Studio Code’s extensions menu and will be limited to debugging Node.js apps (I assume you’ve done that, otherwise your Visual Studio Code application wouldn’t be running in an App Service).
Once you’ve installed the extension:
If this is your first debugging session, you’ll be asked to enable remote debugging. And starting remote debugging session can take, literally, minutes. Be patient.
After starting the session, debugging your remote application should work identically to debugging a local app.
In any complex system, nothing works right all the time. Determining what, exactly, is going wrong and, more importantly, where it’s going wrong is essential to addressing anything that’s your responsibility (some problems really do go away by themselves, and some problems belong to other people).
That means that, when your code stops working “just fine” in production you need observability—you need to see what your code is doing. And that means logging (and Application Insights, but that’s a different topic). As part of setting up your App Service and writing your initial code, you should be supporting logging to be ready for that moment when your production system stops working “just fine.”
To enable logging in your App Service, in Azure Portal, surf to your App Service. From the menu on the left, select Monitoring | App Service logs to open the App Service logs pane on the right.
In the logging page, at the top, set the Application logging toggle to File System. Once you enable logging, a Level dropdown list will display that lets you set the lowest level you want to see messages for (i.e., if you pick Warning, you’ll also get Error messages). I selected Verbose because, in development, more information is always valuable.
If your App Service is running on Windows, you have several more choices in addition to Application logging, including dumping all the HTTP-level errors to a log (just set the web server logging toggle to On). Another example: In production, your app is probably replacing the default error pages with custom pages, but you can have those default error pages dumped to your log files anyway by setting the Detailed error messages toggle to On.
Once you’ve finished making your development-level changes, click the Save button at the top left of the panel before you leave the panel.
To review your log file output in near-real time (i.e., as in a debugging session), back in the App Services menu on the left, under the Monitoring node, select Log stream (it’s right under App Service logs).
If you’re getting more messages than you find useful, you can reduce the level of the logging messages that you set when configuring logging in the log stream panel—just use the Log Level dropdown at the top of the panel that displays your log messages. If, for example, you set your message level to Verbose while configuring log settings, you can limit messages to just warnings in the Log stream window. You can’t lower the level and increase the number of messages beyond what you set when configuring logging, though. If you set your message level to Warnings in log settings, setting the level to Verbose in log streams won’t get you any more messages.
With logging configured to support debugging, you will get whatever messages are automatically generated by the App Service. You should add to your code any messages that you think will be helpful in debugging your app using your platform’s logging support.
In a client-side JavaScript/TypeScript app, you can use console.log to write to your App Service’s log.
In a .NET frontend app, you can grab the ILogger object automatically added to your project’s Service’s collection in a Razor Page or controller’s constructor. This code in a Web API controller would do the trick:
public class HomeController : Controller
{
private readonly ILogger<HomeController> logger;
public HomeController(ILogger<HomeController> logger)
{
this.logger = logger;
In a minimal Web Service’s Program.cs file, you can use the ILogger object available from your WebApplication object’s Logger property to write to the Log Stream using any of the object’s various Log* methods (e.g., LogError, LogWarning, etc.).
Enhancing my .NET code from previous post Coding Azure 2: Securing a Web Service in an App Service to an Azure SQL Database to provide logging support for debugging, I could end up with code like this (you’ll need to decide how much logging you think is appropriate—though, in my experience, it’s very difficult to have “too much”):
app.MapGet("/products", () =>
{
List<Product> prds = new List<Product>();
Product prd = null;
try
{
app.Logger.LogInformation("Creating Connection");
SqlConnection con =
new SqlConnection(@"Server=tcp:warehousedbserver.database.windows.net;
User Id=237ffe44-cf7f-4012-b2cc-239c59dfe0d1;
Initial Catalog=WarehouseDB;
Authentication='Active Directory Managed Identity';");
app.Logger.LogInformation("Opening Connection");
con.Open();
…
With logging and debugging tools in hand, you can start to resolve problems in your Web Service and your frontends.
In my next posts, I’ll look at creating a .NET 8 server-side frontend and a JavaScript/TypeScript client-side frontend and enable only those frontends to talk to my Web Service. I’ll create both of those frontends in and deploy them to an App Service from Visual Studio Code.
After that, I’ll secure each of those front ends to my Web Service so that it can only be accessed from my frontend. Fun! (OK, not really, but necessary).
Peter Vogel is the author of the Coding Azure series, providing full-stack consulting from UX design through object modeling to database design. Peter holds multiple Azure certifications in Azure administration, architecture, development and security. He is also a Microsoft Certified Trainer.