Skip to main content
Published / updated

Hosting the Application

Before you start​

You need: Stage 10. You have a Release build of the API, a built frontend, and no secrets in source control.

You also need: a Microsoft account, and a card for Azure identity verification if you take that route. The free tier does not charge it, but Azure asks for it.

Time: 3–5 hours the first time. Under thirty minutes every time after.

Learning objective​

Deploy the API, the frontend and the database somewhere a stranger can reach them, and explain every configuration difference between that environment and your laptop.

Topics​

  • Why a live URL changes the conversation
  • What has to be hosted, and where
  • The database first
  • Deploying the API to Azure App Service
  • Configuration and connection strings in the cloud
  • The frontend, and the CORS change it forces
  • The IIS route instead
  • Keeping it cheap, and what to do when it sleeps

Why bother​

Stage 10 ended with a build in a folder. That is a deployable artefact, not a deployment. This stage puts it somewhere with a URL.

The practical reason: a link on a resume is opened. A GitHub repository is not, at least not first. A recruiter with sixty applications clicks a link before they clone anything, and a working screen buys the thirty seconds that gets the repository looked at too.

The better reason: deploying is where you find out what you actually understood.

It worked locally becauseProduction makes you handle it
The connection string was in a file on your machineConfiguration comes from the environment
The API and the frontend were both localhostTwo real origins, so CORS becomes real
You ran as yourself against a local SQL ServerA restricted database login, over the network
dotnet run set the environment to DevelopmentProduction, so the exception page is off
Certificates were the development onesReal HTTPS

Every one of those is an interview question, and having deployed once turns each into a story rather than a definition.

What has to be hosted​

Three separate things. Students routinely try to deploy them as one and get stuck.

PartWhat it isWhere it goes
DatabaseSQL ServerA hosted SQL database
APIAn ASP.NET Core application, always runningAn app host — App Service or IIS
FrontendStatic HTML, CSS and JavaScript after npm run buildAny static host

Deploy in that order. The API needs the database to start cleanly; the frontend needs the API's URL baked into its build.

The database first​

Create a hosted SQL database, then run your Track 06 script against it from SSMS — the same script that drops and rebuilds locally.

Two things to do at creation time, and both catch people out:

  • Set the firewall to allow your own IP, or SSMS cannot connect at all. On Azure SQL this is under Networking → Add your client IPv4 address.
  • Allow Azure services to reach it, or your App Service cannot connect even though SSMS can. Same page, a separate checkbox.

Create a login for the application that is not the admin login. The application needs SELECT, INSERT, UPDATE, DELETE and EXECUTE on your procedures — nothing else. It does not need to create tables at runtime.

Seed only demonstration data. Ravi Kumar, Priya Sharma, Dr. Mehta, NexCoding Academy. Never real names, never real phone numbers. This URL is public and you are about to put it on a resume.

Free tiers change. Azure's free database offer, its size limits and its duration are not what they were two years ago and will not be this in another two. Check the current terms on the pricing page before you create anything, and set a spending limit or a budget alert on the subscription while you are there.

Deploying the API​

From Visual Studio:

  1. Right-click the API project → Publish.
  2. Target Azure → Azure App Service (Windows) → Next.
  3. Sign in, then Create new. Pick a resource group, a region near you, and a hosting plan on the Free F1 tier.
  4. Finish, then Publish.

The first publish takes a few minutes and ends with a browser tab at https://your-app-name.azurewebsites.net.

It will not work yet. It has no connection string and it does not know it is in production. That is the next section, and it is the part worth understanding.

A note on the free tier. F1 gives you a small daily CPU allowance and no custom domain or scaling. That is fine for a portfolio. It also puts the app to sleep after about twenty minutes idle, so the first request after a quiet spell takes fifteen to thirty seconds while it starts. Plan for that — see the last section.

Configuration in the cloud​

Your appsettings.json has no production connection string and no JWT signing key, because Stage 10 established that committing either is unrecoverable. So the host has to supply them.

In the portal, open the App Service → Configuration:

AddAsValue
ConnectionStrings:SchoolDbConnection string, type SQLAzureThe one from the database's connection strings page, with the application login
Jwt__KeyApplication settingA newly generated key — not the one from your machine
Jwt__Issuer, Jwt__AudienceApplication settingsYour App Service URL
ASPNETCORE_ENVIRONMENTApplication settingProduction

The double underscore is not a typo. Environment variables cannot contain a colon, so ASP.NET Core reads Jwt__Key as the Jwt:Key you wrote in Article 03 of the ASP.NET Core track. Jwt:Key as a variable name silently does nothing, and the error you get is a confusing one about the key being missing.

Generate a new signing key for production. If the production key equals your development key, every token you minted while debugging is valid against the live site. Rotating it is one setting; explaining why you rotated it is an interview answer.

Then confirm the environment is right. Visit an endpoint that throws. You should see a plain 500 with a trace id, not a stack trace. If you see the developer exception page, ASPNETCORE_ENVIRONMENT did not take — save the setting and restart the app.

