Update project to .NET 10.0 and upgrade dependencies in Dockerfile and project files

This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-03-09 22:27:48 +02:00
parent 1739a2b120
commit 44e75afc4f
7 changed files with 82 additions and 51 deletions
+3 -4
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
@@ -9,14 +9,13 @@
<ItemGroup>
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8"/>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.3" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.4"/>
</ItemGroup>
<ItemGroup>
+20 -26
View File
@@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Serilog;
Log.Logger = new LoggerConfiguration()
@@ -79,19 +79,13 @@ builder.Services.AddSwaggerGen(c =>
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Description = "Put **_ONLY_** your JWT Bearer token on textbox below!",
Reference = new OpenApiReference
{
Id = JwtBearerDefaults.AuthenticationScheme,
Type = ReferenceType.SecurityScheme
}
};
c.AddSecurityDefinition(jwtSecurityScheme.Reference.Id, jwtSecurityScheme);
c.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, jwtSecurityScheme);
c.AddSecurityRequirement(new OpenApiSecurityRequirement
c.AddSecurityRequirement(_ => new OpenApiSecurityRequirement
{
{ jwtSecurityScheme, Array.Empty<string>() }
{ new OpenApiSecuritySchemeReference(JwtBearerDefaults.AuthenticationScheme, null), new List<string>() }
});
});
builder.Services.Configure<ResourcesConfig>(builder.Configuration.GetSection(nameof(ResourcesConfig)));
@@ -142,75 +136,75 @@ app.MapPost("/login",
var user = await userService.ValidateUser(request, ct: cancellationToken);
return Results.Ok(new { Token = authService.CreateToken(user)});
})
.WithOpenApi(op => new(op){ Summary = "Login"});;
.WithSummary("Login");
app.MapPost("/users",
async (RegisterUserRequest registerUserRequest, IUserService userService, CancellationToken cancellationToken)
=> await userService.RegisterUser(registerUserRequest, cancellationToken))
.RequireAuthorization(apiAdminPolicy)
.WithOpenApi(op => new(op){ Summary = "Creates a new user"});
.WithSummary("Creates a new user");
app.MapGet("/users/current",
async (IAuthService authService) => await authService.GetCurrentUser())
.RequireAuthorization()
.WithOpenApi(op => new(op){ Summary = "Get Current User"});
.WithSummary("Get Current User");
app.MapGet("/users",
async (string? searchEmail, RoleEnum? searchRole, IUserService userService, CancellationToken ct)
=> await userService.GetUsers(searchEmail, searchRole, ct))
.RequireAuthorization(apiAdminPolicy)
.WithOpenApi(op => new(op){ Summary = "List users by criteria"});
.WithSummary("List users by criteria");
app.MapPut("/users/hardware/set",
async ([FromBody]SetHWRequest request, IUserService userService, ICache cache, CancellationToken ct) =>
await userService.UpdateHardware(request.Email, request.Hardware, ct: ct))
.RequireAuthorization(apiAdminPolicy)
.WithOpenApi(op => new OpenApiOperation(op){ Summary = "Sets user's hardware"});
.WithSummary("Sets user's hardware");
app.MapPut("/users/queue-offsets/set",
async ([FromBody]SetUserQueueOffsetsRequest request, IUserService userService, CancellationToken ct)
=> await userService.UpdateQueueOffsets(request.Email, request.Offsets, ct))
.RequireAuthorization()
.WithOpenApi(op => new OpenApiOperation(op) { Summary = "Sets user's queue offsets" });
.WithSummary("Sets user's queue offsets");
app.MapPut("/users/{email}/set-role/{role}", async (string email, RoleEnum role, IUserService userService, CancellationToken ct)
=> await userService.ChangeRole(email, role, ct))
.RequireAuthorization(apiAdminPolicy)
.WithOpenApi(op => new OpenApiOperation(op) { Summary = "Set user's role" });
.WithSummary("Set user's role");
app.MapPut("/users/{email}/enable", async (string email, IUserService userService, CancellationToken ct)
=> await userService.SetEnableStatus(email, true, ct))
.RequireAuthorization(apiAdminPolicy)
.WithOpenApi(op => new OpenApiOperation(op) { Summary = "Disable user" });
.WithSummary("Enable user");
app.MapPut("/users/{email}/disable", async (string email, IUserService userService, CancellationToken ct)
=> await userService.SetEnableStatus(email, false, ct))
.RequireAuthorization(apiAdminPolicy)
.WithOpenApi(op => new OpenApiOperation(op) { Summary = "Disable user" });
.WithSummary("Disable user");
app.MapDelete("/users/{email}", async (string email, IUserService userService, CancellationToken ct)
=> await userService.RemoveUser(email, ct))
.RequireAuthorization(apiAdminPolicy)
.WithOpenApi(op => new OpenApiOperation(op) { Summary = "Remove user" });
.WithSummary("Remove user");
app.MapPost("/resources/{dataFolder?}",
async ([FromRoute]string? dataFolder, IFormFile data, IResourcesService resourceService, CancellationToken ct)
=> await resourceService.SaveResource(dataFolder, data, ct))
.Accepts<IFormFile>("multipart/form-data")
.RequireAuthorization()
//.WithOpenApi(op => new(op){ Summary = "Upload resource"}); //For some reason doesn't work when this is specified.
.WithSummary("Upload resource")
.DisableAntiforgery();
app.MapGet("/resources/list/{dataFolder?}",
async ([FromRoute]string? dataFolder, string? search, IResourcesService resourcesService, CancellationToken ct)
=> await resourcesService.ListResources(dataFolder, search, ct))
.RequireAuthorization()
.WithOpenApi(op => new OpenApiOperation(op) { Summary = "Lists resources in folder" });
.WithSummary("Lists resources in folder");
app.MapPost("/resources/clear/{dataFolder?}",
([FromRoute]string? dataFolder, IResourcesService resourcesService) => resourcesService.ClearFolder(dataFolder))
.RequireAuthorization(apiAdminPolicy)
.WithOpenApi(op => new OpenApiOperation(op) { Summary = "Clear folder" });
.WithSummary("Clear folder");
app.MapPost("/resources/get/{dataFolder?}", //Need to have POST method for secure password
async ([FromBody]GetResourceRequest request, [FromRoute]string? dataFolder, IAuthService authService,
@@ -227,7 +221,7 @@ app.MapPost("/resources/get/{dataFolder?}", //Need to have POST method for secur
return Results.File(stream, "application/octet-stream", request.FileName);
}).RequireAuthorization()
.WithOpenApi(op => new OpenApiOperation(op){ Summary = "Gets encrypted by users Password and HardwareHash resources. POST method for secure password"});
.WithSummary("Gets encrypted by users Password and HardwareHash resources. POST method for secure password");
app.MapGet("/resources/get-installer",
async (IAuthService authService, IResourcesService resourcesService, CancellationToken ct) =>
@@ -240,7 +234,7 @@ app.MapGet("/resources/get-installer",
throw new FileNotFoundException("Installer file was not found!");
return Results.File(stream, "application/octet-stream", name);
}).RequireAuthorization()
.WithOpenApi(op => new OpenApiOperation(op) { Summary = "Gets latest installer" });
.WithSummary("Gets latest installer");
app.MapGet("/resources/get-installer/stage",
async (IAuthService authService, IResourcesService resourcesService, CancellationToken ct) =>
@@ -253,7 +247,7 @@ app.MapGet("/resources/get-installer/stage",
throw new FileNotFoundException("Installer file was not found!");
return Results.File(stream, "application/octet-stream", name);
}).RequireAuthorization()
.WithOpenApi(op => new OpenApiOperation(op) { Summary = "Gets latest installer" });
.WithSummary("Gets latest installer");
app.MapPost("/resources/check",
+4 -7
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
@@ -9,15 +9,12 @@
<ItemGroup>
<PackageReference Include="FluentValidation" Version="11.10.0" />
<PackageReference Include="linq2db" Version="5.4.1" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Npgsql" Version="8.0.5" />
<PackageReference Include="Npgsql" Version="10.0.1" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Extensions.Options">
<HintPath>C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.8\Microsoft.Extensions.Options.dll</HintPath>
</Reference>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
</Project>
+3 -10
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
@@ -11,18 +11,11 @@
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Http.Abstractions">
<HintPath>C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.8\Microsoft.AspNetCore.Http.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Features" />
<Reference Include="Microsoft.Extensions.Options">
<HintPath>C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.8\Microsoft.Extensions.Options.dll</HintPath>
</Reference>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="LazyCache.AspNetCore" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
</ItemGroup>
+2 -2
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
+2 -2
View File
@@ -1,9 +1,9 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 8080
# Build whole app
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /app
COPY . .
+48
View File
@@ -0,0 +1,48 @@
#!/bin/sh
apt install -y docker.io apache2-utils nginx
# install cloudflared
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb
dpkg -i cloudflared.deb
rm cloudflared.deb
docker run -d -p 5000:5000 --name registry --restart always registry:latest
cd /etc/nginx
mkdir -p auth
cd auth
htpasswd -c .htpasswd zxsanny
chmod 640 .htpasswd
chown root:www-data .htpasswd
cd /etc/nginx/sites-available
tee docker-registry << 'END'
server {
listen 80;
server_name _;
client_max_body_size 900M;
location / {
auth_basic "Registry";
auth_basic_user_file /etc/nginx/auth/.htpasswd;
proxy_pass http://localhost:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
END
ln -sf /etc/nginx/sites-available/docker-registry /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl restart nginx
# start tunnel — prints a *.trycloudflare.com URL
cloudflared tunnel --url http://localhost:80
# then from another machine:
# docker login <printed-trycloudflare-url>
# enter username: zxsanny and the password set above