Skip to content

Commit 224e620

Browse files
authored
Add Call web API sample 10.0 (#539)
1 parent 460f39d commit 224e620

File tree

100 files changed

+64364
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+64364
-1
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<InvariantGlobalization>true</InvariantGlobalization>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.0-preview.4.25258.107" />
12+
<PackageReference Include="Microsoft.AspNetCore.JsonPatch.SystemTextJson" Version="10.0.0-preview.4.25258.110" />
13+
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.0-preview.4.25258.107" />
14+
<PackageReference Include="NSwag.AspNetCore" Version="14.1.0" />
15+
</ItemGroup>
16+
17+
</Project>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
@Backend_HostAddress = https://localhost:7212
2+
3+
GET {{Backend_HostAddress}}/todoitems/
4+
Accept: application/json
5+
6+
###
7+
8+
GET {{Backend_HostAddress}}/todoitems/complete
9+
Accept: application/json
10+
11+
###
12+
13+
GET {{Backend_HostAddress}}/todoitems/incomplete
14+
Accept: application/json
15+
16+
###
17+
18+
GET {{Backend_HostAddress}}/todoitems/2
19+
20+
###
21+
22+
PATCH {{Backend_HostAddress}}/todoitems/2
23+
Content-Type: application/json
24+
25+
{
26+
"operationType": 2,
27+
"path": "/IsComplete",
28+
"op": "replace",
29+
"value": true
30+
}
31+
32+
###
33+
34+
Post {{Backend_HostAddress}}/todoitems
35+
Content-Type: application/json
36+
37+
{
38+
"name": "Test drive Jeep CJ",
39+
"isComplete": false
40+
}
41+
42+
###
43+
44+
Put {{Backend_HostAddress}}/todoitems/1
45+
Content-Type: application/json
46+
47+
{
48+
"id": 1,
49+
"name": "Make coffee",
50+
"isComplete": true
51+
}
52+
53+
###
54+
55+
DELETE {{Backend_HostAddress}}/todoitems/4
56+
57+
###
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using Microsoft.EntityFrameworkCore;
2+
3+
namespace Backend.Models;
4+
5+
public class TodoContext(DbContextOptions<TodoContext> options) : DbContext(options)
6+
{
7+
public DbSet<TodoItem> TodoItems { get; set; } = null!;
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Backend.Models;
2+
3+
public sealed class TodoItem
4+
{
5+
public long Id { get; set; }
6+
public string? Name { get; set; }
7+
public bool IsComplete { get; set; }
8+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
using Microsoft.AspNetCore.JsonPatch.SystemTextJson;
2+
using Microsoft.EntityFrameworkCore;
3+
using Backend;
4+
using Backend.Models;
5+
6+
var builder = WebApplication.CreateBuilder(args);
7+
8+
// Add the database (in memory for the sample)
9+
builder.Services.AddDbContext<TodoContext>(opt => opt.UseInMemoryDatabase("TodoList"));
10+
11+
// Add a CORS policy for the client
12+
// Add .AllowCredentials() for apps that use an Identity Provider for authn/z
13+
builder.Services.AddCors(
14+
options => options.AddDefaultPolicy(
15+
policy => policy.WithOrigins([builder.Configuration["BackendUrl"] ?? "https://localhost:5001",
16+
builder.Configuration["FrontendUrl"] ?? "https://localhost:5002"])
17+
.AllowAnyMethod()
18+
.AllowAnyHeader()));
19+
20+
// Add services to the container
21+
builder.Services.AddEndpointsApiExplorer();
22+
23+
// Add NSwag services
24+
builder.Services.AddOpenApiDocument();
25+
26+
var app = builder.Build();
27+
28+
if (builder.Environment.IsDevelopment())
29+
{
30+
// Seed the database
31+
await using var scope = app.Services.CreateAsyncScope();
32+
await SeedData.InitializeAsync(scope.ServiceProvider);
33+
34+
// Add OpenAPI/Swagger generator and the Swagger UI
35+
app.UseOpenApi();
36+
app.UseSwaggerUi();
37+
}
38+
39+
// Activate the CORS policy
40+
app.UseCors();
41+
42+
app.UseHttpsRedirection();
43+
44+
// Set up API endpoints and methods
45+
var todoItems = app.MapGroup("/todoitems");
46+
47+
todoItems.MapGet("/", GetAllTodos);
48+
todoItems.MapGet("/complete", GetCompleteTodos);
49+
todoItems.MapGet("/incomplete", GetIncompleteTodos);
50+
todoItems.MapGet("/{id}", GetTodo);
51+
todoItems.MapPost("/", CreateTodo);
52+
todoItems.MapPut("/{id}", UpdateTodo);
53+
todoItems.MapDelete("/{id}", DeleteTodo);
54+
todoItems.MapPatch("/{id}", PatchTodo);
55+
56+
app.Run();
57+
58+
static async Task<IResult> GetAllTodos(TodoContext db)
59+
{
60+
return TypedResults.Ok(await db.TodoItems.ToArrayAsync());
61+
}
62+
63+
static async Task<IResult> GetCompleteTodos(TodoContext db)
64+
{
65+
return TypedResults.Ok(await db.TodoItems.Where(t => t.IsComplete).ToListAsync());
66+
}
67+
68+
static async Task<IResult> GetIncompleteTodos(TodoContext db)
69+
{
70+
return TypedResults.Ok(await db.TodoItems.Where(t => !t.IsComplete).ToListAsync());
71+
}
72+
73+
static async Task<IResult> GetTodo(long id, TodoContext db)
74+
{
75+
return await db.TodoItems.FindAsync(id) is TodoItem todo ? TypedResults.Ok(todo) : TypedResults.NotFound();
76+
}
77+
78+
static async Task<IResult> CreateTodo(TodoItem todo, TodoContext db)
79+
{
80+
db.TodoItems.Add(todo);
81+
await db.SaveChangesAsync();
82+
83+
return TypedResults.Created($"/todoitems/{todo.Id}", todo);
84+
}
85+
86+
static async Task<IResult> UpdateTodo(long id, TodoItem inputTodo, TodoContext db)
87+
{
88+
var todo = await db.TodoItems.FindAsync(id);
89+
90+
if (todo is null)
91+
{
92+
return TypedResults.NotFound();
93+
}
94+
95+
todo.Name = inputTodo.Name;
96+
todo.IsComplete = inputTodo.IsComplete;
97+
98+
await db.SaveChangesAsync();
99+
100+
return TypedResults.NoContent();
101+
}
102+
103+
static async Task<IResult> DeleteTodo(long id, TodoContext db)
104+
{
105+
if (await db.TodoItems.FindAsync(id) is TodoItem todo)
106+
{
107+
db.TodoItems.Remove(todo);
108+
await db.SaveChangesAsync();
109+
110+
return TypedResults.NoContent();
111+
}
112+
113+
return TypedResults.NotFound();
114+
}
115+
116+
static async Task<IResult> PatchTodo(long id, TodoContext db)
117+
{
118+
if (await db.TodoItems.FindAsync(id) is TodoItem todo)
119+
{
120+
var patchDocument = new JsonPatchDocument<TodoItem>().Replace(p => p.IsComplete, true);
121+
patchDocument.ApplyTo(todo);
122+
await db.SaveChangesAsync();
123+
124+
return TypedResults.Ok(todo);
125+
}
126+
127+
return TypedResults.NoContent();
128+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"$schema": "http://json.schemastore.org/launchsettings.json",
3+
"iisSettings": {
4+
"windowsAuthentication": false,
5+
"anonymousAuthentication": true,
6+
"iisExpress": {
7+
"applicationUrl": "http://localhost:27123",
8+
"sslPort": 44394
9+
}
10+
},
11+
"profiles": {
12+
"http": {
13+
"commandName": "Project",
14+
"dotnetRunMessages": true,
15+
"launchBrowser": true,
16+
"launchUrl": "swagger",
17+
"applicationUrl": "http://localhost:5266",
18+
"environmentVariables": {
19+
"ASPNETCORE_ENVIRONMENT": "Development"
20+
}
21+
},
22+
"https": {
23+
"commandName": "Project",
24+
"dotnetRunMessages": true,
25+
"launchBrowser": true,
26+
"launchUrl": "swagger",
27+
"applicationUrl": "https://localhost:7212;http://localhost:5266",
28+
"environmentVariables": {
29+
"ASPNETCORE_ENVIRONMENT": "Development"
30+
}
31+
},
32+
"IIS Express": {
33+
"commandName": "IISExpress",
34+
"launchBrowser": true,
35+
"launchUrl": "swagger",
36+
"environmentVariables": {
37+
"ASPNETCORE_ENVIRONMENT": "Development"
38+
}
39+
}
40+
}
41+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Backend.Models;
3+
4+
namespace Backend;
5+
6+
public class SeedData
7+
{
8+
public static async Task InitializeAsync(IServiceProvider serviceProvider)
9+
{
10+
using var context = new TodoContext(serviceProvider.GetRequiredService<DbContextOptions<TodoContext>>());
11+
12+
context.Add(new TodoItem { Name = "Lift weights", IsComplete = true });
13+
context.Add(new TodoItem { Name = "Feed Merlin", IsComplete = false });
14+
context.Add(new TodoItem { Name = "Update web API article", IsComplete = true });
15+
context.Add(new TodoItem { Name = "Attend Blazor party", IsComplete = false });
16+
17+
await context.SaveChangesAsync();
18+
}
19+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
}
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
},
8+
"AllowedHosts": "*",
9+
"BackendUrl": "https://localhost:7212",
10+
"FrontendUrl": "https://localhost:7172"
11+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.10.34607.79
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Backend", "Backend\Backend.csproj", "{DAFFE81D-7A08-40E0-9E14-E4F2E6D6F705}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorApp", "BlazorApp\BlazorApp\BlazorApp.csproj", "{C349B9FD-D74D-407F-BAF9-739A2D02D45F}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorApp.Client", "BlazorApp\BlazorApp.Client\BlazorApp.Client.csproj", "{17AC0B37-E294-4E83-B2D8-D6ECD8F83897}"
11+
EndProject
12+
Global
13+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
14+
Debug|Any CPU = Debug|Any CPU
15+
Release|Any CPU = Release|Any CPU
16+
EndGlobalSection
17+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
18+
{DAFFE81D-7A08-40E0-9E14-E4F2E6D6F705}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19+
{DAFFE81D-7A08-40E0-9E14-E4F2E6D6F705}.Debug|Any CPU.Build.0 = Debug|Any CPU
20+
{DAFFE81D-7A08-40E0-9E14-E4F2E6D6F705}.Release|Any CPU.ActiveCfg = Release|Any CPU
21+
{DAFFE81D-7A08-40E0-9E14-E4F2E6D6F705}.Release|Any CPU.Build.0 = Release|Any CPU
22+
{C349B9FD-D74D-407F-BAF9-739A2D02D45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23+
{C349B9FD-D74D-407F-BAF9-739A2D02D45F}.Debug|Any CPU.Build.0 = Debug|Any CPU
24+
{C349B9FD-D74D-407F-BAF9-739A2D02D45F}.Release|Any CPU.ActiveCfg = Release|Any CPU
25+
{C349B9FD-D74D-407F-BAF9-739A2D02D45F}.Release|Any CPU.Build.0 = Release|Any CPU
26+
{17AC0B37-E294-4E83-B2D8-D6ECD8F83897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27+
{17AC0B37-E294-4E83-B2D8-D6ECD8F83897}.Debug|Any CPU.Build.0 = Debug|Any CPU
28+
{17AC0B37-E294-4E83-B2D8-D6ECD8F83897}.Release|Any CPU.ActiveCfg = Release|Any CPU
29+
{17AC0B37-E294-4E83-B2D8-D6ECD8F83897}.Release|Any CPU.Build.0 = Release|Any CPU
30+
EndGlobalSection
31+
GlobalSection(SolutionProperties) = preSolution
32+
HideSolutionNode = FALSE
33+
EndGlobalSection
34+
GlobalSection(ExtensibilityGlobals) = postSolution
35+
SolutionGuid = {18AAE385-F8E7-4FFC-933F-26E8C6CB3528}
36+
EndGlobalSection
37+
EndGlobal
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[
2+
{
3+
"Name": "Start Solution",
4+
"Projects": [
5+
{
6+
"Path": "Backend\\Backend.csproj",
7+
"Action": "StartWithoutDebugging",
8+
"DebugTarget": "https"
9+
},
10+
{
11+
"Path": "BlazorApp\\BlazorApp\\BlazorApp.csproj",
12+
"Action": "Start",
13+
"DebugTarget": "https"
14+
}
15+
]
16+
}
17+
]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
8+
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.0-preview.4.25258.107" />
13+
<PackageReference Include="Microsoft.AspNetCore.JsonPatch.SystemTextJson" Version="10.0.0-preview.4.25258.110" />
14+
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0-preview.4.25258.107" />
15+
</ItemGroup>
16+
17+
</Project>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace BlazorApp.Client.Models;
2+
3+
public sealed class Movie
4+
{
5+
public long Id { get; set; }
6+
public string? Name { get; set; }
7+
public bool IsWatched { get; set; }
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace BlazorApp.Client.Models;
2+
3+
public sealed class TodoItem
4+
{
5+
public long Id { get; set; }
6+
public string? Name { get; set; }
7+
public bool IsComplete { get; set; }
8+
}

0 commit comments

Comments
 (0)