Check /version from Stage 10. It tells you which commit is live, which is the first question when something behaves oddly.

The frontend, and the CORS change​

Build the frontend against the deployed API, not localhost:

npm ci
npm run build

The API base URL must come from the frontend's environment file, not be typed into a service class — the same rule as the API's connection string, for the same reason. Then upload the dist output to any static host: Azure Static Web Apps, Netlify, Vercel or GitHub Pages all take a folder.

Now the API rejects it, and the browser console says the request was blocked by CORS policy. This is correct behaviour, not a bug.

In Article 11 of the ASP.NET Core track you allowed http://localhost:5173. Your frontend is now at a real domain, and the API has never heard of it. Move the allowed origins into configuration and add the real one as an App Service setting.

Do not "fix" this with AllowAnyOrigin. It works, and it means any site on the internet can call your API with a user's credentials attached. A reviewer who sees AllowAnyOrigin next to AllowCredentials in a portfolio project has learned something about the candidate — and ASP.NET Core actually refuses that combination at startup, which is the framework telling you the same thing.

Fix CORS on the server, always. Browser extensions that disable it change nothing for your users.

The IIS route instead​

If the training environment gives you a Windows server rather than a cloud subscription, the shape is the same and the steps differ.

  1. Install the ASP.NET Core Hosting Bundle on the server. This is the step everyone misses, and the symptom is a 500.19 or 500.31 on every request.
  2. In IIS Manager, add a website pointing at your published folder.
  3. Set the application pool's .NET CLR version to No Managed Code — ASP.NET Core runs its own runtime; IIS is only the front door.
  4. Give the app pool identity read access to the folder, and the database login rights to the database.
  5. Set ASPNETCORE_ENVIRONMENT — in web.config, or as a system environment variable.

500.30 means your application started and crashed, usually on a missing connection string. Turn on stdout logging in web.config, hit the site once, and read the log file. That single trick resolves most first-deployment failures on IIS.

Keeping it cheap and awake​

  • Set a budget alert on the subscription on day one. The free tier is free until something you created is not on it.
  • Delete the resource group when you are finished with a demo. It removes everything inside in one action.
  • Expect the first request to be slow on a free plan. Do not let an interviewer meet that cold start — open the URL two minutes before the call.
  • Put the cold start in your README. "Hosted on a free tier; the first request may take up to thirty seconds while the app wakes." That reads as someone who understands their deployment, not as an excuse.
  • Screenshot the working application and put the images in the README as well, so the project survives the day you take the hosting down.

Common mistakes​

  • Deploying the API before the database exists, then debugging a startup crash that is only a missing table
  • Leaving the firewall closed to Azure services and concluding the connection string is wrong
  • Using Jwt:Key instead of Jwt__Key in an environment variable
  • Reusing the development signing key in production
  • Shipping with ASPNETCORE_ENVIRONMENT unset, so the exception page is live
  • Answering CORS with AllowAnyOrigin rather than the real origin
  • Baking the API URL into the frontend source instead of its environment file
  • Seeding real student names and phone numbers into a public demo
  • Forgetting the Hosting Bundle on IIS and reading 500.19 as a code problem
  • No budget alert

Practice​

  1. Create the hosted database. Open the firewall to your IP and to Azure services.
  2. Run your Track 06 script against it from SSMS. Seed demonstration data only.
  3. Create an application login with only the rights the application needs.
  4. Publish the API to a Free F1 App Service.
  5. Add the connection string, a new JWT key, the issuer, the audience, and ASPNETCORE_ENVIRONMENT.
  6. Hit an endpoint that throws. Confirm you get a plain 500 and not a stack trace.
  7. Build the frontend against the deployed API URL and host the output.
  8. Watch the CORS failure happen. Fix it on the server, with the exact origin.
  9. Sign in and run the Stage 10 smoke test against the live site.
  10. Add the live URL, the cold-start note and screenshots to the README.
  11. Set a budget alert.

You can now​

  • Name the three separately hosted parts and the order they deploy in
  • Create a hosted database with a firewall and a least-privilege application login
  • Publish an ASP.NET Core API to App Service, or to IIS with the Hosting Bundle
  • Supply connection strings and keys from the environment, with __ for :
  • Prove the application is running as Production
  • Diagnose and correctly fix a CORS failure between two real origins
  • Explain why production gets a different signing key
  • Put a live URL on a resume and describe its limits honestly

Review questions​

  1. Why must the database be deployed before the API, and the API before the frontend?
  2. Why does Jwt__Key work as an environment variable when Jwt:Key does not?
  3. Your frontend worked locally and is blocked in production. What changed, and where is it fixed?
  4. What does a 500.30 on IIS tell you that a 500.19 does not?
  5. Why is reusing your development signing key in production a problem, given that nobody else knows it?

Next: return to the Track 01 overview, or continue to Track 11 — Angular or Track 12 — React.