Move the business layer implementations to the hosts - #772
Open
KrzysztofPajak wants to merge 1 commit into
Open
Conversation
Grand.Web.Common referenced all nine Grand.Business.* implementations alongside the contracts in Grand.Business.Core, without using a single type from any of them. Because Grand.Web is built on Grand.Web.Common, and Grand.Plugin.props points every plugin at it too, the shared web layer and each plugin compiled against the whole business layer for no reason. The references were never about code. Each implementation carries a Startup/StartupApplication.cs, and TypeSearcher discovers IStartupApplication by walking the assemblies present in the AppDomain - so an implementation the host does not reference is never registered. That makes the host, as the composition root, the place they belong. src/Build/Grand.Host.props holds the list once, the way Grand.Plugin.props already does for plugins, and says why removing an entry costs an entire area's DI registration with nothing failing at build time. Each host's dependency closure is unchanged: the same nine assemblies are still referenced, copied and written to deps.json. Only the compile-time graph of Grand.Web.Common shrinks, from twelve project references to three. One consequence was not obvious. Those references were also an implicit version floor for Grand.Web.AdminShared: the Scryber.Core graph outvoted elFinder.Net.* 1.5.0, and without them elFinder won with Newtonsoft.Json 11.0.2 (GHSA-5crp-9r3c-p9vr) and SixLabors.ImageSharp 2.0.0 (GHSA-2cmq-823j-5qj8 and six more). The floor is now stated explicitly next to the existing Microsoft.AspNetCore.Http pin, which exists for the same package graph and the same reason, and resolves back to the 13.0.3 and 3.1.12 that the accident used to produce. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Type: feature
Issue
Grand.Web.Commonreferenced all nineGrand.Business.*implementations alongside the contracts inGrand.Business.Core, while using zero types from any of them — there is not a singleusingof an implementation namespace anywhere in the project.Because
Grand.Webbuilds onGrand.Web.Common,Grand.Web.AdminSharedbuilds on it, andsrc/Build/Grand.Plugin.propspoints every plugin at it, the shared web layer and each plugin compiled against the entire business layer for no reason. This is the coupling node described in the architecture notes as the largest in the solution.Reproduce:
dotnet list src/Web/Grand.Web.Common/Grand.Web.Common.csproj reference— twelve project references, nine of them implementations that nothing in the project links.Solution
The references were never about code. Each implementation carries a
Startup/StartupApplication.cs, andTypeSearcherdiscoversIStartupApplicationby walking the assemblies present in theAppDomain— so an implementation the host does not reference is never loaded and its services are never registered. That makes the host, as the composition root, where they belong.src/Build/Grand.Host.propsholds the list once, mirroring whatGrand.Plugin.propsalready does for plugins, with a comment stating why removing an entry costs an entire business area's DI registration while nothing fails at build time.Grand.Web,Grand.Web.Admin,Grand.Web.Store,Grand.Web.Vendor) import it.Grand.Web.Common, which drops from twelve project references to three.Each host's dependency closure is unchanged — the same nine assemblies are referenced, copied to output and written to
deps.json. Only the compile-time graph shrinks.One consequence was not obvious and is worth review attention. Those references were also an implicit version floor for
Grand.Web.AdminShared: theScryber.Coregraph outvotedelFinder.Net.*1.5.0, and once they were gone elFinder won withNewtonsoft.Json11.0.2 (GHSA-5crp-9r3c-p9vr) andSixLabors.ImageSharp2.0.0 (GHSA-2cmq-823j-5qj8 and six more) — eight new NU1903/NU1902 warnings. The floor is now stated explicitly next to the existingMicrosoft.AspNetCore.Httppin, which exists for the same package graph and the same reason. Both resolve back to exactly what the accident used to produce: 13.0.3 and 3.1.12.Side effect worth naming:
SixLabors.ImageSharpis now a direct reference ofGrand.Web.AdminSharedrather than only transitive. Nothing changes in the shipped artifacts or the licensing position, but it partly reverses #763. The real fix remains replacing elFinder.Breaking changes
None. No public interface, view model, widget zone or plugin system name changes. Plugins are unaffected at build and at runtime:
Grand.Plugin.propsreferencesGrand.Web.CommonwithExcludeAssets="all", and no plugin, module or test project uses an implementation namespace — everyGrand.Business.*.TestsandGrand.Mapping.Testsreferences its implementation project directly.Testing
src/Web/Grand.Web/Pluginsandsrc/Web/Grand.Web/Modules— these are fixedOutputPathdirectories that the build never cleans, so stale copies otherwise mask the result.dotnet build ./GrandNode.sln— succeeds; one pre-existingCS0618warning, no NU19xx.dotnet list src/Web/Grand.Web.Common/Grand.Web.Common.csproj reference— three references, not twelve.src/Web/*/bin/Debug/net10.0/directories still contains tenGrand.Business.*.dll(nine implementations plusGrand.Business.Core).dotnet list src/Web/Grand.Web.AdminShared/Grand.Web.AdminShared.csproj package --include-transitiveshowsNewtonsoft.Json13.0.3 andSixLabors.ImageSharp3.1.12./, a category page, and/search?q=book— all 200. This is the real test: aStartupApplicationthat stopped being discovered fails on a request, not at startup./admin/login,/vendor/loginand/store/login— all 200.dotnet testonGrand.Web.Common.Tests(15),Grand.Infrastructure.Tests(94) andGrand.Mapping.Tests(238) — all pass.🤖 Generated with Claude Code