Skip to content

Commit 5865b4c

Browse files
committed
feat: Upgrade project to .NET 10.0
1 parent a1185b3 commit 5865b4c

File tree

7 files changed

+46
-46
lines changed

7 files changed

+46
-46
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- name: Setup .NET
2323
uses: actions/setup-dotnet@v5
2424
with:
25-
dotnet-version: 8.0.x
25+
dotnet-version: 10.0.x
2626

2727
- uses: pnpm/action-setup@v4
2828
name: Install pnpm

BUILDING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Building
22

3-
Git Clone, open the folder in VSCode and install dependencies when prompted. You will need to install the .NET SDK 8.0 and Node.js 20. Install pnpm globally using `npm install -g pnpm` then type into the terminal:
3+
Git Clone, open the folder in VSCode and install dependencies when prompted. You will need to install the .NET SDK 10.0 and Node.js 20. Install pnpm globally using `npm install -g pnpm` then type into the terminal:
44

55
`dotnet watch --project src`
66

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
66

77
ESPresense-companion is a Home Assistant Add-on / Docker container that processes indoor position data from ESPresense BLE nodes. It's a full-stack application with:
88

9-
- **Backend**: ASP.NET Core (.NET 8.0) with C# providing REST APIs, WebSocket communication, and MQTT integration
9+
- **Backend**: ASP.NET Core (.NET 10.0) with C# providing REST APIs, WebSocket communication, and MQTT integration
1010
- **Frontend**: SvelteKit 5 with TypeScript providing a reactive web interface for device visualization and management
1111
- **Database**: SQLite for storing historical data and device settings
1212
- **Communication**: MQTT for node communication, WebSockets for real-time UI updates
@@ -59,7 +59,7 @@ pnpm check
5959
```
6060

6161
### Development Setup
62-
1. Install .NET SDK 8.0 and Node.js 20
62+
1. Install .NET SDK 10.0 and Node.js 20
6363
2. Install pnpm globally: `npm install -g pnpm`
6464
3. Run `dotnet watch --project src` (serves backend on port 5279)
6565
4. During development, Vite dev server proxies `/api` and `/ws` requests to the .NET backend

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Build stage
2-
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
2+
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0 AS build-env
33
ARG TARGETPLATFORM
44
ARG BUILDPLATFORM
55

@@ -24,7 +24,7 @@ RUN dotnet restore
2424
RUN dotnet publish -c Release -o out
2525

2626
# Runtime stage
27-
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
27+
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
2828
WORKDIR /App
2929
EXPOSE 8267 8268
3030

src/ESPresense.Companion.csproj

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net10.0</TargetFramework>
55
<RuntimeIdentifiers>linux</RuntimeIdentifiers>
66
<Nullable>enable</Nullable>
77
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
@@ -22,12 +22,11 @@
2222
<PackageReference Include="DotNet.Glob" Version="3.1.3" />
2323
<PackageReference Include="Flurl.Http.Newtonsoft" Version="0.9.1" />
2424
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
25-
<PackageReference Include="MathNet.Filtering" Version="0.7.0" />
26-
<PackageReference Include="MathNet.Filtering.Kalman" Version="0.7.0" />
2725
<PackageReference Include="MathNet.Spatial" Version="0.6.0" />
28-
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="8.0.22" />
26+
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="10.0.1" />
2927
<PackageReference Include="ModelContextProtocol.AspNetCore" Version="0.4.0-preview.3" />
3028
<PackageReference Include="MQTTnet" Version="5.0.1.1416" />
29+
<PackageReference Include="MQTTnet.Extensions.ManagedClient" Version="4.3.7.1207" />
3130
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
3231
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
3332
<PackageReference Include="Polly" Version="8.6.5" />

src/Program.cs

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,32 @@
2323

2424
FlurlHttp.Clients.UseNewtonsoft();
2525

26-
builder.Host.UseSerilog((context, cfg) => cfg.ReadFrom.Configuration(context.Configuration));
26+
builder.Host.UseSerilog((ctx, cfg) => cfg.ReadFrom.Configuration(ctx.Configuration));
2727

2828
Log.Logger.Information(MathNet.Numerics.Control.Describe().Trim('\r', '\n'));
2929

30-
var configDir = Environment.GetEnvironmentVariable("CONFIG_DIR") ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".espresense");
30+
var configDir = Environment.GetEnvironmentVariable("CONFIG_DIR")
31+
?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".espresense");
3132
var storageDir = Path.Combine(configDir, ".storage");
3233
Directory.CreateDirectory(storageDir);
3334

3435
var configLoader = new ConfigLoader(configDir);
35-
36-
builder.Services.AddSingleton(a => configLoader);
37-
builder.Services.AddHostedService(a => configLoader);
36+
builder.Services.AddSingleton(_ => configLoader);
37+
builder.Services.AddHostedService(_ => configLoader);
3838

3939
builder.Services.AddDataProtection()
40-
.UseEphemeralDataProtectionProvider();
40+
.PersistKeysToFileSystem(new DirectoryInfo(Path.Combine(storageDir, "keys")));
4141

42-
builder.Services.AddSingleton(a =>
42+
builder.Services.AddSingleton(_ =>
4343
{
4444
SQLitePCL.Batteries.Init();
45-
var databasePath = Path.Combine(storageDir, "history.db");
46-
Directory.CreateDirectory(Path.GetDirectoryName(databasePath) ?? throw new InvalidOperationException("HOME not found"));
47-
var sqLiteConnection = new SQLiteAsyncConnection(databasePath)
45+
var dbPath = Path.Combine(storageDir, "history.db");
46+
Directory.CreateDirectory(Path.GetDirectoryName(dbPath)!);
47+
return new SQLiteAsyncConnection(dbPath)
4848
{
4949
Trace = true,
5050
Tracer = Log.Debug
5151
};
52-
53-
return sqLiteConnection;
5452
});
5553

5654
builder.Services.AddAutoMapper(cfg =>
@@ -60,9 +58,9 @@
6058

6159
builder.Services.AddSingleton<HttpClient>();
6260
builder.Services.AddSingleton<DatabaseFactory>();
63-
builder.Services.AddSingleton<IMqttNetLogger>(a => new MqttNetLogger());
61+
builder.Services.AddSingleton<IMqttNetLogger>(_ => new MqttNetLogger());
6462
builder.Services.AddSingleton<MqttCoordinator>();
65-
builder.Services.AddSingleton<IMqttCoordinator>(provider => provider.GetRequiredService<MqttCoordinator>());
63+
builder.Services.AddSingleton<IMqttCoordinator>(p => p.GetRequiredService<MqttCoordinator>());
6664
builder.Services.AddSingleton<TelemetryService>();
6765
builder.Services.AddSingleton<GlobalEventDispatcher>();
6866
builder.Services.AddSingleton<DeviceTracker>();
@@ -78,11 +76,11 @@
7876

7977
builder.Services.AddHostedService<MultiScenarioLocator>();
8078
builder.Services.AddHostedService<OptimizationRunner>();
81-
builder.Services.AddHostedService(provider => provider.GetRequiredService<DeviceTracker>());
82-
builder.Services.AddHostedService(provider => provider.GetRequiredService<DeviceSettingsStore>());
83-
builder.Services.AddHostedService(provider => provider.GetRequiredService<NodeSettingsStore>());
84-
builder.Services.AddHostedService(provider => provider.GetRequiredService<NodeTelemetryStore>());
85-
builder.Services.AddHostedService(provider => provider.GetRequiredService<TelemetryService>());
79+
builder.Services.AddHostedService(p => p.GetRequiredService<DeviceTracker>());
80+
builder.Services.AddHostedService(p => p.GetRequiredService<DeviceSettingsStore>());
81+
builder.Services.AddHostedService(p => p.GetRequiredService<NodeSettingsStore>());
82+
builder.Services.AddHostedService(p => p.GetRequiredService<NodeTelemetryStore>());
83+
builder.Services.AddHostedService(p => p.GetRequiredService<TelemetryService>());
8684
builder.Services.AddHostedService<DeviceCleanupService>();
8785
builder.Services.AddSingleton<State>();
8886
builder.Services.AddControllersWithViews().AddJsonOptions(opt =>
@@ -103,27 +101,30 @@
103101

104102
var app = builder.Build();
105103

106-
app.UseWebSockets(new WebSocketOptions
107-
{
108-
KeepAliveInterval = TimeSpan.FromMinutes(15)
109-
});
104+
app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = TimeSpan.FromMinutes(15) });
110105

111106
app.UseSerilogRequestLogging(o =>
112107
{
113-
o.EnrichDiagnosticContext = (dc, ctx) => dc.Set("UserAgent", ctx?.Request.Headers.UserAgent);
114-
o.GetLevel = (ctx, ms, ex) => ex != null ? LogEventLevel.Error : ctx.Response.StatusCode > 499 ? LogEventLevel.Error : ms > 500 ? LogEventLevel.Warning : ctx.Request.Path.Value.IndexOf("/state", StringComparison.OrdinalIgnoreCase) > 0 ? LogEventLevel.Verbose : LogEventLevel.Debug;
108+
o.EnrichDiagnosticContext = (dc, ctx) => dc.Set("UserAgent", ctx.Request.Headers.UserAgent);
109+
o.GetLevel = (ctx, elapsedMs, ex) =>
110+
ex != null ? LogEventLevel.Error :
111+
ctx.Response.StatusCode > 499 ? LogEventLevel.Error :
112+
elapsedMs > 500 ? LogEventLevel.Warning :
113+
ctx.Request.Path.Value?.Contains("/state", StringComparison.OrdinalIgnoreCase) == true
114+
? LogEventLevel.Verbose
115+
: LogEventLevel.Debug;
115116
});
116117

117118
app.UseSwagger(c => c.RouteTemplate = "api/swagger/{documentName}/swagger.{json|yaml}");
118-
app.UseSwaggerUI(c => c.RoutePrefix = "api/swagger");
119+
app.UseSwaggerUI(c =>
120+
{
121+
c.SwaggerEndpoint("/api/swagger/v1/swagger.json", "v1");
122+
c.RoutePrefix = "api/swagger";
123+
});
119124

120-
app.UseStaticFiles();
121-
app.UseRouting();
125+
app.MapStaticAssets();
122126
app.MapMcp("/api/mcp");
123-
124-
app.MapControllerRoute(
125-
name: "default",
126-
pattern: "{controller}/{action=Index}/{id?}");
127+
app.MapControllers();
127128

128129
app.MapFallbackToFile("index.html");
129130

tests/ESPresense.Companion.Tests.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net10.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77

@@ -12,9 +12,9 @@
1212

1313
<ItemGroup>
1414
<PackageReference Include="AutoMapper" Version="16.0.0" />
15-
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
16-
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
17-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
15+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" />
16+
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.0" />
17+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
1818
<PackageReference Include="NUnit" Version="3.13.3" />
1919
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
2020
<PackageReference Include="NUnit.Analyzers" Version="3.6.1" />

0 commit comments

Comments
 (0)