Remigiusz ZalewskiRemigiusz Zalewski

How to deploy ASP .NET Core Web Api to Azure

deploy-aspnet-core-web-api-to-azure

Introduction

Azure App Service is the straightforward middle ground between "runs on my machine" and a full Kubernetes deployment - a managed web host that takes a dotnet publish output and runs it, with scaling, custom domains, and TLS handled for you. This video walks the first deploy of an ASP.NET Core Web API to App Service, end to end, from an empty Azure subscription to a live HTTPS endpoint.

🎬 Watch the full video here:


App Service Plan vs. App Service

These are two different resources and the distinction matters for cost: the App Service Plan is the underlying compute (CPU, memory, pricing tier - Free, Basic, Standard, Premium), and the App Service (the actual web app) runs on top of it. Multiple App Services can share one plan, which is how you avoid paying for a full VM's worth of compute per API.

Picking the runtime stack correctly

Azure needs to know which .NET runtime to run the published output on - this is chosen when creating the App Service and has to match the app's target framework:

  • Runtime stack: .NET (matching your TargetFramework, e.g. .NET 9)
  • Operating System: Linux is generally cheaper and is the default recommendation unless something in the app depends on Windows specifically
  • Region: closest to your actual users, since it directly affects latency

Publishing from Visual Studio

Right-click the project, Publish, target Azure App Service, and either create a new one or pick an existing one. Visual Studio builds a publish profile that handles the zip-deploy under the hood - functionally the same as dotnet publish plus az webapp deploy, but wrapped in a UI wizard for the first deploy.

Configuration has to move separately from code

appsettings.json checked into source control should never contain production secrets - connection strings, API keys, anything sensitive belongs in App Service's Application Settings, which surface to the running app as environment variables and override anything in appsettings.json with the same key:

ConnectionStrings__DefaultConnection = <production connection string>

The double underscore (__) is .NET's convention for expressing nested configuration keys as flat environment variable names - ConnectionStrings:DefaultConnection in JSON becomes ConnectionStrings__DefaultConnection as an env var.

HTTPS and custom domains

App Service gives every app a free *.azurewebsites.net subdomain with HTTPS already configured. Adding a custom domain (api.yoursite.com) requires a CNAME record pointed at the App Service and, unless you bring your own certificate, an App Service Managed Certificate - free, auto-renewing, and bound to the custom domain once DNS is verified.

Common pitfalls

  • Choosing the wrong runtime stack and getting a generic 500 error with no obvious cause until you check the stack matches your TargetFramework.
  • Committing production secrets to appsettings.json. Use App Service Application Settings instead.
  • Forgetting the App Service Plan's pricing tier has hard limits (Free tier sleeps after inactivity, has no custom domain support).
  • Not checking Log Stream when something fails post-deploy. It's the fastest way to see the actual startup exception.
  • Assuming the deploy is done once it says "Success." Always hit the live endpoint to confirm before considering it finished.

Key Takeaways

  • An App Service Plan is the compute; an App Service is the app running on it - multiple apps can share one plan.
  • The runtime stack chosen in Azure must match your project's TargetFramework.
  • Application Settings in the Azure portal override appsettings.json values via __-delimited environment variable names - keep secrets there, not in source control.
  • Every App Service gets a free HTTPS subdomain; custom domains need a CNAME plus a Managed Certificate.
  • Check Log Stream first when a deploy succeeds but the app doesn't respond correctly.

Get the Full Source Code

The complete runnable solution - the API project and its publish profile - is available to Patreon supporters. If you want the exact configuration used instead of rebuilding it from the walkthrough above, you can find it on Patreon.

Resources