diff --git a/.github/workflows/fw-lite.yaml b/.github/workflows/fw-lite.yaml
index 8a49a2dd42..04a2772b64 100644
--- a/.github/workflows/fw-lite.yaml
+++ b/.github/workflows/fw-lite.yaml
@@ -50,7 +50,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- name: Cache NuGet packages
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
@@ -123,7 +123,7 @@ jobs:
submodules: true
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- name: Dotnet build (Release)
run: dotnet build backend/FwLite/FwLiteProjectSync.Tests/FwLiteProjectSync.Tests.csproj -c Release
@@ -300,7 +300,7 @@ jobs:
path: ${{ env.VIEWER_BUILD_OUTPUT_DIR }}
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- name: Dotnet build
working-directory: backend/FwLite/FwLiteWeb
@@ -335,7 +335,7 @@ jobs:
path: ${{ env.VIEWER_BUILD_OUTPUT_DIR }}
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- name: Publish Linux
working-directory: backend/FwLite/FwLiteWeb
@@ -383,7 +383,7 @@ jobs:
path: ${{ env.VIEWER_BUILD_OUTPUT_DIR }}
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- name: Setup Maui
run: dotnet workload install maui-android
@@ -404,7 +404,7 @@ jobs:
KEYSTORE_PASS: ${{ secrets.FW_LITE_KEYSTORE_PASS }}
KEYSTORE_ALIAS: ${{ vars.FW_LITE_KEYSTORE_UPLOAD_KEY_ALIAS }}
run: |
- dotnet publish -f net10.0-android -p:BuildApple=false --artifacts-path ../artifacts \
+ dotnet publish -f net11.0-android -p:BuildApple=false --artifacts-path ../artifacts \
-p:ApplicationDisplayVersion=${{ needs.build-and-test.outputs.semver-version }} \
-p:ApplicationVersion=${{ github.run_number }} \
-p:InformationalVersion=${{ needs.build-and-test.outputs.version }} \
@@ -421,7 +421,7 @@ jobs:
working-directory: backend/FwLite/FwLiteMaui
run: |
echo "::warning::Signing key unavailable (likely a fork PR); building an unsigned Android APK."
- dotnet publish -f net10.0-android -p:BuildApple=false --artifacts-path ../artifacts \
+ dotnet publish -f net11.0-android -p:BuildApple=false --artifacts-path ../artifacts \
-p:ApplicationDisplayVersion=${{ needs.build-and-test.outputs.semver-version }} \
-p:ApplicationVersion=${{ github.run_number }} \
-p:InformationalVersion=${{ needs.build-and-test.outputs.version }} \
@@ -432,8 +432,8 @@ jobs:
with:
name: fw-lite-android
if-no-files-found: error
-# path looks like this: backend/FwLite/artifacts/publish/FwLiteMaui/release_net10.0-android/org.sil.fwlitemaui-signed.apk
- path: backend/FwLite/artifacts/publish/FwLiteMaui/release_net10.0-android/*
+# path looks like this: backend/FwLite/artifacts/publish/FwLiteMaui/release_net11.0-android/org.sil.fwlitemaui-signed.apk
+ path: backend/FwLite/artifacts/publish/FwLiteMaui/release_net11.0-android/*
publish-win:
name: Publish FW Lite app for Windows
@@ -449,7 +449,7 @@ jobs:
path: ${{ env.VIEWER_BUILD_OUTPUT_DIR }}
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- name: Cache NuGet packages
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
@@ -482,7 +482,7 @@ jobs:
- name: Publish Windows MAUI portable app
working-directory: backend/FwLite/FwLiteMaui
run: |
- dotnet publish -f net10.0-windows10.0.19041.0 -p:BuildAndroid=false --artifacts-path ../artifacts -p:WindowsPackageType=None -p:ApplicationDisplayVersion=${{ needs.build-and-test.outputs.semver-version }} -p:InformationalVersion=${{ needs.build-and-test.outputs.version }}
+ dotnet publish -f net11.0-windows10.0.19041.0 -p:BuildAndroid=false --artifacts-path ../artifacts -p:WindowsPackageType=None -p:ApplicationDisplayVersion=${{ needs.build-and-test.outputs.semver-version }} -p:InformationalVersion=${{ needs.build-and-test.outputs.version }}
mkdir -p ../artifacts/sign/portable
cp -r ../artifacts/publish/FwLiteMaui/* ../artifacts/sign/portable/
@@ -492,7 +492,7 @@ jobs:
# AppxPackageDir is the MSIX-targets equivalent of --artifacts-path: without it
# MAUI 10 writes AppPackages to $(MSBuildProjectDirectory)/AppPackages, ignoring
# --artifacts-path. Redirect it under artifacts/ so everything lives in one tree.
- dotnet publish -f net10.0-windows10.0.19041.0 -p:BuildAndroid=false --artifacts-path ../artifacts -p:AppxPackageDir=../artifacts/AppPackages/ -p:ApplicationDisplayVersion=${{ needs.build-and-test.outputs.semver-version }} -p:InformationalVersion=${{ needs.build-and-test.outputs.version }}
+ dotnet publish -f net11.0-windows10.0.19041.0 -p:BuildAndroid=false --artifacts-path ../artifacts -p:AppxPackageDir=../artifacts/AppPackages/ -p:ApplicationDisplayVersion=${{ needs.build-and-test.outputs.semver-version }} -p:InformationalVersion=${{ needs.build-and-test.outputs.version }}
mkdir -p ../artifacts/msix
cp ../artifacts/AppPackages/*/*.msix ../artifacts/msix/
@@ -609,7 +609,7 @@ jobs:
path: ${{ env.VIEWER_BUILD_OUTPUT_DIR }}
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- name: Publish FwLiteWeb (linux-x64)
working-directory: backend/FwLite/FwLiteWeb
run: dotnet publish -r linux-x64 --artifacts-path ../artifacts -p:PublishSingleFile=true
diff --git a/.github/workflows/integration-test-gha.yaml b/.github/workflows/integration-test-gha.yaml
index f18eba9fc4..a112e0b177 100644
--- a/.github/workflows/integration-test-gha.yaml
+++ b/.github/workflows/integration-test-gha.yaml
@@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- uses: ./.github/actions/setup-k8s
with:
lexbox-api-tag: ${{ inputs.lexbox-api-tag }}
diff --git a/.github/workflows/integration-test.yaml b/.github/workflows/integration-test.yaml
index a6358768a6..95c3552536 100644
--- a/.github/workflows/integration-test.yaml
+++ b/.github/workflows/integration-test.yaml
@@ -72,7 +72,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- uses: MatteoH2O1999/setup-python@429b7dee8a48c31eb72ce0b420ea938ff51c2f11 # v3.2.1
id: python
if: ${{ inputs.runs-on != 'windows-latest' && !env.act && inputs.hg-version == '3' }}
diff --git a/.github/workflows/lexbox-api.yaml b/.github/workflows/lexbox-api.yaml
index 7dd81f5549..be3dc149a1 100644
--- a/.github/workflows/lexbox-api.yaml
+++ b/.github/workflows/lexbox-api.yaml
@@ -47,7 +47,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- name: Install Task
uses: arduino/setup-task@c0bc642852239c2689f73f4ea6459c29405f3c52 # v3.0.0
with:
diff --git a/.github/workflows/lexbox-fw-headless.yaml b/.github/workflows/lexbox-fw-headless.yaml
index 706af1da46..5c72efd27f 100644
--- a/.github/workflows/lexbox-fw-headless.yaml
+++ b/.github/workflows/lexbox-fw-headless.yaml
@@ -47,7 +47,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
- dotnet-version: '10.x'
+ global-json-file: global.json
- name: Dotnet build
run: dotnet build backend/FwHeadless/FwHeadless.csproj
- name: Unit tests
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index bbe63c24bd..a7d94c7641 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -9,7 +9,7 @@
"build",
"${workspaceFolder}/backend/FwLite/FwLiteMaui/FwLiteMaui.csproj",
"--framework",
- "net10.0-windows10.0.19041.0",
+ "net11.0-windows10.0.19041.0",
],
"problemMatcher": "$msCompile"
},
diff --git a/AGENTS.md b/AGENTS.md
index d7ad9b5408..3b667c3917 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -9,7 +9,7 @@ This is a monorepo containing:
### Tech Stack
-- **Backend**: .NET 10, C#, Entity Framework Core, GraphQL (Hot Chocolate)
+- **Backend**: .NET 11, C#, Entity Framework Core, GraphQL (Hot Chocolate)
- **Frontend**: SvelteKit, TypeScript
- **Database**: PostgreSQL
- **Infrastructure**: Docker, Kubernetes, Skaffold, Tilt
@@ -117,7 +117,7 @@ If you are struggling, explain the difficulty to the user instead of cheating. *
## Cursor Cloud specific instructions
-System deps (.NET 10 SDK, Taskfile/`task`) are baked into the VM snapshot; the startup update script only refreshes pnpm + FwLiteWeb NuGet deps. The generated TS types under `frontend/viewer/src/lib/dotnet-types/generated-types/` are committed, so the viewer runs without a backend build.
+System deps (.NET 11 SDK, Taskfile/`task`) are baked into the VM snapshot; the startup update script only refreshes pnpm + FwLiteWeb NuGet deps. The generated TS types under `frontend/viewer/src/lib/dotnet-types/generated-types/` are committed, so the viewer runs without a backend build.
### Running FW Lite Web (headless)
diff --git a/backend/AGENTS.md b/backend/AGENTS.md
index 081083c0cb..66bcc0e029 100644
--- a/backend/AGENTS.md
+++ b/backend/AGENTS.md
@@ -1,6 +1,6 @@
# Backend
-.NET 10 backend for LexBox and FwLite applications.
+.NET 11 backend for LexBox and FwLite applications.
## Build & Test
@@ -13,7 +13,7 @@ dotnet test
# Build specific project
dotnet build LexBoxApi/LexBoxApi.csproj
-dotnet build FwLite/FwLiteMaui/FwLiteMaui.csproj --framework net10.0-windows10.0.19041.0
+dotnet build FwLite/FwLiteMaui/FwLiteMaui.csproj --framework net11.0-windows10.0.19041.0
```
## Project Structure
@@ -38,7 +38,7 @@ To build against local Harmony source (e.g. when developing the CRDT substrate),
- **Nullable**: Enabled globally, `Nullable` warnings are errors
- **Implicit usings**: Enabled
-- **Target framework**: net10.0 (unless platform-specific)
+- **Target framework**: net11.0 (unless platform-specific)
- **Async**: Use `async/await`, not `.Result` or `.Wait()`. Prefer `return await Foo()` over returning the task directly — awaiting keeps this method on the stack trace when the inner call throws. Only drop the `await` (return the task) as a hot-path micro-optimization ([#2435](https://github.com/sillsdev/languageforge-lexbox/pull/2435#discussion_r3584331713))
- **Records**: Prefer for DTOs and immutable data
diff --git a/backend/Directory.Build.props b/backend/Directory.Build.props
index a2aa73bf47..34ef124bd5 100644
--- a/backend/Directory.Build.props
+++ b/backend/Directory.Build.props
@@ -11,7 +11,7 @@
dev
- net10.0
+ net11.0
false
enable
enable
diff --git a/backend/Dockerfile b/backend/Dockerfile
index c6eaba94a7..ff3a8190d8 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -1,10 +1,10 @@
# syntax=docker/dockerfile:1
-FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
+FROM mcr.microsoft.com/dotnet/aspnet:11.0-preview AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
-FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:11.0-preview AS build
COPY . .
# WORKDIR /src
diff --git a/backend/FwHeadless/Dockerfile b/backend/FwHeadless/Dockerfile
index e5f0eb552a..3da4955593 100644
--- a/backend/FwHeadless/Dockerfile
+++ b/backend/FwHeadless/Dockerfile
@@ -1,10 +1,10 @@
# syntax=docker/dockerfile:1
-FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
+FROM mcr.microsoft.com/dotnet/aspnet:11.0-preview AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
-FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:11.0-preview AS build
COPY . .
RUN --mount=type=cache,target=/root/.nuget/packages dotnet restore "FwHeadless/FwHeadless.csproj"
@@ -19,20 +19,50 @@ RUN --mount=type=cache,target=/root/.nuget/packages dotnet publish /p:Informatio
FROM mcr.microsoft.com/dotnet/runtime:8.0 AS dotnet8
+# Chorus Mercurial 6.5 needs Python 3.12. aspnet:11.0-preview is Ubuntu 26.04
+# (python3 is 3.14). Build 3.12 in a throwaway stage (same base, so glibc/ssl match);
+# curl/gnupg/deadsnakes never enter the runtime image.
+FROM base AS python312
+RUN apt-get update \
+ && apt-get install --yes --no-install-recommends ca-certificates curl gnupg \
+ && curl -fsSL 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xF23C5A6CF475977595C89F51BA6932366A755776' \
+ | gpg --dearmor -o /etc/apt/keyrings/deadsnakes.gpg \
+ && echo "deb [signed-by=/etc/apt/keyrings/deadsnakes.gpg] https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") main" \
+ > /etc/apt/sources.list.d/deadsnakes.list \
+ && apt-get update \
+ && apt-get install --yes --no-install-recommends python3.12 \
+ && rm -rf /var/lib/apt/lists/*
+
FROM base AS final
RUN mkdir -p /var/lib/fw-headless /var/www/.local/share && chown -R www-data:www-data /var/lib/fw-headless /var/www/.local/share
+# Shared libs python3.12 / stdlib extensions need; the aspnet image does not ship them.
+# Installing python3.12 itself here would also pull distro python3 (3.14).
RUN apt-get update \
- && apt-get install --yes --no-install-recommends tini iputils-ping python3 \
+ && apt-get install --yes --no-install-recommends tini iputils-ping ca-certificates \
+ libexpat1 zlib1g libbz2-1.0 libcrypt1 libdb5.3t64 libffi8 liblzma5 \
+ libncursesw6 libreadline8t64 libsqlite3-0 libssl3t64 libtinfo6 libuuid1 \
&& rm -rf /var/lib/apt/lists/*
+COPY --from=python312 /usr/bin/python3.12 /usr/bin/python3.12
+COPY --from=python312 /usr/lib/python3.12 /usr/lib/python3.12
+COPY --from=python312 /etc/python3.12 /etc/python3.12
WORKDIR /app
+# Mercurial 6.5's demandimport breaks on 3.12+ (circular import of threading.RLock).
+# Chorus spawns hg as a child, so this must be in the image env.
+ENV HGDEMANDIMPORT=disable
# dotnet 8 runtime is for ChorusMerge
COPY --from=dotnet8 /usr/share/dotnet/host/fxr/ /usr/share/dotnet/host/fxr/
COPY --from=dotnet8 /usr/share/dotnet/shared/Microsoft.NETCore.App/ /usr/share/dotnet/shared/Microsoft.NETCore.App/
COPY --from=publish /app/publish .
# Ensure Chorus and Mercurial exec bits were not stripped by dotnet CLI tools
RUN chmod +x chorusmerge && chmod +x Mercurial/hg && chmod +x Mercurial/chg 2>/dev/null || true
-# Fix up mercurial.ini path to fixutf8
-RUN sed -i -e 's/fixutf8 = \/FwHeadless/fixutf8 = \/app/' Mercurial/mercurial.ini
+# Fix up mercurial.ini path to fixutf8; point hg at python3.12 (shebang is python3)
+RUN sed -i -e 's/fixutf8 = \/FwHeadless/fixutf8 = \/app/' Mercurial/mercurial.ini \
+ && sed -i '1s|^#!.*python3.*|#!/usr/bin/env python3.12|' Mercurial/hg
+# Smoke-test: bundled hg must start (python3.12). Chorus treats hg exit 1 as
+# success, so a dead interpreter looks like "no .hg" at clone time.
+RUN python3.12 --version \
+ && ./Mercurial/hg version \
+ || { echo "hg version smoke test failed (python3.12 $(python3.12 --version 2>&1))"; exit 1; }
COPY Testing/test-template-repo.zip /tmp/test-template-repo.zip
# Smoke-test FixFwData at image build time: FwHeadless runs under dotnet (AspNetCore shared
# framework) but FixFwData is a standalone apphost (Core only). Web publish does not copy the
@@ -40,7 +70,7 @@ COPY Testing/test-template-repo.zip /tmp/test-template-repo.zip
# target must publish it into the same output. Running it here catches a broken publish early.
RUN test -f FixFwData \
&& chmod +x FixFwData \
- && python3 -c "import zipfile; open('/tmp/smoke.fwdata','wb').write(zipfile.ZipFile('/tmp/test-template-repo.zip').read('kevin-test-01.fwdata'))" \
+ && python3.12 -c "import zipfile; open('/tmp/smoke.fwdata','wb').write(zipfile.ZipFile('/tmp/test-template-repo.zip').read('kevin-test-01.fwdata'))" \
&& ./FixFwData /tmp/smoke.fwdata; ec=$?; rm -f /tmp/test-template-repo.zip /tmp/smoke.fwdata; \
if [ $ec -gt 1 ]; then echo "FixFwData smoke test failed with exit $ec"; exit 1; fi
# Smoke-test: chorusmerge must engage the FieldWorks merge handler, not silently keep one
diff --git a/backend/FwHeadless/FwHeadless.csproj b/backend/FwHeadless/FwHeadless.csproj
index 9b6dd151ba..e7e6faab93 100644
--- a/backend/FwHeadless/FwHeadless.csproj
+++ b/backend/FwHeadless/FwHeadless.csproj
@@ -44,7 +44,7 @@
chorusmerge
PreserveNewest
-
+
ChorusMerge.runtimeconfig.json
PreserveNewest
diff --git a/backend/FwLite/AGENTS.md b/backend/FwLite/AGENTS.md
index 2bc1a1d26a..41252dcbea 100644
--- a/backend/FwLite/AGENTS.md
+++ b/backend/FwLite/AGENTS.md
@@ -27,7 +27,7 @@ task fw-lite-web # from repo root
dotnet test FwLiteOnly.slnf
# Build MAUI app (Windows)
-dotnet build FwLiteMaui/FwLiteMaui.csproj --framework net10.0-windows10.0.19041.0
+dotnet build FwLiteMaui/FwLiteMaui.csproj --framework net11.0-windows10.0.19041.0
```
## Testing on Android (agents)
@@ -48,6 +48,8 @@ task fw-lite:has-stale-generated-types
The configuration for this lives in `FwLiteShared/TypeGen/ReinforcedFwLiteTypingConfig.cs` and `FwLiteShared/Reinforced.Typings.settings.xml`.
+> **.NET 11 preview note:** Reinforced.Typings 1.6.7 has no net11 tool, so `FwLiteShared.csproj` forces its net10 `rtcli` and patches the tool's runtimeconfig to run on the net11 runtime (`_RtPatchToolRuntimeConfig` target). It's self-contained — no env vars needed. Delete `RtForceTargetFramework` + that target once the package ships a net11 tool.
+
⚠️ **`[JSInvokable]` methods must not have optional/defaulted parameters (nor a `CancellationToken`).** The generated TS marks them optional (`arg?`), but that's a lie: Blazor JSInterop requires JS to pass every parameter, and can't marshal a `CancellationToken` — so JS callers break at runtime. If a server-side (REST) caller needs cancellation or an extra arg, add a separate **non-`[JSInvokable]`** overload for it (see `AuthService.SignInWebView`).
## Project Structure
diff --git a/backend/FwLite/FwLiteMaui.Tests/FwLiteMaui.Tests.csproj b/backend/FwLite/FwLiteMaui.Tests/FwLiteMaui.Tests.csproj
index 36af9daff8..45f70505bd 100644
--- a/backend/FwLite/FwLiteMaui.Tests/FwLiteMaui.Tests.csproj
+++ b/backend/FwLite/FwLiteMaui.Tests/FwLiteMaui.Tests.csproj
@@ -5,10 +5,10 @@
true
- $(TargetFrameworks);net10.0-android
- $(TargetFrameworks);net10.0-ios;net10.0-maccatalyst
- $(TargetFrameworks);net10.0-windows10.0.19041.0
- $(NoWarn);XA0101
+ $(TargetFrameworks);net11.0-android
+ $(TargetFrameworks);net11.0-ios;net11.0-maccatalyst
+ $(TargetFrameworks);net11.0-windows10.0.19041.0
+ $(NoWarn);XA0101
diff --git a/backend/FwLite/FwLiteMaui/FwLiteMaui.csproj b/backend/FwLite/FwLiteMaui/FwLiteMaui.csproj
index 69624a297c..e695ab09db 100644
--- a/backend/FwLite/FwLiteMaui/FwLiteMaui.csproj
+++ b/backend/FwLite/FwLiteMaui/FwLiteMaui.csproj
@@ -2,9 +2,9 @@
- $(TargetFrameworks);net10.0-android;
- $(TargetFrameworks);net10.0-ios;net10.0-maccatalyst
- $(TargetFrameworks);net10.0-windows10.0.19041.0
+ $(TargetFrameworks);net11.0-android;
+ $(TargetFrameworks);net11.0-ios;net11.0-maccatalyst
+ $(TargetFrameworks);net11.0-windows10.0.19041.0
preview
- android-arm;android-arm64;android-x86;android-x64
+ android-arm;android-arm64;android-x64
Exe
FwLiteMaui
true
@@ -60,7 +60,7 @@
$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))
-
+
@@ -133,7 +133,7 @@
DependsOnTargets="_VerifyLinq2DbEfCoreVersionPin"
BeforeTargets="_ResolveAssemblies;_LinkAssembliesNoShrink;_AfterILLinkAdditionalSteps;_RemoveRegisterAttribute"
Inputs="build\Linq2DbCctorPatcher\Program.cs;build\Linq2DbCctorPatcher\Linq2DbCctorPatcher.csproj"
- Outputs="build\Linq2DbCctorPatcher\bin\$(Configuration)\net10.0\Linq2DbCctorPatcher.dll">
+ Outputs="build\Linq2DbCctorPatcher\bin\$(Configuration)\net11.0\Linq2DbCctorPatcher.dll">
@@ -156,7 +156,7 @@
Inputs="@(_Linq2DbStagedAssemblies)"
Outputs="@(_Linq2DbStagedAssemblies->'%(FullPath).cctor-patched')">
- <_Linq2DbPatcherDll>$(MSBuildThisFileDirectory)build\Linq2DbCctorPatcher\bin\$(Configuration)\net10.0\Linq2DbCctorPatcher.dll
+ <_Linq2DbPatcherDll>$(MSBuildThisFileDirectory)build\Linq2DbCctorPatcher\bin\$(Configuration)\net11.0\Linq2DbCctorPatcher.dll
diff --git a/backend/FwLite/FwLiteMaui/build/Linq2DbCctorPatcher/Linq2DbCctorPatcher.csproj b/backend/FwLite/FwLiteMaui/build/Linq2DbCctorPatcher/Linq2DbCctorPatcher.csproj
index 7c1483ed72..8bbaaca53e 100644
--- a/backend/FwLite/FwLiteMaui/build/Linq2DbCctorPatcher/Linq2DbCctorPatcher.csproj
+++ b/backend/FwLite/FwLiteMaui/build/Linq2DbCctorPatcher/Linq2DbCctorPatcher.csproj
@@ -1,7 +1,7 @@
Exe
- net10.0
+ net11.0
enable
enable
diff --git a/backend/FwLite/FwLiteShared/FwLiteShared.csproj b/backend/FwLite/FwLiteShared/FwLiteShared.csproj
index d299ef8c46..f6d6ef7180 100644
--- a/backend/FwLite/FwLiteShared/FwLiteShared.csproj
+++ b/backend/FwLite/FwLiteShared/FwLiteShared.csproj
@@ -1,6 +1,17 @@
false
+
+ net10.0
+
+ $(BundledNETCoreAppPackageVersion)
@@ -14,7 +25,7 @@
-
+
@@ -22,4 +33,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/backend/FwLite/FwLiteWeb/Dockerfile b/backend/FwLite/FwLiteWeb/Dockerfile
index ecbb8f887b..abe7f2a17a 100644
--- a/backend/FwLite/FwLiteWeb/Dockerfile
+++ b/backend/FwLite/FwLiteWeb/Dockerfile
@@ -1,10 +1,10 @@
-FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
+FROM mcr.microsoft.com/dotnet/aspnet:11.0-preview AS base
USER $APP_UID
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
-FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:11.0-preview AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["FwLiteWeb/FwLiteWeb.csproj", "FwLiteWeb/"]
diff --git a/backend/FwLite/README.md b/backend/FwLite/README.md
index 66fad5e3dc..d8aa89d9fd 100644
--- a/backend/FwLite/README.md
+++ b/backend/FwLite/README.md
@@ -34,7 +34,7 @@ dotnet test FwLiteOnly.slnf
### Building for a specific framework
```bash
-dotnet build -f net10.0-ios
+dotnet build -f net11.0-ios
```
You can choose which framework to build for with the `-f` flag.
diff --git a/backend/FwLite/Taskfile.yml b/backend/FwLite/Taskfile.yml
index 5960ddffc9..165ecaee81 100644
--- a/backend/FwLite/Taskfile.yml
+++ b/backend/FwLite/Taskfile.yml
@@ -67,7 +67,7 @@ tasks:
maui-windows:
desc: Run Maui Windows, requires vite dev server to be running, use task fw-lite-win in root
dir: ./FwLiteMaui
- cmd: dotnet run -f net10.0-windows10.0.19041.0
+ cmd: dotnet run -f net11.0-windows10.0.19041.0
publish-maui-windows:
deps: [ publish-maui-windows-msix, publish-maui-windows-portable]
@@ -75,12 +75,12 @@ tasks:
publish-maui-windows-portable:
dir: ./FwLiteMaui
cmds:
- - dotnet publish -f net10.0-windows10.0.19041.0 --artifacts-path ../artifacts -p:WindowsPackageType=None -p:BuildAndroid=false
+ - dotnet publish -f net11.0-windows10.0.19041.0 --artifacts-path ../artifacts -p:WindowsPackageType=None -p:BuildAndroid=false
publish-maui-windows-msix:
dir: ./FwLiteMaui
cmds:
- - dotnet publish -f net10.0-windows10.0.19041.0 --artifacts-path ../artifacts -p:BuildAndroid=false
+ - dotnet publish -f net11.0-windows10.0.19041.0 --artifacts-path ../artifacts -p:BuildAndroid=false
run-maui-android:
dir: ./FwLiteMaui
@@ -106,12 +106,12 @@ tasks:
deps: [ ui:build-viewer ]
dir: ./FwLiteMaui
# EXTRA_ARGS goes through a Task var so multi-token values stay separate; CLI_ARGS gets re-quoted into a single shell arg.
- cmd: dotnet build -f net10.0-android -t:InstallAndroidDependencies -p:AcceptAndroidSdkLicenses=True -p:FwLiteFlavor={{.FLAVOR}} {{.EXTRA_ARGS}} {{.CLI_ARGS}}
+ cmd: dotnet build -f net11.0-android -t:InstallAndroidDependencies -p:AcceptAndroidSdkLicenses=True -p:FwLiteFlavor={{.FLAVOR}} {{.EXTRA_ARGS}} {{.CLI_ARGS}}
install-maui-android:
desc: Retry install + run without rebuilding (for when you miss the permission prompt) - uses existing build artifacts
dir: ./FwLiteMaui
- cmd: dotnet build -f net10.0-android -t:Install,Run --no-restore --no-dependencies -p:FwLiteFlavor={{.FLAVOR}} {{.EXTRA_ARGS}}
+ cmd: dotnet build -f net11.0-android -t:Install,Run --no-restore --no-dependencies -p:FwLiteFlavor={{.FLAVOR}} {{.EXTRA_ARGS}}
install-maui-android-dev:
desc: Retry install + run for the "Dev" flavor without rebuilding
@@ -128,9 +128,9 @@ tasks:
publish-maui-android-release:
deps: [ ui:build-viewer ]
dir: ./FwLiteMaui
- # Produces a signed AAB/APK at bin/Release/net10.0-android/-Signed.{aab,apk}.
+ # Produces a signed AAB/APK at bin/Release/net11.0-android/-Signed.{aab,apk}.
# No -t:Run — the SDK's Run uses bundletool, which errors out with multiple devices/emulators.
- cmd: dotnet build -f net10.0-android -c Release -t:InstallAndroidDependencies -p:AcceptAndroidSdkLicenses=True -p:FwLiteFlavor={{.FLAVOR}} {{.CLI_ARGS}}
+ cmd: dotnet build -f net11.0-android -c Release -t:InstallAndroidDependencies -p:AcceptAndroidSdkLicenses=True -p:FwLiteFlavor={{.FLAVOR}} {{.CLI_ARGS}}
install-maui-android-release-dev:
desc: Build a Release "Dev" APK and adb-install it on the connected USB device (uses `adb -d`)
@@ -138,7 +138,7 @@ tasks:
cmds:
- task: publish-maui-android-release
vars: { FLAVOR: 'Dev' }
- - adb -d install -r bin/Release/net10.0-android/org.sil.FwLiteMaui.dev-Signed.apk
+ - adb -d install -r bin/Release/net11.0-android/org.sil.FwLiteMaui.dev-Signed.apk
build-mini-lcm-sdk:
desc: Builds the sdk, a zip with the FwLiteWeb server with a project and config to run locally
@@ -185,7 +185,7 @@ tasks:
test-verified:
desc: Run only tests that generate verified snapshot files
# always produces exit status 1, because the framework isn't valid for all test projects
- cmd: dotnet test ../../FwLiteOnly.slnf --filter "Category=Verified" --framework net10.0 --logger "console;verbosity=minimal"
+ cmd: dotnet test ../../FwLiteOnly.slnf --filter "Category=Verified" --framework net11.0 --logger "console;verbosity=minimal"
reset-verified:
desc: Reset all verified snapshot files to their state on origin/develop
cmds:
diff --git a/backend/WebServiceDefaults/WebServiceDefaults.csproj b/backend/WebServiceDefaults/WebServiceDefaults.csproj
index 8b58ee4f35..def4384183 100644
--- a/backend/WebServiceDefaults/WebServiceDefaults.csproj
+++ b/backend/WebServiceDefaults/WebServiceDefaults.csproj
@@ -1,6 +1,6 @@
- net10.0
+ net11.0
enable
enable
diff --git a/docs/research/msix-appinstaller-fwlite.md b/docs/research/msix-appinstaller-fwlite.md
index 5e261b2fbd..f88b5f820d 100644
--- a/docs/research/msix-appinstaller-fwlite.md
+++ b/docs/research/msix-appinstaller-fwlite.md
@@ -171,7 +171,7 @@ experiment before committing to the approach.**
FW Lite's generated file uses the **2021 schema** and `OnLaunch` + `ShowPrompt` +
`UpdateBlocksActivation` + `AutomaticBackgroundTask` + `ForceUpdateFromAnyVersion`, so the effective
floor is **Windows 10 2004 (19041)** — which is also the MAUI target framework floor
-(`net10.0-windows10.0.19041.0`), so no new constraint is introduced.
+(`net11.0-windows10.0.19041.0`), so no new constraint is introduced.
**Signing / trust:** packages must be signed with a certificate trusted by the device. A CA-trusted
cert (Trusted Signing, which FW Lite uses) means Windows already trusts it and nothing needs to be
diff --git a/global.json b/global.json
index 1e7fdfa95f..2b40c8f6cb 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,7 @@
{
+ "//": "version is a floor: CI installs it exactly (setup-dotnet global-json-file); locally rollForward:latestMinor uses the newest installed 11.x SDK.",
"sdk": {
- "version": "10.0.100",
+ "version": "11.0.100-preview.7.26381.103",
"rollForward": "latestMinor"
}
}