Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a9041cd
Bump linq2db v5→v6 and EF Core 9→10 package versions
myieye May 20, 2026
8d2b22a
Fix linq2db v6 query regressions in LcmCrdt via shadow properties
myieye May 20, 2026
584d021
Add Linq2DbCctorPatcher Android build tool
myieye May 20, 2026
525cfd7
EF Core 10 follow-ons: RichMultiString null-setter, model and test up…
myieye May 20, 2026
c687e40
Bump harmony submodule to 96a75b26 (HasCommit TOCTOU fix)
myieye May 20, 2026
06aefc5
Linq2DbCctorPatcher cleanups
myieye May 21, 2026
b0e9805
Restore predefined-data named-GUIDs work from #2278
myieye May 21, 2026
519c4be
Update DbModel snapshot for EF Core 10 debug-string changes
myieye May 21, 2026
2283483
Clean up linq2db v6 comments and reduce diff noise
myieye May 21, 2026
713bafc
Bump Microsoft.* patch versions
myieye May 21, 2026
1e9374d
Bump linq2db 6.2.1 -> 6.3.0 and linq2db.EntityFrameworkCore 10.3.0 ->…
myieye May 22, 2026
38ba249
Trim linq2db v6 noise: restore Dev flavor, slim cctor-patcher comments
myieye May 22, 2026
696b37b
Add Json.At ergonomic helper, scope cctor-patcher excludes
myieye May 22, 2026
de1fafb
Pin SDK to 10.0.108 / latestPatch
myieye May 22, 2026
cbc2d33
Revert SDK pin to 10.0.100 / latestMinor
myieye May 22, 2026
c5dccbf
Run cctor patcher before Android AOT compilation
myieye May 22, 2026
7b3ffe9
Fix cctor patcher parallel-build race in Release multi-RID
myieye May 22, 2026
0c126f1
Add task android-release-dev: Release "Dev" APK + adb install
myieye May 22, 2026
64a1666
Move linq2db v6 design notes from markdown to issue #2291
myieye May 22, 2026
afc4df6
Drop LinqToDB.Internal.Common dependency for IsNullOrEmpty()
myieye May 22, 2026
e15f368
Tiny Refactor
myieye May 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,8 @@ tasks:
aliases: [android-install-emulator-dev]
desc: Install the "Dev" flavor on a running x86_64 emulator without building
deps: [fw-lite:install-maui-android-emulator-dev]

