Razor View Templates from a shared DLL?

Imported from the CodePlex archive for reference purposes. Support for MvcCodeRouting has ended.

Commented on
Hey Max,

I have been placing common Controllers into a shared dll for awhile now. Referencing this dll from each of my MVC apps the routing just works great with your infrastructure. I am at a point now where I have some razor templated views that I would like to also keep in that shared dll. Is this possible?

I've read through your 'embedded-resource' and 'extract-views' doc but it is sparse on examples and I can't seem to get this to work. I always get the dreaded 'The view 'MyAction' or its master was not found or no view engine supports the searched locations. The following locations were searched:'

I do have a rootController from the shared dll registered properly with:

routes.MapCodeRoutes(
rootController: typeof(Namespace.SubFolder.Controllers.MyController)
, settings: new CodeRoutingSettings { EnableEmbeddedViews = true }
);
I created a new folder in the shared dll Namespace/SubFolder/Views/MyController and then created a MyAction.cshtml file in that folder. Didn't work, so I checked your doc and tried renaming MyAction.cshtml to Namespace.SubFolder.Views.MyController.MyAction.cshtml and then changed the Build Action to 'Embedded Resource'. That also did not work.

What am I doing wrong? Thanks.
Wade
Commented on link
  • First, make sure you are not using MVC 5.0, there's a bug that makes embedded views not to work. Use 5.1 or greater, or 4.
  • In the shared project, create the Views folder at the root of the project, just like you do in your host MVC app.
  • Create subfolders and views just like you would do in your host app.
  • Set the Build Action to 'Embedded Resource' for each view.
  • On the host app you have to call ViewEngines.Engines.EnableCodeRouting() and use the EnableEmbeddedViews = true setting.
The documentation is a bit confusing, because it is explaining what Visual Studio does for you.
Commented on link
Thanks Max, I reviewed your checklist and got it to work.

For me....

1) I am using MVC 4
2) I moved views folder to root of shared library project
3) Left my subfolder structure intact but moved it to the new root location
4) Build action on view was already set to 'embedded resource' but I double-checked after performing step 3.
5) I had forgotten to mention it in my initial post but I did have those 2 calls already in place

I reran app and it still failed. So I also did the following...

6) Renamed my view from Namespace.SubFolder.Views.MyController.MyAction.cshtml to just MyAction.cshtml.
7) I noticed that (under project properties) my library 'Assembly name' was MyCompany.Shared but my 'Default namespace' was just MyCompany. Once I changed the 'Default namespace' to match 'Assembly name' I reran it and now it works!

Seems my problem must have been some combination of items 2, 6 and 7.

Coolness Max - you've got great support on this great infrastructure.

Wade
Commented on link
Follow-up question Max. In the above scenario where my razor templates are in a shared library as embedded resources I am having a problem with the razor Intellisense. It is not seeing the namespaces I have configured in my MVC project web.config file.

web.config entries at base of Views folder in Mvc application
    <system.web.webPages.razor>
        <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <pages pageBaseType="MyCustomRazorBasePage">
            <namespaces>
                <add namespace="Custom1" />
                <add namespace="Cusotm2" />
                <add namespace="System"/>
                <add namespace="System.Collections"/>
                <add namespace="System.Collections.Generic"/>
                <add namespace="System.Web.Helpers" />
                <add namespace="System.Web.Mvc" />
                <add namespace="System.Web.Mvc.Ajax" />
                <add namespace="System.Web.Mvc.Html" />
                <add namespace="System.Web.Routing" />
                <add namespace="System.Web.WebPages" />
            </namespaces>
        </pages>
    </system.web.webPages.razor>
  <system.web>
    <httpHandlers>
       <add path="routes.axd" verb="GET,HEAD" type="MvcCodeRouting.RouteDebugHandler, MvcCodeRouting" />
    </httpHandlers>
    <pages validateRequest="false" pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=4.0.0.0, Culture=neutral,   PublicKeyToken=31BF3856AD364E35"        pageBaseType="MyCustomRazorBasePage"  userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <controls>
        <add assembly="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
      </controls>
    </pages>
  </system.web>
If I explicitly prefix my references in the template, Intellisense works fine.
Commented on link
You have to use the Web.config in the shared library project, although that file is not meant to be deployed it helps in situations like this.
Commented on link
Made a copy of web.config and moved it into root of shared library project. Cleaned solution, rebuilt and reloaded Visual Studio. VS is still ignoring the namespaces.
Commented on link
Max, please don't waste any time on this. I don't think this is related to your framework. I just created a new project from scratch to contain the shared views, models and controllers. It is working there (and was working on my Shared Library up until this week.

I think something just got out of synch somewhere along the way. At the point, the easiest fix is using this new project and moving over the existing code.

Thanks,
Wade
Commented on link
I was just going to suggest you do exactly that, glad you could figure it out.