# Getting started
This page is designed to give you an introduction to doing common tasks in C# minimal server app. If you want to follow along with the steps here, then you first need to install the .NET 6 SDK (opens new window).
Before you can follow along with the minimal server quick start, please install the following:
- .NET 6 SDK (opens new window)
- An editor of your choice, such as VS Code (opens new window) or Visual Studio (opens new window)
Once you have done that, open a terminal such as PowerShell, Command Prompt, or bash. Run the following command to create your first app:
dotnet new web --output minimalapp
This command will create a new directory with a few files to get you started:
- Program.cs: This is your first code file we will be editing for most of this guide.
- MinimalApp.csproj: This is a project file that helps the
dotnet
command know how to run your code. We will ignore it for this guide as it has everything it needs already. - appsettings.json: This is a JSON configuration file with some initial settings for your app, we also will not be using these in this guide but you can use them to add your own settings like, for example, a connection string to get data from a database.
# Your app
Getting to know your app.
The app in your Program.cs looks like this:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
2
3
4
5
6
What have we built?
In four lines of code
var builder = WebApplication.CreateBuilder(args);
You create an app builder, which is used to configure the app. In this default example, you aren't doing any configuration yet, so just build an app
object. You use the builder to create an app and then you run the app, this is known as the builder pattern.
var app = builder.Build();
Build the app
object, the app
object is what we will use to route URLs to code.
app.MapGet("/", () => "Hello World!");
You call MapGet
, which is how you route URLs to code.
app.Run();
Finally, app.Run
executes the app you configured in the previous lines. It's not until you call Run
that your app will start and you can browse to URLs.
# Running your app
To run your app, use the dotnet run
command on your terminal in the same directory as the Program.cs file.
dotnet run
After running you will see log output like the following:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
2
3
4
5
6
7
8
9
If you navigate to http://localhost:5000
in a browser you will see the text Hello World!
as the browser makes a request to your app and displays the output.
# What if I see something different?
If you haven't changed any code in the Program.cs and your app still fails to run then it is likely a problem with the installation of dotnet
. But there are a couple of common things you might see:
- If you see an error saying
Couldn't find a project to run
then you are probably in the wrong directory, make sure your terminal is in the right place. - If you see an error saying
Failed to bind to address https://127.0.0.1:5001: address already in use
then you probably have anotherdotnet run
command running on another terminal window. You can stop that app by pressingCTRL + C
. You can only have one app listening on a given address on a computer. We will talk about how to change the URL your app is listening on a bit later.
# Basic Routing
When building a web application you typically want to try and create meaningful URLs that execute your code. For example, going to /hello
returns a hello string and going to /todos
or /todolist
shows me all the todo items I have. It doesn't matter what URL you use as long as it makes sense to you and you think it will make sense to your users.
In your ASP.NET Core program, you use the Map
methods to create an endpoint that binds a URL to our code:
app.MapGet("/hello", () => "Hello World!");
app.MapGet("/todos", () => new { TodoItem = "Learn about routing", Complete = false });
2
If you run the app with the above
/todos
route and view it in a browser, you'll see that the framework has automatically converted the todo item to JSON.
# Route Variables
You can add variables to routes using curly braces like {id}
:
app.MapGet("/hello/{name}", (string name) => $"Hello {name}");
This endpoint will match URLs like /hello/David
would return Hello David
. If you add this method to the ones shown earlier, then navigating to /hello
would return Hello World!
as the two endpoints have different routes and match differently.
If you have two routes the same then your application will still run, but when you try to navigate to those routes you will get an error like: In this image, we have two
hello
routes and the framework can't tell which code you want it to run, so it throws an error. Remember thathello/
andhello
are the same as far as ASP.NET Core is concerned, the end slash doesn't make them different.
# Constraints
You can specify the type of a variable by doing /hello/{name:int}
, which would mean that the route would no longer match if you navigated to /hello/David
but would match if you navigate to /hello/1
because we said that our name variable should be an int
in the route. These are called Route Constraints (opens new window) and allow you to have fine control over what code gets run when users enter different types of URLs.
# HTTP Methods Overview
So far we've shown MapGet
, which allows you to specify a HTTP Get action, which is what a browser sends when you go to a URL. But there are other HTTP methods you are likely to want and you can use other Map methods to get those, for example MapPost
or MapPut
. The other Map methods work the same as MapGet
that we've already seen but responds to a post or put respectively. You can learn more about HTTP request methods here (opens new window). For now, think of using Post
when sending data to the app and Get
when getting data from the app.
app.MapGet("/hello", () => "Hello World!");
app.MapGet("/todos", () => new { TodoItem = "Learn about routing", Complete = false });
app.MapPost("/todos", () => Results.Ok());
2
3
Notice that MapPost
and MapGet
in this example are using the same URL. That is because the different verbs can all use the same URL and ASP.NET Core will invoke the right code for you. What this allows is for you to create a URL for your todos and use GET to get todos and POST to add a todo.
# Error Handling Overview
If you have an unexpected error in your code, then ASP.NET Core automatically tries to show you what went wrong:
app.MapGet("/dobad", () => int.Parse("this is not an int"));
If you visit the dobad
URL in a browser, you'll see this:
And the following will appear in the terminal that you run dotnet run
in:
Both of these give you an idea of what's wrong. In this case, you tried to turn a string that isn't a number into an int
.
# Environments
In the previous screenshot, you can see the terminal output saying Hosting environment: Development
. This is controlled by the environment variable ASPNETCORE_ENVIRONMENT
. If the ASPNETCORE_ENVIRONMENT
is not set, then ASP.NET Core assumes the value is Production
, when using dotnet run
or editors like VS Code or Visual Studio they will set the value to Development
.
The error handling page showed above only appears when the environment is Development
. You can check the environment value yourself like this:
if (app.Environment.IsDevelopment())
{
app.MapGet("/OnlyInDev",
() => "This can only be accessed when the app is running in development.");
}
2
3
4
5
You can set the environment variable to whatever value you want and add whatever logic you like to your app based on the environment.
if (app.Environment.EnvironmentName == "TestEnvironment")
{
app.MapGet("/OnlyInTestEnvironment", () => "TestEnvironment");
}
2
3
4
The pre-defined values for environment are Development
, Staging
, and Production
. Development
is set by development time tooling like dotnet run
and we assume that the environment is Production
if it isn't set to anything. ASP.NET Core will add the error handling page to your app if the environment is Development
.
# Accessing Data
OK, so if you use MapPost
to send data to the code, how does that work?
# Model Binding
The most common way of accessing data in ASP.NET Core is to create classes and let ASP.NET Core fill them in for you:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/hello", () => "Hello World!");
app.MapGet("/todos", () => new { TodoItem = "Learn about routing", Complete = false });
app.MapPost("/todos", (Todo todo) => todo.Name);
app.Run();
class Todo
{
public string Name {get;set;}
public bool IsComplete {get;set;}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
This code will send the name part of aIf I then use Thunder Client in VS Code to send a request to the todos
URL then it would look like this:
ASP.NET will try to create an instance of the class you say you need from any JSON in the body
of a request. It will also automatically convert any objects you return to JSON, like in our GET
todos URL above.
# HttpContext
Another more basic way of accessing information, and data, from a request is using the HttpContext
object. ASP.NET Core creates a HttpContext
for each request, and you can access it in your code like this:
app.MapGet("/hello/{name}", (HttpContext ctx) => $"Hello {ctx.Request.RouteValues["name"]}");
In this code, you are accepting an HttpContext
and using it to manually access the route value rather than letting ASP.NET Core automatically match it like you did in the previous example. As well as all route values the HttpContext
has access to all request information, like the body and cookies. You can read from the request property of HttpContext and write to the Response property, which ASP.NET Core does for you in all of the examples before this one.
# Returning HTML
If you want to return some HTML rather than processing JSON like you've been doing so far, ASP.NET Core uses a language called Razor, which is a mix of C# and HTML to make authoring UI easier. So let's add Razor to your app:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
app.MapGet("/todos", () => new { TodoItem = "Learn about routing", Complete = false });
app.MapPost("/todos", (Todo todo) => todo.Name);
app.MapRazorPages();
app.Run();
class Todo
{
public string Name {get;set;}
public bool IsComplete {get;set;}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Then create a folder called Pages
and a file in that folder called Index.razor
with this content:
@page "/page/route"
<html>
<body>
<div>
This is some content.
</div>
</body>
</html>
2
3
4
5
6
7
8
9
Then if you run your application and navigate to /
you will see your content:
This is because Index
is the name of the default URL that a browser will try to load. If you called your cshtml
file SomethingElse.cshtml
then you would navigate to /SomethingElse
to see the content.