fw-lite-android-release-dev:
aliases: [android-release-dev]
desc: Build a Release "Dev" APK and adb-install it on the connected USB device
deps: [fw-lite:install-maui-android-release-dev]
87 changes: 45 additions & 42 deletions backend/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
<PackageVersion Include="coverlet.collector" Version="10.0.0" />
<PackageVersion Include="CrystalQuartz.AspNetCore" Version="7.3.0" />
<PackageVersion Include="DataAnnotatedModelValidations" Version="10.0.0" />
<!-- Pinned: FluentAssertions 8.x has a serious BeEquivalentTo perf regression
that pushes FwLite CI past its 60-minute timeout. 7.0.0-alpha.5 is the
last known-good build for our suite. -->
<PackageVersion Include="FluentAssertions" Version="7.0.0-alpha.5" />
<PackageVersion Include="FluentValidation" Version="12.1.1" />
<PackageVersion Include="GitHubActionsTestLogger" Version="3.0.4" />
<PackageVersion Include="Gridify" Version="2.17.0" />
<PackageVersion Include="Gridify.EntityFramework" Version="2.17.0" />
<PackageVersion Include="Gridify" Version="2.19.1" />
<PackageVersion Include="Gridify.EntityFramework" Version="2.19.1" />
<PackageVersion Include="HotChocolate.AspNetCore" Version="$(HotChocolateVersion)" />
<PackageVersion Include="HotChocolate.AspNetCore.Authorization" Version="$(HotChocolateVersion)" />
<PackageVersion Include="HotChocolate.Data.EntityFramework" Version="$(HotChocolateVersion)" />
Expand All @@ -25,38 +28,38 @@
<PackageVersion Include="HotChocolate.Types.OffsetPagination" Version="$(HotChocolateVersion)" />
<PackageVersion Include="Humanizer.Core" Version="3.0.10" />
<PackageVersion Include="icu.net" Version="3.0.1" />
<PackageVersion Include="linq2db.AspNet" Version="5.4.1" />
<PackageVersion Include="linq2db.EntityFrameworkCore" Version="9.0.0" />
<PackageVersion Include="linq2db.Extensions" Version="6.3.0" />
<PackageVersion Include="linq2db.EntityFrameworkCore" Version="10.4.0" />
<PackageVersion Include="MailKit" Version="4.16.0" />
<PackageVersion Include="Meziantou.Extensions.Logging.Xunit" Version="2.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Google" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Google" Version="10.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="10.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="$(MauiVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.16" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.16" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.16" />
<PackageVersion Include="Microsoft.Extensions.Caching.Hybrid" Version="10.5.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="9.0.16" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.5.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging.Debug" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options.DataAnnotations" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.5.0" />
<PackageVersion Include="Microsoft.Extensions.TimeProvider.Testing" Version="10.5.0" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.8" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Client" Version="10.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="10.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.8" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Caching.Hybrid" Version="10.6.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.6.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Logging.Debug" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.Options.DataAnnotations" Version="10.0.8" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.6.0" />
<PackageVersion Include="Microsoft.Extensions.TimeProvider.Testing" Version="10.6.0" />
<PackageVersion Include="Microsoft.ICU.ICU4C.Runtime" Version="72.1.0.3" />
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="4.84.0" />
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.18.0" />
Expand All @@ -70,16 +73,16 @@
<PackageVersion Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="3.0.0" />
<PackageVersion Include="Moq" Version="4.20.72" />
<PackageVersion Include="Moq.Contrib.HttpClient" Version="1.4.0" />
<PackageVersion Include="NeinLinq" Version="7.3.2" />
<PackageVersion Include="NeinLinq.EntityFrameworkCore" Version="7.3.2" />
<PackageVersion Include="NeinLinq" Version="7.4.0" />
<PackageVersion Include="NeinLinq.EntityFrameworkCore" Version="7.4.0" />
<PackageVersion Include="Nito.AsyncEx.Coordination" Version="5.1.2" />
<PackageVersion Include="Npgsql" Version="9.0.5" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
<PackageVersion Include="Npgsql.OpenTelemetry" Version="9.0.5" />
<PackageVersion Include="Npgsql" Version="10.0.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
<PackageVersion Include="Npgsql.OpenTelemetry" Version="10.0.2" />
<PackageVersion Include="NReco.Logging.File" Version="1.3.1" />
<PackageVersion Include="OpenIddict.AspNetCore" Version="7.1.0" />
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="7.1.0" />
<PackageVersion Include="OpenIddict.Quartz" Version="7.1.0" />
<PackageVersion Include="OpenIddict.AspNetCore" Version="7.5.0" />
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="7.5.0" />
<PackageVersion Include="OpenIddict.Quartz" Version="7.5.0" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
Expand Down Expand Up @@ -119,9 +122,9 @@
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.18.0" />
<PackageVersion Include="System.Linq.Async" Version="7.0.1" />
<PackageVersion Include="System.Reactive" Version="6.1.0" />
<PackageVersion Include="System.Security.Cryptography.Xml" Version="10.0.7" />
<PackageVersion Include="System.Text.Encodings.Web" Version="10.0.7" />
<PackageVersion Include="System.Text.Json" Version="10.0.7" />
<PackageVersion Include="System.Security.Cryptography.Xml" Version="10.0.8" />
<PackageVersion Include="System.Text.Encodings.Web" Version="10.0.8" />
<PackageVersion Include="System.Text.Json" Version="10.0.8" />
<PackageVersion Include="SystemTextJson.JsonDiffPatch" Version="2.0.0" />
<PackageVersion Include="SystemTextJsonPatch" Version="5.0.0" />
<PackageVersion Include="tusdotnet" Version="2.11.1" />
Expand Down
64 changes: 64 additions & 0 deletions backend/FwLite/FwLiteMaui/FwLiteMaui.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@
<PropertyGroup>
<TargetPlatform>$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))</TargetPlatform>
</PropertyGroup>
<!-- Linq2DbCctorPatcher (under build\) is its own net10.0 Exe project; keep it off this compile. -->
<ItemGroup>
<Compile Remove="build\Linq2DbCctorPatcher\**" />
<Content Remove="build\Linq2DbCctorPatcher\**" />
<None Remove="build\Linq2DbCctorPatcher\**" />
<EmbeddedResource Remove="build\Linq2DbCctorPatcher\**" />
<MauiAsset Remove="build\Linq2DbCctorPatcher\**" />
</ItemGroup>
<ItemGroup>
<!-- App Icon -->
<!-- background color is required for mac per: https://learn.microsoft.com/en-us/dotnet/maui/user-interface/images/app-icons?view=net-maui-8.0&tabs=windows#recolor-the-background -->
Expand Down Expand Up @@ -100,4 +108,60 @@
-->
<PackageReference Include="Mono.Unix" ExcludeAssets="all" />
</ItemGroup>
<!-- Android workaround for linq2db.EntityFrameworkCore's broken SqlTransparentExpression
cctor. See https://github.com/sillsdev/languageforge-lexbox/issues/2291 for the
full story, including the kill-switch checklist for when upstream PR #5546 ships. -->
<Target Name="_VerifyLinq2DbEfCoreVersionPin"
Condition="'$(TargetPlatform)' == 'android'"
BeforeTargets="_BuildLinq2DbCctorPatcher">
<PropertyGroup>
<_Linq2DbEfCoreEffectiveVersion>$([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)..\..\Directory.Packages.props')), 'linq2db\.EntityFrameworkCore[^&gt;]*Version=&quot;([^&quot;]+)&quot;').Groups[1].Value)</_Linq2DbEfCoreEffectiveVersion>
</PropertyGroup>
<Error Condition="'$(_Linq2DbEfCoreEffectiveVersion)' == ''"
Text="Could not read linq2db.EntityFrameworkCore version from backend/Directory.Packages.props." />
<Error Condition="'$(_Linq2DbEfCoreEffectiveVersion)' != '' And !$([System.Text.RegularExpressions.Regex]::IsMatch('$(_Linq2DbEfCoreEffectiveVersion)', '^10\.[34]\.[0-9]+(-.*)?$'))"
Text="linq2db.EntityFrameworkCore is $(_Linq2DbEfCoreEffectiveVersion) but the cctor patcher only covers 10.3.x / 10.4.x. See https://github.com/sillsdev/languageforge-lexbox/issues/2291 for the kill-switch / pin-widening checklist." />
</Target>
<!-- Build the patcher tool BEFORE the Android SDK dispatches per-RID inner builds.
_ResolveAssemblies is the outer-build target that fans out into parallel per-RID
MSBuild invocations; if we built the patcher inside any of those inner builds,
4 parallel `dotnet build` processes would race on the same obj/bin. By running
once at the outer level, every inner build sees the patcher dll already in place.
The Inputs/Outputs guard makes the target a no-op on incremental rebuilds. -->
<Target Name="_BuildLinq2DbCctorPatcher"
Condition="'$(TargetPlatformIdentifier)' == 'android'"
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">
<Exec Command="dotnet build &quot;$(MSBuildThisFileDirectory)build\Linq2DbCctorPatcher\Linq2DbCctorPatcher.csproj&quot; --configuration $(Configuration) --nologo" />
</Target>
<!-- Separate target so the ItemGroup is materialized by the time _PatchLinq2Db...'s Inputs/Outputs batching reads it. -->
<Target Name="_CollectLinq2DbStagedAssemblies"
Condition="'$(TargetPlatform)' == 'android'">
<ItemGroup>
<_Linq2DbStagedAssemblies Include="$(IntermediateOutputPath)**\linq2db.EntityFrameworkCore.dll" />
</ItemGroup>
</Target>
<!-- Incremental: per-dll <dll>.cctor-patched sentinels gate re-runs.
_AndroidAotCompilation must stay in BeforeTargets: in Release the AOT step compiles
IL to native .so files, and Android's runtime prefers the AOT'd native code over IL.
If the patcher runs after AOT, the patched dll in the AAB is shadowed by AOT'd
unpatched native code and the bug still ships. -->
<Target Name="_PatchLinq2DbSqlTransparentExpressionCctor"
Condition="'$(TargetPlatform)' == 'android'"
DependsOnTargets="_BuildLinq2DbCctorPatcher;_CollectLinq2DbStagedAssemblies"
AfterTargets="_LinkAssembliesNoShrink;_AfterILLinkAdditionalSteps;_RemoveRegisterAttribute"
BeforeTargets="_CollectAssembliesToCompress;_BuildApkFastDev;_AndroidAotCompilation"
Inputs="@(_Linq2DbStagedAssemblies)"
Outputs="@(_Linq2DbStagedAssemblies->'%(FullPath).cctor-patched')">
<PropertyGroup>
<_Linq2DbPatcherDll>$(MSBuildThisFileDirectory)build\Linq2DbCctorPatcher\bin\$(Configuration)\net10.0\Linq2DbCctorPatcher.dll</_Linq2DbPatcherDll>
</PropertyGroup>
<Error Condition="!Exists('$(_Linq2DbPatcherDll)')"
Text="Linq2DbCctorPatcher.dll not found at $(_Linq2DbPatcherDll). _BuildLinq2DbCctorPatcher should have produced it." />
<Message Importance="high" Text="Linq2db cctor patcher: @(_Linq2DbStagedAssemblies->Count()) staged linq2db.EntityFrameworkCore.dll copies under $(IntermediateOutputPath)" />
<Exec Command="dotnet &quot;$(_Linq2DbPatcherDll)&quot; &quot;%(_Linq2DbStagedAssemblies.FullPath)&quot;"
Condition="'@(_Linq2DbStagedAssemblies)' != ''" />
</Target>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<!-- This tool is invoked from MSBuild targets in FwLiteMaui.csproj; nothing else references it. -->
<IsPackable>false</IsPackable>
<!-- No native apphost: invoked via `dotnet patcher.dll`. Also avoids a parallel-build
race on apphost.exe when multiple RID inner builds trigger the patcher concurrently. -->
<UseAppHost>false</UseAppHost>
<!-- Don't let this opt into shared central package management; we just pin Mono.Cecil locally. -->
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.6" />
</ItemGroup>
</Project>
Loading
Loading