fix: resolve precompiled block views in Production runtime mode (#273)#315
Merged
rickbutterfield merged 3 commits intoJul 8, 2026
Merged
Conversation
BlockPreviewViewResolver only resolved a view when the .cshtml file was present on disk (File.Exists). In a precompiled deployment - e.g. Runtime:Mode = Production, where Umbraco does not register Razor runtime compilation - the source files may be absent while the views are compiled into the assembly, so resolution failed and previews rendered "view not found". Resolution now consults the Razor view engine even when the file is not on disk, picking up precompiled views. The on-disk fast path is preserved (belt), and the not-on-disk path is guarded against the runtime compiler throwing FileNotFoundException on a case-sensitive file-system miss (braces, regression guard for #84). Adds unit tests for precompiled-but-not-on-disk resolution, IOException safety, and PascalCase fall-through. Makes the resolver testable by no longer gating solely on the un-mockable File.Exists. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…273) Adds a "Runtime mode and Production deployments" section to the configuration guide explaining that Umbraco only enables Razor runtime compilation in BackofficeDevelopment mode, so Production (and Development) runtime modes require views to be precompiled (RazorCompileOnBuild / RazorCompileOnPublish). Without this, no Razor view can render - block previews and the front-end alike. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The File.Exists fast-path issued the same GetView call as the guarded branch, so it no longer avoided work - it only decided whether the call was wrapped in try/catch. This left an asymmetry where an on-disk view that threw IOException (e.g. a locked file) would crash resolution while the same failure off-disk was swallowed. Collapse to a single guarded GetView call. On-disk views resolve exactly as before (GetView succeeds); off-disk precompiled views still resolve (#273); IOException from the runtime compiler (#84) is still treated as "not resolvable". IWebHostEnvironment is no longer needed and is removed along with its now-redundant test mock. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
rickbutterfield
added a commit
that referenced
this pull request
Jul 8, 2026
…d-view-resolution fix: resolve precompiled block views in Production runtime mode (#273)
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.
Summary
Fixes #273. Block previews rendered a "view not found" warning in deployments where Razor runtime compilation is off and the block views are precompiled into the assembly rather than present on disk (e.g.
Runtime:Mode = ProductionwithRazorCompileOnBuild=true).BlockPreviewViewResolveronly resolved a view when the.cshtmlfile existed on disk (File.Exists). In a lean/precompiled publish the source files are absent while the views live in the compiled assembly, so resolution short-circuited to "not found".Root cause & tension
The
File.Existsguard was added deliberately in #84: on a case-sensitive file system the runtime view compiler throwsFileNotFoundException(instead of returningSuccess = false) when asked for a view path that isn't on disk. Simply removing the guard would regress #84. The two issues pull in opposite directions:.cshtmlon diskGetViewthrows → needs a guardFile.Existsfalse → butGetViewsafely finds the compiled viewFix — belt and braces
TryResolveViewkeeps the on-disk fast path (exception-free, preserves #84) and adds a guardedGetViewfallback when the file isn't on disk, so precompiled views resolve. The fallback catchesIOExceptionso the #84 runtime-compiler throw can't crash resolution. Behaviour is unchanged for on-disk deployments.Tests
ResolveView_WhenViewIsPrecompiledButNotOnDisk_ResolvesView(Production Website Cannot Find Views #273)ResolveView_WhenRazorEngineThrowsIOException_ReturnsNullWithoutThrowing(Issue finding template on Linux #84 guard)ResolveView_WhenOnlyPascalCaseViewAvailable_ResolvesPascalCaseViewEach was watched fail before implementing (including verifying the guard test fails with the
catchremoved). Full suite: 67 passed, 0 failed. The mock now returns a realisticNotFoundso the resolver is testable throughGetView— the previousFile.Exists-only path was un-mockable and never exercised in tests.End-to-end verification
Published the test site with views precompiled +
.cshtmlexcluded (0 on disk), ran with runtime compilation off, and confirmed in the backoffice that the Block Grid preview rendered real content (heroBlockoutput) with no "view not found" warning and no preview errors server-side — i.e. resolution went through the new precompiled fallback path.Docs
Adds a "Runtime mode and Production deployments" section to
docs/configuration.md. It explains that Umbraco only enables Razor runtime compilation inBackofficeDevelopmentmode, soProduction(andDevelopment) runtime modes require views to be precompiled (RazorCompileOnBuild/RazorCompileOnPublish = true) — without which no Razor view can render, block previews and front-end alike. This is the configuration half of #273 (the default Umbraco template ships with these set tofalse).🤖 Generated with Claude Code