You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
415 lines
14 KiB
Markdown
415 lines
14 KiB
Markdown
---
|
|
marp: true
|
|
paginate: true
|
|
math: mathjax
|
|
theme: buutti
|
|
title: 1. Introduction to ASP.NET
|
|
---
|
|
|
|
# Introduction to ASP.NET
|
|
|
|
<!-- headingDivider: 5 -->
|
|
<!-- class: invert -->
|
|
|
|
## ASP.NET
|
|
|
|
* ASP.NET is a server-side framework developed by Microsoft
|
|
* Introduced in 2002
|
|
* Successor to Microsoft's Active Server Pages (ASP) technology
|
|
* Runs on the .NET platform, and can use all .NET supported programming languages
|
|
* A framework for building Internet-connected applications, like
|
|
* Web apps
|
|
* Web APIs
|
|
* Backend for desktop & mobile apps
|
|
|
|
## ASP.NET Core
|
|
|
|
* *__ASP.NET Core__* is a complete redesign & rewrite of ASP.NET
|
|
* Introduced in 2016
|
|
* Initially ran on both versions of .NET (Framework and Core)
|
|
* .NET Framework support was eventually dropped
|
|
* Open source, cross-platform
|
|
* Enhanced security compared to ASP.NET
|
|
* We will be focusing on Web APIs and won't be covering the frontend development tools of ASP.NET
|
|
|
|
<!-- APIs are interfaces that applicaitons use to communicate with each other
|
|
Xamarin for mobile
|
|
Use of NuGet packages add modularity and decrease the minimum memory footprint of your projects -->
|
|
|
|
### Why use ASP.NET Core?
|
|
|
|
* As a .NET application, supports *__NuGet packages__* that can be added to your projects modularly
|
|
* Full support for C#
|
|
* Base Class Library
|
|
* Great community support
|
|
* StackOverflow
|
|
* Open projects on GitHub
|
|
* Some companies have a long history with Microsoft frameworks
|
|
* ASP.NET is the logical choice in that case
|
|
* .NET is constantly getting updates and new releases
|
|
* Learn to read [the documentation](https://learn.microsoft.com/en-us/aspnet/core/?view=aspnetcore-9.0)!
|
|
|
|
## Swagger & Swagger UI
|
|
|
|
<div class='columns32' markdown='1'>
|
|
<div markdown='1'>
|
|
|
|
* [Swagger](https://swagger.io/) (now [OpenAPI](https://swagger.io/docs/specification/v3_0/about/)) is a language-independent specification for describing REST APIs without needing to look at the source code
|
|
* [Swagger UI](https://swagger.io/tools/swagger-ui/): Web-based UI for automatically providing information about the API (actions and their capabilities) using the specification above
|
|
* The default implementation of Swagger UI in ASP.NET is called [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) (see [docs](https://learn.microsoft.com/en-us/aspnet/core/tutorials/web-api-help-pages-using-swagger?view=aspnetcore-7.0
|
|
))
|
|
* Useful for basic debugging and testing
|
|
|
|
</div>
|
|
<div markdown='1'>
|
|
|
|

|
|
|
|
</div>
|
|
</div>
|
|
|
|
## Exercise 1: Creating an ASP.NET Core Web Application
|
|
<!--_class: "exercise invert" -->
|
|
|
|
1) Open Visual Studio and from the right select *Create a new project*
|
|
2) Search for *ASP.NET* and select _ASP.NET Core Web API_ ***(NOTE: Not Web App!)***
|
|
|
|
<div class='columns12' markdown='1'>
|
|
<div markdown='1'>
|
|
|
|

|
|
|
|
</div>
|
|
<div markdown='1'>
|
|
|
|

|
|
|
|
</div>
|
|
</div>
|
|
|
|
---
|
|
|
|
<!--_class: "exercise invert" -->
|
|
|
|
3) Give a *Project name* and set a *Location* for the repository, and check *Place solution and project in the same directory*. Click *Next* in the bottom right corner.
|
|
4) Select *.NET 9.0* under *Framework*. *Authentication type* should be *None* for now. Uncheck *Configure for HTTPS*. Click *Create* in the bottom right corner.
|
|
|
|
<div class='columns' markdown='1'>
|
|
<div markdown='1'>
|
|
|
|

