Reputation: 27328
Scenario:
It works fine but when publish the app with precompiled views, the FindView from the link above methods returns null.
Steps to reproduce:
How do I find and render precompiled view at runtime?
Upvotes: 1
Views: 1556
Reputation: 177
I could not understand why, but in the console application, AddMvc()
skips one configuration step - it does not add a provider that retrieves precompiled views from assembly.
In my case I use console app (net472) and Razor class library and put RazorViewToStringRenderer
in this library.
To add the provider, we need to do the following
var viewAssembly = Assembly.Load(typeof(RazorViewToStringRenderer).Assembly.GetName().Name + ".Views");
var viewAssemblyPart = new CompiledRazorAssemblyPart(viewAssembly);
services.AddMvc().PartManager.ApplicationParts.Add(viewAssemblyPart);
After this steps RazorViewToStringRenderer
works perfect.
Upvotes: 3
Reputation: 3074
I'm using the same code in a web project and I had to add the complete directory info to the GetView attempt. The FindView method works (without precompilation) with the View or CSHTML extension. But the GetView needs both and always works (with and without precompilation of views)
var getViewResult = _viewEngine
.GetView(
executingFilePath: null,
viewPath: $"/Views/{viewName}.cshtml",
isMainPage: true);
Upvotes: 1
Reputation: 31282
The easiest fix would be disabling of precompiled views during the publish. If it is an option, then just set MvcRazorCompileOnPublish
to false
in csproj file
<PropertyGroup>
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
</PropertyGroup>
If however you want to use precompiled views, then you need to make several fixes in ConfigureDefaultServices
method.
First of all, move services.Configure<RazorViewEngineOptions>
call after AddMvc()
. Otherwise you override RazorViewEngineOptions
configuration setup added by AddMvc()
and it will not be filled with required data (the job performed by RazorViewEngineOptionsSetup).
After this fix basic rendering will work however partial views and layout will not be located by Razor Engine. To fix this, you need to add location format without controller name (/Views/{0}.cshtml
) to RazorViewEngineOptions.ViewLocationFormats
collection.
After described fixes rendering based on precompiled views works fine for me. Here is corrected ConfigureDefaultServices
method:
private static void ConfigureDefaultServices(IServiceCollection services, string customApplicationBasePath)
{
string applicationName;
IFileProvider fileProvider;
if (!string.IsNullOrEmpty(customApplicationBasePath))
{
applicationName = Path.GetFileName(customApplicationBasePath);
fileProvider = new PhysicalFileProvider(customApplicationBasePath);
}
else
{
applicationName = Assembly.GetEntryAssembly().GetName().Name;
fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());
}
services.AddSingleton<IHostingEnvironment>(new HostingEnvironment
{
ApplicationName = applicationName,
WebRootFileProvider = fileProvider,
});
var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
services.AddSingleton<DiagnosticSource>(diagnosticSource);
services.AddLogging();
services.AddTransient<RazorViewToStringRenderer>();
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationFormats.Add("/Views/{0}.cshtml");
options.FileProviders.Clear();
options.FileProviders.Add(fileProvider);
});
services.AddMvc();
}
Upvotes: 1