dotnet / dotnet/aspnetcore

Using WebApplicationFactory precompiled .cshtml views are not found

Open
#64,331 2 comments 0 reactions 0 assignees View on GitHub
area-mvc feature-mvc-testing NativeAOT
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Describe the bug

I have a web application written using .NET9. In this application I am using the Slim Builder to create the web application (intend to do NativeAOT compilation before actual deployment).

In this application I also use Razor views (.cshtml files) that are automatically precompiled into the application assembly. The application runs fine when I just run the application standalone (even when the .cshtml files are not copied to a deployment location). However, when I want to implement integration tests using the `WebApplicationFactory` and request one of the URLs that should invoke a Razor view, the test stops with a `FileNotFoundException` indicating it cannot find the .cshtml file, which is thrown from the code `RazorHelper.RenderViewToStream` method that is listed below.

I render the view myself using code like this (the method is mapped `WebApplication.MapGet`):
```C#
private static Task HandleIndex(HttpContext httpContext,
[FromServices] IRazorViewEngine viewEngine,
[FromServices] ITempDataProvider tempDataProvider)
{
return RazorHelper.RenderView(@"~/Pages/SharedPages/Index.cshtml",
new IndexModel(),
viewEngine,
tempDataProvider);
}

public static class RazorHelper
{
public static async Task RenderView(string viewPath,
TModel model,
IRazorViewEngine viewEngine,
ITempDataProvider tempDataProvider)
{
HttpContext httpContext = model.HttpContext;

using (StreamWriter streamWriter = new(httpContext.Response.BodyWriter.AsStream()))
{
await RenderViewToStream(viewPath,
model,
httpContext.GetRouteData(),
httpContext,
viewEngine,
tempDataProvider,
streamWriter).ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext);
}
}

private static async Task RenderViewToStream(string viewPath,
TModel model,
RouteData routeData,
HttpContext httpContext,
IRazorViewEngine viewEngine,
ITempDataProvider tempDataProvider,
StreamWriter streamWriter)
{
// Create the action context
ActionContext actionContext = new(httpContext,
routeData,
new ActionDescriptor());

// Get the actual view
ViewEngineResult viewEngineResult = viewEngine.GetView(null/*executingFilePath*/,
viewPath,
false/*isMainPage*/);
IView? view;
if (viewEngineResult.Success)
{
view = viewEngineResult.View;
}
else
{
throw new FileNotFoundException($@"Unable to find '{viewPath}'");
}

// Create the model and the view data
ViewDataDictionary viewData = new(new EmptyModelMetadataProvider(),
new ModelStateDictionary())
{
Model = model
};

// Create the view context
ViewContext viewContext = new(actionContext,
view,
viewData,
new TempDataDictionary(httpContext,
tempDataProvider),
streamWriter,
new());

// Render the view
await view.RenderAsync(viewContext).
ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext);
}
}
```

I am wondering why this code works when the ASP.NET core application is running standalone (or is debugged from Visual Studio), but does not work when it is run from an integration test using the `WebApplicationFactory`.

### Expected Behavior

The code above runs both when the application is run, and when doing an integration tests using the `WebApplicationFactory`.

### Steps To Reproduce

_No response_

### Exceptions (if any)

_No response_

### .NET Version

9.0.307

### Anything else?

.NET SDK:
Version: 9.0.307
Commit: 3bc3012cf9
Workload version: 9.0.300-manifests.6f9c3023
MSBuild version: 17.14.28+09c1be848

Runtime Environment:
OS Name: Windows
OS Version: 10.0.22631
OS Platform: Windows
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\9.0.307\

.NET workloads installed:
[maui-windows]
Installation Source: VS 17.14.36705.20
Manifest Version: 9.0.111/9.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\9.0.100\microsoft.net.sdk.maui\9.0.111\WorkloadManifest.json
Install Type: Msi

[maccatalyst]
Installation Source: VS 17.14.36705.20
Manifest Version: 26.0.9752/9.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\9.0.100\microsoft.net.sdk.maccatalyst\26.0.9752\WorkloadManifest.json
Install Type: Msi

[android]
Installation Source: VS 17.14.36705.20
Manifest Version: 35.0.78/9.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\9.0.100\microsoft.net.sdk.android\35.0.78\WorkloadManifest.json
Install Type: Msi

[ios]
Installation Source: VS 17.14.36705.20
Manifest Version: 26.0.9752/9.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\9.0.100\microsoft.net.sdk.ios\26.0.9752\WorkloadManifest.json
Install Type: Msi

[aspire]
Installation Source: VS 17.14.36705.20
Manifest Version: 8.2.2/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.aspire\8.2.2\WorkloadManifest.json
Install Type: Msi

Configured to use loose manifests when installing new manifests.

Host:
Version: 9.0.11
Architecture: x64
Commit: fa7cdded37

.NET SDKs installed:
5.0.416 [C:\Program Files\dotnet\sdk]
9.0.307 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
Microsoft.AspNetCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.22 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 9.0.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.22 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 9.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.22 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 9.0.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
x86 [C:\Program Files (x86)\dotnet]
registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
Not set

global.json file:
C:\_MVS\personal.NET\global.json

Learn more:
https://aka.ms/dotnet/info

Download .NET:
https://aka.ms/dotnet/download

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.