I am trying to make a modular architecture using ASP.Net Core 2.2 and MVC. Essentially I have a base ASP.Net Core 2.2 web app. And then I want to keep adding class libraries to act as features to my app. I am routing to these features by configuring AreaViewLocationFormats. My Class Libraries are targeting SDK - Microsoft.NET.Sdk.Razor. On Build I do see .Views.dll and my base app is able to scan these and add to the application factory.
At the app start up I am scanning dlls and Views.dll of these class libraries and then adding them to the application parts like this (I have simplified this so that I can share):
foreach (var file in plugInFolder.GetFileSystemInfos("*.dll", SearchOption.AllDirectories))
{
Assembly assembly;
try
{
assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(file.FullName);
}
catch (FileLoadException ex)
{
// If assembly is already loaded, we'll just catch it and continue to the next one, plugins can have same dependencies:
if (ex.Message == "Assembly with same name is already loaded")
{
continue;
}
throw;
}
//If its a View Assembly then we need to load it differently:
if (assembly.FullName.Contains(".Views"))
{
mvcBuilder.ConfigureApplicationPartManager(mgr => {
foreach (var b in CompiledRazorAssemblyApplicationPartFactory.GetDefaultApplicationParts(assembly))
{
mvcBuilder.ConfigureApplicationPartManager(apm => apm.ApplicationParts.Add(b));
}
});
}
// If plugin hasn't been loaded already
else if (!plugins.ContainsKey(pluginFolder.Name) && // plug in isn't loaded already and
pluginFolder.Name == assembly.GetName().Name) // plug in Name matches Folder Name {Our convention}
{
plugins.Add(pluginFolder.Name, new PlugInInfo { Name = pluginFolder.Name, Assembly = assembly, Path = pluginFolder.PhysicalPath });
//plugin load:
mvcBuilder.AddApplicationPart(assembly);
}
}
The issue is with the Views.dll in that they have below weird attributes(checked via ILSpy) :
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RazorCompiledItem(typeof(Views_Home_Index), "mvc.1.0.view", "/Views/Home/Index.cshtml")]
[assembly: RazorView("/Views/Home/Index.cshtml", typeof(Views_Home_Index))]
I think that because of the "/Views/Home/Index.cshtml" in above compilation I can only call my views if I use
return View("/Views/Home/Index.cshtml")
The issue with that is - I can't use the same Views-Home-Index naming with other class libraries. For now, I can work around without precompiling views and using cshtml files. But I wanted to have the advantage of pre-compiled views. I have referred to MS docs for Razor SDK but failed to get appropriate help or may be I missed something. Is there anything I can do to fix these names of the compiled Views? Please guide.
I believe that naming is coming from the location of the View per MVC convention but I want to be able to call my view by
return View("<FeatureName>/Views/Home/Index.cshtml");
But currently it only works with:
return View("Views/Home/Index.cshtml");
I reached out to aspnet core team and I have an answer. Please refer following if you are also stuck here and upvote my question :) https://github.com/aspnet/AspNetCore/issues/7112