I have a large MVC 4 site that is split into one project per MVC area. We use RazorGenerator to precompile all of our views into a project assembly to deploy and use PrecompiledMvcEngine for our ViewEngine .
I just created a new area in which I would like to share Shared views from another assembly, but when I try to find Partial View I get an InvalidOperationException and none of the DisplayTemplates or EditorTemplates are found either.
I find this to be similar to the problem described in this question .
My code in RazorGenerator App_Start is as follows:
var assemblies = new List<Tuple<string, Assembly>>() { Tuple.Create("Areas/Area1", typeof(ABC.Project1.AreaRegistration).Assembly), Tuple.Create("Areas/Area2", typeof(ABC.Project2.AreaRegistration).Assembly), };
When I come across a partial link in a view in Area2, for example @Html.Partial("Partials/Footer") , I get an exception. Razor seems to be looking for the right way
System.InvalidOperationException: The partial view 'Partials/Footer' was not found or no view engine supports the searched locations. The following locations were searched: ~/Areas/Area2/Views/Home/Partials/Footer.cshtml ~/Areas/Area2/Views/Shared/Partials/Footer.cshtml ~/Views/Home/Partials/Footer.cshtml ~/Views/Shared/Partials/Footer.cshtml ~/Areas/Area1/Views/Shared/Partials/Footer.cshtml at System.Web.Mvc.HtmlHelper.FindPartialView(ViewContext viewContext, String partialViewName, ViewEngineCollection viewEngineCollection)
If you look at the source code of PrecompiledMvcEngine , it looks only for viewing in the assembly.
Initially, I thought that the viewer would consider all registered ViewEngines when trying to resolve the path, but this seems like a wrong assumption (and I can understand why not to).
Is there a way to share views across multiple assemblies?
Update
I worked on the issue by creating a custom version of PrecompiledMvcEngine , which takes a list of assemblies in its constructor. The main change:
_mappings = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase); foreach (var kvp in assemblies) { var baseVirtualPath = NormalizeBaseVirtualPath(kvp.Key); var assembly = kvp.Value; var mapping = from type in assembly.GetTypes() where typeof(WebPageRenderingBase).IsAssignableFrom(type) let pageVirtualPath = type.GetCustomAttributes(inherit: false).OfType<PageVirtualPathAttribute>().FirstOrDefault() where pageVirtualPath != null select new KeyValuePair<string, Type>(CombineVirtualPaths(baseVirtualPath, pageVirtualPath.VirtualPath), type); foreach (var map in mapping) { _mappings.Add(map); } }
Any better alternative or pitfalls with this approach?