|
|
* ***Note:*** *Configure for HTTPS* would enforce HTTPS for added security (see [docs](https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-9.0&tabs=visual-studio%2Clinux-sles))
|
|
|
|
</div>
|
|
<div markdown='1'>
|
|
|
|

|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
---
|
|
|
|
<!--_class: "exercise invert" -->
|
|
|
|
5) Add [Swagger](https://learn.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-8.0&tabs=visual-studio
|
|
) to your project. Go to *View > Other Windows > Package Manager Console* and run the following command:
|
|
```
|
|
Install-Package Swashbuckle.AspNetCore -Version 6.6.2
|
|
```
|
|
|
|

|
|
|
|
|
|
---
|
|
|
|
<!--_class: "exercise invert" -->
|
|
|
|
6) Make sure `Program.cs` includes the following lines:
|
|
```csharp
|
|
builder.Services.AddControllers();
|
|
|
|
builder.Services.AddEndpointsApiExplorer(); // add this
|
|
builder.Services.AddSwaggerGen(); // add this
|
|
|
|
// ...
|
|
|
|
if (app.Environment.IsDevelopment())
|
|
{
|
|
app.UseSwagger(); // add this
|
|
app.UseSwaggerUI(); // add this
|
|
app.MapOpenApi();
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
<!--_class: "exercise invert" -->
|
|
|
|
7) Start debugging from the top (the ▶ button with the text *http*).
|
|
* Click OK to trust the sertificates.
|
|
|
|

|
|
|
|
8) Open the Swagger UI in a web browser by going to `http://localhost:<port>/swagger`.
|
|
* The port number is shown on the debug console window that should now be open.
|
|

|
|
|
|
---
|
|
|
|
<!--_class: "exercise invert" -->
|
|
|
|
9) A web page should open, showing SwaggerUI for a weather forecast API. Click it open 🔽.
|
|
10) Click *Try it out*, and 11. *Execute* the **GET** request and see what it returns.
|
|
|
|
<div class='columns' markdown='1'>
|
|
<div markdown='1'>
|
|
|
|

|
|
|
|
</div>
|
|
<div markdown='1'>
|
|
|
|

|
|

|
|
|
|
</div>
|
|
</div>
|
|
|
|
---
|
|
|
|
<!--_class: "exercise invert" -->
|
|
|
|
12) Close the window. Browse through the source files on Solution Explorer on the right and check where the weather forecasts come from.
|
|
|
|
<div class='centered'>
|
|
|
|

