title: RazorGenerator PrecompiledMvcEngine cannot locate Partial View or Editor Templates across assemblies
body: <p>I have a large MVC 4 site that is broken into one project per MVC Area.  We use RazorGenerator to pre-compile all of our views into the project assembly for deployment and use the <code>PrecompiledMvcEngine</code> for our <code>ViewEngine</code>.</p>
  
  <p>I have just created a new Area that I would like to share the <code>Shared</code> views from another assembly, but I get an <code>InvalidOperationException</code> when trying to locate a Partial View and none of the DisplayTemplates or EditorTemplates appear to be found either.</p>
  
  <p>I believe it is similar to the issue described in <a href="https://stackoverflow.com/questions/13527354/razor-generator-how-to-use-view-compiled-in-a-library-as-the-partial-view-for-m">this question</a>.</p>
  
  <p>My code in the RazorGenerator App_Start is like this:</p>
  
  <pre class="lang-cs prettyprint-override"><code>var assemblies = new List&lt;Tuple&lt;string, Assembly&gt;&gt;()
  {
      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);
  }
  </code></pre>
  
  <p>When I encounter a partial reference in a view within Area2 like <code>@Html.Partial("Partials/Footer")</code>, I get the exception.  It appears that Razor is looking for the correct path</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>Looking at the source code of the <code>PrecompiledMvcEngine</code>, it appears that it only looks for views within the assembly.</p>
  
  <p>I initially thought that the view system would look across all registered ViewEngines when trying to resolve a path, but that seems to be an incorrect assumption (and I can see why one would not do that).</p>
  
  <p>Is there a way to share the views across multiple assemblies? </p>
  
  <p><strong>Update</strong></p>
  
  <p>I've worked around the issue by creating a custom version of the <code>PrecompiledMvcEngine</code> that takes a list of assemblies in its constructor.  The core change is this:</p>
  
  <pre class="lang-cs prettyprint-override"><code>_mappings = new Dictionary&lt;string, Type&gt;(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&lt;PageVirtualPathAttribute&gt;().FirstOrDefault()
          where pageVirtualPath != null
          select new KeyValuePair&lt;string, Type&gt;(CombineVirtualPaths(baseVirtualPath, pageVirtualPath.VirtualPath), type);
  
      foreach (var map in mapping)
      {
          _mappings.Add(map);
      }
  }
  </code></pre>
  
  <p>Any better alternative or pitfalls with this approach?</p>