Skip to content

Commit 0786791

Browse files
committed
Added firstapi sample and some docs
1 parent 06938ce commit 0786791

File tree

11 files changed

+299
-0
lines changed

11 files changed

+299
-0
lines changed

sessions/Season-05/0505-ApiDesignAndDevelopment/README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# 0505 - API Design and Development with C# and .NET
22

3+
In response to [question #79](https://github.com/csharpfritz/csharp_with_csharpfritz/issues/79) we invited Shayne to join us to talk about APIs.
4+
35
## Topics
46

57
- Build an API with ASP()[].NET Core and Swagger
@@ -12,6 +14,85 @@
1214
- Connecting to a frontend framework: Razor Pages, Blazor, etc
1315
- Deployment - Containers and App Service
1416

17+
## Build your first API with ASP[]().NET Core and Swagger
18+
19+
It's drop dead simple to get your first app running with Swagger to get awesome documentation and interactions for your API.
20+
21+
```cli
22+
dotnet new webapi
23+
```
24+
25+
When you run the app and navigate to https://localhost:5001/swagger you'll find the swagger documentation for your new API:
26+
27+
![Swagger Page for your API](firstapi_swagger.png)
28+
29+
Customize it further with [Swashbuckle tools](https://docs.microsoft.com/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-5.0&tabs=visual-studio).
30+
31+
You can generate and build client-side code with the dotnet-openapi tool. Details at https://docs.microsoft.com/aspnet/core/web-api/Microsoft.dotnet-openapi
32+
33+
## Design Patterns
34+
35+
## API Versioning
36+
37+
## Caching
38+
39+
## Pagination
40+
41+
## Uploading files to an API
42+
43+
Instead of receiving an input parameter of type string or int, receive an input parameter of type `IFormFile` like this:
44+
45+
```csharp
46+
[HttpPost]
47+
public async Task<IActionResult> UploadFile(
48+
IFormFile file,
49+
CancellationToken token
50+
)
51+
{
52+
53+
using (var stream = new FileStream("somefolder\\myuploadedfile.txt"))
54+
{
55+
56+
await file.CopyToAsync(stream);
57+
58+
}
59+
60+
}
61+
```
62+
63+
The ASP[]().NET team has some [recommendations when handling files](https://docs.microsoft.com/aspnet/core/mvc/models/file-uploads?view=aspnetcore-5.0) for you, and we'll copy them here to ensure you see them:
64+
65+
### Security Considerations
66+
67+
Use caution when providing users with the ability to upload files to a server. Attackers may attempt to:
68+
69+
- Execute denial of service attacks.
70+
- Upload viruses or malware.
71+
- Compromise networks and servers in other ways.
72+
73+
Security steps that reduce the likelihood of a successful attack are:
74+
75+
- Upload files to a dedicated file upload area, preferably to a non-system drive. A dedicated ___location makes it easier to impose security restrictions on uploaded files. Disable execute permissions on the file upload ___location.†
76+
- Do not persist uploaded files in the same directory tree as the app.†
77+
- Use a safe file name determined by the app. Don't use a file name provided by the user or the untrusted file name of the uploaded file.† HTML encode the untrusted file name when displaying it. For example, logging the file name or displaying in UI (Razor automatically HTML encodes output).
78+
- Allow only approved file extensions for the app's design specification.†
79+
- Verify that client-side checks are performed on the server. Client-side checks are easy to circumvent.
80+
- Check the size of an uploaded file. Set a maximum size limit to prevent large uploads.
81+
- When files shouldn't be overwritten by an uploaded file with the same name, check the file name against the database or physical storage before uploading the file.
82+
- Run a virus/malware scanner on uploaded content before the file is stored.
83+
84+
### Server Configuration
85+
86+
YOu will need to [extend the configuration of Kestrel](https://docs.microsoft.com/aspnet/core/mvc/models/file-uploads?view=aspnetcore-5.0#server-and-app-configuration) in order to receive larger files.
87+
88+
## JWT Authentication
89+
90+
Blog at: https://devblogs.microsoft.com/aspnet/jwt-validation-and-authorization-in-asp-net-core/
91+
92+
## Connecting to a front-end framework
93+
94+
## Deploying - Docker, Azure, etc
95+
1596
## Reference articles
1697

1798
- Brady's API series on DevBlogs:
Loading
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.Extensions.Logging;
7+
8+
namespace FirstApi.Controllers
9+
{
10+
[ApiController]
11+
[Route("[controller]")]
12+
public class WeatherForecastController : ControllerBase
13+
{
14+
private static readonly string[] Summaries = new[]
15+
{
16+
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
17+
};
18+
19+
private readonly ILogger<WeatherForecastController> _logger;
20+
21+
public WeatherForecastController(ILogger<WeatherForecastController> logger)
22+
{
23+
_logger = logger;
24+
}
25+
26+
[HttpGet]
27+
public IEnumerable<WeatherForecast> Get()
28+
{
29+
var rng = new Random();
30+
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
31+
{
32+
Date = DateTime.Now.AddDays(index),
33+
TemperatureC = rng.Next(-20, 55),
34+
Summary = Summaries[rng.Next(Summaries.Length)]
35+
})
36+
.ToArray();
37+
}
38+
}
39+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net5.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
9+
</ItemGroup>
10+
11+
</Project>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Hosting;
6+
using Microsoft.Extensions.Configuration;
7+
using Microsoft.Extensions.Hosting;
8+
using Microsoft.Extensions.Logging;
9+
10+
namespace FirstApi
11+
{
12+
public class Program
13+
{
14+
public static void Main(string[] args)
15+
{
16+
CreateHostBuilder(args).Build().Run();
17+
}
18+
19+
public static IHostBuilder CreateHostBuilder(string[] args) =>
20+
Host.CreateDefaultBuilder(args)
21+
.ConfigureWebHostDefaults(webBuilder =>
22+
{
23+
webBuilder.UseStartup<Startup>();
24+
});
25+
}
26+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"$schema": "http://json.schemastore.org/launchsettings.json",
3+
"iisSettings": {
4+
"windowsAuthentication": false,
5+
"anonymousAuthentication": true,
6+
"iisExpress": {
7+
"applicationUrl": "http://localhost:40344",
8+
"sslPort": 44372
9+
}
10+
},
11+
"profiles": {
12+
"IIS Express": {
13+
"commandName": "IISExpress",
14+
"launchBrowser": true,
15+
"launchUrl": "swagger",
16+
"environmentVariables": {
17+
"ASPNETCORE_ENVIRONMENT": "Development"
18+
}
19+
},
20+
"FirstApi": {
21+
"commandName": "Project",
22+
"dotnetRunMessages": "true",
23+
"launchBrowser": true,
24+
"launchUrl": "swagger",
25+
"applicationUrl": "https://localhost:5001;http://localhost:5000",
26+
"environmentVariables": {
27+
"ASPNETCORE_ENVIRONMENT": "Development"
28+
}
29+
}
30+
}
31+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Builder;
6+
using Microsoft.AspNetCore.Hosting;
7+
using Microsoft.AspNetCore.HttpsPolicy;
8+
using Microsoft.AspNetCore.Mvc;
9+
using Microsoft.Extensions.Configuration;
10+
using Microsoft.Extensions.DependencyInjection;
11+
using Microsoft.Extensions.Hosting;
12+
using Microsoft.Extensions.Logging;
13+
using Microsoft.OpenApi.Models;
14+
15+
namespace FirstApi
16+
{
17+
public class Startup
18+
{
19+
public Startup(IConfiguration configuration)
20+
{
21+
Configuration = configuration;
22+
}
23+
24+
public IConfiguration Configuration { get; }
25+
26+
// This method gets called by the runtime. Use this method to add services to the container.
27+
public void ConfigureServices(IServiceCollection services)
28+
{
29+
30+
services.AddControllers();
31+
services.AddSwaggerGen(c =>
32+
{
33+
c.SwaggerDoc("v1", new OpenApiInfo { Title = "FirstApi", Version = "v1" });
34+
});
35+
}
36+
37+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
38+
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
39+
{
40+
if (env.IsDevelopment())
41+
{
42+
app.UseDeveloperExceptionPage();
43+
app.UseSwagger();
44+
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "FirstApi v1"));
45+
}
46+
47+
app.UseHttpsRedirection();
48+
49+
app.UseRouting();
50+
51+
app.UseAuthorization();
52+
53+
app.UseEndpoints(endpoints =>
54+
{
55+
endpoints.MapControllers();
56+
});
57+
}
58+
}
59+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace FirstApi
4+
{
5+
public class WeatherForecast
6+
{
7+
public DateTime Date { get; set; }
8+
9+
public int TemperatureC { get; set; }
10+
11+
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
12+
13+
public string Summary { get; set; }
14+
}
15+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
}
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft": "Warning",
6+
"Microsoft.Hosting.Lifetime": "Information"
7+
}
8+
},
9+
"AllowedHosts": "*"
10+
}

0 commit comments

Comments
 (0)