|
|
|
|
</div>
|
|
|
|
## ASP.NET Core Web API contents
|
|
|
|
* In the previous exercise, we chose an API template for our new project, which have some files and dependencies already added
|
|
* The weather forecasts come from `WeatherForecastController.cs` in the *Controllers* folder
|
|
* (More on Controllers later...)
|
|
* Throughout this training, the aim is to get an understanding of the underlying logic of ASP.NET Core
|
|
* You can use the API template for the assignments, though
|
|
|
|
## `Program.cs`
|
|
|
|
* The `Program.cs` file in ASP.NET 7 is where the ***services*** for the web application are configured and the ***middleware*** is defined
|
|
* The file starts with defining the builder for the web application
|
|
```csharp
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
```
|
|
* The program is actually a console application that also hosts a web server
|
|
* The default server in ASP.NET applications is [Kestrel](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-9.0) (lightweight, cross-platform)
|
|
* The old default is [IIS](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/?view=aspnetcore-9.0) (Windows-specific, nowadays used as a [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) server)
|
|
|
|
### Services
|
|
|
|
* The controllers and some other components (like Swagger) are added to the application as ***services***
|
|
* Services are components that are available anywhere within your program via *dependency injection* (introduced in [C# Basics Lecture 15](https://gitea.buutti.com/education/csharp-basics/src/branch/main/15-design-patterns-in-csharp.md))
|
|
|
|
```csharp
|
|
// Add services to the container.
|
|
|
|
builder.Services.AddControllers();
|
|
builder.Services.AddEndpointsApiExplorer();
|
|
builder.Services.AddSwaggerGen();
|
|
```
|
|
* As the comment above suggests, more services can be added as needed
|
|
|
|
### Middlewares
|
|
|
|
* Handling of each HTTP request is defined as a set of [middlewares](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-9.0)
|
|
* Middleware is a software that's added into the middle of an app pipeline to handle requests and responses
|
|
* Middleware can decide whether to modify the data/request as needed, and pass the request into the next middleware
|
|
```csharp
|
|
if (app.Environment.IsDevelopment()){
|
|
app.UseSwagger();
|
|
app.UseSwaggerUI();
|
|
app.MapOpenApi();
|
|
}
|
|
app.UseAuthorization();
|
|
app.MapControllers();
|
|
app.Run();
|
|
```
|
|
|
|
## Routing
|
|
|
|
* *__Routing__* is how web APIs match the requested URI to a corresponding action
|
|
* The URIs that can be used to get a response from the API are called the *__endpoints__* of the API
|
|
|
|
| Request method | Endpoint | Action |
|
|
|:---------------|:---------------------------------------|:---------------------|
|
|
| `GET` | `http://someserver.com/api/products` | `GetProducts()` |
|
|
| `GET` | `http://someserver.com/api/products/3` | `GetProduct(int id)` |
|
|
| `POST` | `http://someserver.com/api/products` | `PostProduct()` |
|
|
|
|
## Attributes
|
|
|
|
* ***Attributes*** ([see C# Basics: Lecture 15](/education/csharp-basics/src/branch/main/15-design-patterns-in-csharp.md#attributes)) are a way of attaching metadata to entities (classes, methods, properties, etc.)
|
|
* In ASP.NET, attributes have a strong role in *__routing__*:
|
|
```csharp
|
|
[ApiController] // Attribute routing requirement,
|
|
// automatic HTTP 400 response, and more
|
|
[Route("[controller]")] // HTTP GET requests are routed to this method
|
|
public class WeatherForecastController : ControllerBase
|
|
{
|
|
//...
|
|
}
|
|
// ...
|
|
[HttpGet] // URIs with "/weatherforecast" are routed to this class
|
|
public IEnumerable<WeatherForecast> Get()
|
|
{
|
|
//...
|
|
}
|
|
```
|
|
|
|
|
|
|
|
|
|
## Attribute Routing
|
|
|
|
| | Attribute | Request |
|
|
|:------------------|:-------------------------------------------------|:---------------------------------------------|
|
|
| Class:<br>Method: | `[Route("api")]`<br>`[HttpGet]` | `GET <localhost>/api` |
|
|
| Class:<br>Method: | `[Route("api")]`<br>`[HttpGet("products")]` | `GET <localhost>/api/products` |
|
|
| Class:<br>Method: | `[Route("api")]`<br>`[HttpGet("products/{id}")]` | `GET <localhost>/api/products/12` |
|
|
| Class:<br>Method: | `[Route("api")]`<br>`[HttpPost("products")]` | `POST <localhost>/api/products` |
|
|
|
|
|
|
|
|
## Exercise 2: Setting up Routes
|
|
<!--_class: "exercise invert" -->
|
|
|
|
1) Change the routes in `WeatherForecastController.cs` so that the forecast result is printed at
|
|
`http://localhost:<port>/api/weatherforecast`
|
|
instead of
|
|
`http://localhost:<port>/weatherforecast`
|
|
|
|
You can see the route change in the Swagger UI `GET` method.
|
|
|
|
## Handling HttpGet Requests
|
|
|
|
* We have now established how to call methods with HTTP requests
|
|
* Additional parameters can be passed to the method with the URI:
|
|
```csharp
|
|
[Route("api")]
|
|
// class declaration
|
|
// ...
|
|
|
|
[HttpGet("list/{someText}")]
|
|
public string[] GetArrayOfStrings(string someText)
|
|
{
|
|
return Enumerable.Range(1, 5).Select(index => new string(someText))
|
|
.ToArray();
|
|
}
|
|
```
|
|
|
|
<div class='centered'>
|
|
|
|

|
|
|
|
</div>
|
|
|
|
---
|
|
|
|
* The URI parameters can be made optional with '?'
|
|
* A default value must be then set for the method parameter:
|
|
```csharp
|
|
[Route("api")]
|
|
// class declaration
|
|
// ...
|
|
|
|
[HttpGet("list/{someText?}")]
|
|
public string[] GetArrayOfStrings(string someText = "default")
|
|
{
|
|
return Enumerable.Range(1, 5).Select(index => new string(someText))
|
|
.ToArray();
|
|
}
|
|
```
|
|
|
|
<div class='centered'>
|
|
|
|

|
|
|
|
</div>
|
|
|
|
---
|
|
|
|
* Apply constraints for the parameters by setting them after `:`
|
|
* If the URI doesn't fit the constraints, the response will hold a `404` status code
|
|
```csharp
|
|
[HttpGet("products/{id:int}")] // Required type: int
|
|
[HttpGet("list/{value:length(3,40)}")] // Required length: 3-40
|
|
```
|
|
|
|
<div class='centered'>
|
|
|
|

|
|
|
|
</div>
|
|
|
|
## Exercise 3: Returning Your Own List
|
|
<!--_class: "exercise invert" -->
|
|
|
|
1) Change the `GET` method so that instead of returning an `IEnumerable` of `WeatherForecast` objects, it returns a `List` of `string` objects.
|
|
* Fill the list with e.g. names and make it as long as you want. Test with browser (Swagger UI).
|
|
2) Create a new method routed at `http://localhost:<port>/api/numberlist/k`, where `k` is any integer. The method should return an array of integers from `1` to `k`.
|
|
* For example, `http://localhost:<port>/api/numberlist/5` would return `[1,2,3,4,5]`. Test with browser (Swagger UI).
|
|
|
|
## Postman
|
|
|
|
* HTTP `POST` requests cannot be made with the browser's address bar, only `GET`!
|
|
* In websites, `POST` requests are usually made with forms
|
|
* In applications, all requests are sent by the client application
|
|
* For testing APIs, multiple tools like [Postman](https://www.postman.com/) or [Insomnia](https://insomnia.rest/) exist
|
|
* Before we cover handling `POST`, `PUT` and other requests in ASP.NET, let's first see how to make them with Postman
|
|
|
|
<div class='centered'>
|
|
|
|

|
|
|
|
</div>
|
|
|
|
## Benefits of using Postman
|
|
|
|
* When developing APIs, tools like Postman will almost always surface in the development cycle
|
|
* Postman lets you create configured HTTP requests to APIs, and save them to a JSON file
|
|
* This is great for testing your APIs without having to write code just for that purpose
|
|
* Supports all the necessary HTTP requests, like `GET`, `POST`, `PUT` and `DELETE`
|
|
|
|
## Exercise 4. Creating requests with Postman
|
|
<!--_class: "exercise invert" -->
|
|
|
|
Run the Weather API program, and test both methods with Postman.
|
|
|
|
1) To get started, open Postman (You can sign in or skip the login)
|
|
* Close the opened window to go straight to making requests
|
|
|
|
<div class='centered'>
|
|
|
|

|
|
|
|
</div>
|
|
|
|
---
|
|
<!--_class: "exercise invert" -->
|
|
|
|
<div class='columns23' markdown='1'>
|
|
<div markdown='1'>
|
|
|
|
2) Create your request by selecting the method and entering the URL
|
|
3) The response with the content body and status code show up below!
|
|
|
|
</div>
|
|
<div markdown='1'>
|
|
|
|

|
|
|
|
</div>
|
|
</div> |