Mert Özen Further With Every Line
Home Blog Setting up the initial project: project structure, Program.cs, and a minimal hosting model.
Backend .NET Core Web API — #02

Setting up the initial project: project structure, Program.cs, and a minimal hosting model.

Mert Özen Jul 5, 2026 11 min 39 views

We set up our first .NET 9 Web API project. We break down Program.cs line by line, and understand the minimal hosting model, the builder-versus-app split, and why middleware order matters.

Before Setting Up Your First Project: What Do You Need?

Before jumping into code, you only need two things on your machine: the .NET 9 SDK and an editor. On the editor side, Visual Studio, VS Code, or JetBrains Rider all work; I'll use the command line in the examples, because I want to see what's actually happening underneath. To check whether the SDK is installed, type this in your terminal:

dotnet --version

If you see a version number starting with 9., you're ready. If not, you'll need to download and install the .NET 9 SDK from Microsoft's official site. One note: the SDK and the Runtime are different things. The Runtime only runs applications, while the SDK lets you build them. We need the SDK.

Creating the Project

Now open an empty folder and step into it. We create our project with a single command:

dotnet new webapi -n KullaniciApi

Here webapi is a template name. It's one of the dozens of templates that ship with .NET; it sets up the API skeleton for us. -n gives the project its name. When you run the command, a folder named KullaniciApi is created and filled with a few files. Let's step into it and run the project:

cd KullaniciApi
dotnet run

You'll see a few log lines in the terminal, along with a local address, something like http://localhost:5xxx. There it is, your API is up. There's nothing noteworthy inside it yet, but it runs. Now let's look at the part that matters, where this magic actually happens.

Program.cs: Where Everything Begins

In the project's root directory there's a file called Program.cs. In the webapi template that comes with .NET 9, this file looks quite plain. You'll come across something roughly like this:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddOpenApi();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

Not much code at first glance, but every line does a job. In the old days, in .NET 5 and earlier, this work was split across two files: Program.cs and Startup.cs. Service registrations sat in one place, middleware configuration in another. The minimal hosting model introduced with .NET 6 merged the two into a single file. Fewer files, less ceremony, a faster way into the topic. This model continues in .NET 9.

Builder and App: Two Separate Stages

Once you understand the logic of this file, everything else falls into place. The code is split into two clear stages. The first stage is builder, the second is app. The turning point between them is the builder.Build() line.

The part up until builder.Build() is called is where you define what the application will have. We can call it the preparation stage. Here you register services: the database connection, authentication, the classes you wrote yourself... all of them are introduced to the system through builder.Services. In the example above, AddControllers registers the controllers, while AddOpenApi registers the API documentation infrastructure.

The part after the builder.Build() line is where you define how the application will behave toward incoming requests. We now have a ready-to-run app, and we tell it "when a request arrives, first do this, then do that." In short: on the builder side you decide what will exist, and on the app side you decide how those things will work. Once you settle this distinction, you won't get lost even in the most complex configurations you'll face later on.

What Is Middleware and Why Does Its Order Matter So Much?

The lines starting with Use... on the app side are the structures we call middleware. Think of middleware as a series of gates that every incoming request must pass through. The request moves from gate to gate; each gate either does something to the request or passes it along untouched to the next one.

For example, app.UseHttpsRedirection() is a gate that redirects the incoming request to HTTPS. app.UseAuthorization() is the gate that checks "does the person making this request have permission for it?" The critical point here is this: the order of these gates is determined by the order in which you write the lines. So the middleware you write first sees the request first.

Why does this matter? Let's think through a small example. Say you placed the authorization check before the authentication that determines who made the request. Then the authorization gate tries to ask "does this person have permission?" while there isn't even a user identity yet, and the logic collapses. When the order is wrong, the error message sometimes isn't very clear; you spend hours hunting for what went wrong. That's why you should set up the middleware order deliberately, not randomly. We'll go much deeper into this when we write our own middleware in later articles.

What Does app.Run() Do?

The app.Run() at the very end of the file is the line that starts the application and keeps it alive. The moment this call is made, the application starts listening for incoming requests and keeps running until you stop it. In other words, the program's flow enters a "waiting" state at this line. You can think of it as a server's ignition key; the moment you turn it, the engine runs and doesn't stop until you shut it down.

Controllers or Minimal API?

The template above sets up a controller-based structure; that is, you define your endpoints in separate classes. But .NET also has a lighter approach called minimal API, which lets you define endpoints directly inside Program.cs. For instance, you can write an endpoint in a single line:

app.MapGet("/merhaba", () => "Selam dünya!");

If you add this line before app.Run() and run the application again, going to the /merhaba address in your browser will greet you with "Selam dünya!". Both approaches have their place, and we'll talk at length about which to choose when in the next article. For now, the only thing you need to know is that both are built on the same foundation, this Program.cs logic.

What I'd Like You to Try Before We Wrap Up

Before moving on to the next article, try this: add the /merhaba endpoint above to your own project, run it, and see it in the browser. Then deliberately change the position of the middleware lines, for example move app.UseAuthorization() to the top, and observe what happens. Breaking something is the fastest way to understand why it sits where it does. In the next article, we'll compare the controller-based structure with the minimal API and clarify which one makes more sense in which project.