RazorGenerator PrecompiledMvcEngine cannot find partial view templates or editor in assemblies

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), }; // Get rid of the default view engine ViewEngines.Engines.Clear(); foreach ( var assembly in assemblies ) { var engine = new PrecompiledMvcEngine(assembly.Item2, assembly.Item1) { UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal }; // Allow sharing of Area1 Shares views with Area2 if (assembly.Item1 == "Areas/Area2") { var sharedPaths = new[] { "~/Areas/Area1/Views/Shared/{0}.cshtml" }; engine.ViewLocationFormats = engine.ViewLocationFormats.Concat(sharedPaths).ToArray(); engine.MasterLocationFormats = engine.MasterLocationFormats.Concat(sharedPaths).ToArray(); engine.PartialViewLocationFormats = engine.PartialViewLocationFormats.Concat(sharedPaths).ToArray(); } ViewEngines.Engines.Insert(0, engine); VirtualPathFactoryManager.RegisterVirtualPathFactory(engine); } 

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?

+6
source share

Source: https://habr.com/ru/post/950107/


All Articles