22

I want to share the layout (Header, Navigation and Footer Razor views) across multiple ASP.NET MVC projects. How can I do that?

Can I create a custom NuGet package to wrap the common Razor files, images and CSS?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
VJAI
  • 32,167
  • 23
  • 102
  • 164

3 Answers3

23

I've hit this more than once via Google now, and though I'd pose another solution (which, IMO, is much safer and more manageable than using precompilers and packages).

In fact, I've shamelessly scraped verbatim an answer from Erik Phillips, so please, credit to him.

what he said... (he says this for javascript files in particular, but this works just as well with any other types) source answer

Here is what I would recommend:

Right click the solution and create a New Solution Folder called Common Javascript Files (or whatever you feel like calling it.

New Solution Folder

Common Javascript Files Solution Folder

Right click on the Solution, click Open Folder in Windows Explorer, or navigate there manually for other versions of Visual Studio :(

Open Folder In Windows Explorer

In the solution directory, create a directory with the same name as the solution folder (solution folders do not normally match directories at the source code level but this will for sanity sake).

Common Javascript Files Directory

In this new directory, add files that need to be shared between solutions.

Add Javascript Files To Directory

In Visual Studio, click the solution folder and select Add - Existing Item.

Visual Studio Add - Existing Itme

In the file selection dialog, navigate to the directory previous created, select the file(s) added to the directory and click Add.

Select Files To Add

Solution Folder Files

In each Project that needs a shared file, right click on the project (or directory within the project) and click Add - Existing Item.

Project Add Existing Item

Navigate to the shared Directory, Select the files and click the drop down arrow then click Add As Link.

Add As Link

Now the files in the projects are essentially short cuts to the files in the Solution Folder. But they are treated as actual files in the project (this includes .CS or Visual Basic files, they will be compiled as files that actually exist in the project).

Linked Files

PROS

  • Files are truly shared across projects at Design time
  • Only the files needed for each project can be added, it's not all or nothing
  • Does not require any configuration in IIS (virtual directory etc)
  • If the solution is in TFS Source control, you can add the Directory to the TFS Source and the shared files will be source controlled.
  • Editing a file by selecting it in the Project, will edit the actual file.
  • Deleting a Linked file does not delete the file.
  • This is not limited to JS files, linked files can be ANY file you might need (Images, Css, Xml, CS, CSHTML, etc)

CONS

  • Each deployment gets it's own file.
  • There is a small learning curve when understanding that Solution Folders are not Directories that exist in a Solution Directory.

AND - stealing from one more answer to consolidate info, here's how you get these to output for debugging (taken from comment below the scraped answer, link to blog post for build target for output for debugging)

Add this to each consuming project's .csproj file:

  <Target Name="CopyLinkedContentFiles" BeforeTargets="Build">
    <Copy SourceFiles="%(Content.Identity)" 
          DestinationFiles="%(Content.Link)" 
          SkipUnchangedFiles='true' 
          OverwriteReadOnlyFiles='true' 
          Condition="'%(Content.Link)' != ''" />
 </Target>
Community
  • 1
  • 1
jleach
  • 7,410
  • 3
  • 33
  • 60
  • @ErikPhilips - FYI, I've copied your answer from another post to here... wasn't quite sure how to handle it, thus: http://meta.stackoverflow.com/questions/323545/stealing-someones-answer/323550 – jleach May 22 '16 at 13:29
  • 4
    pinging someone on a post they haven't participated in doesn't work. If you want ErikPhilips to see this comment, you'd have to ping him on his original answer – psubsee2003 May 22 '16 at 20:07
  • 1
    Just wanted to comment that a disadvantage of this method is that if you edit a linked file you have to restart the project to test it - so it can be pretty tiresome to e.g. edit a CSS file to try things out which would normally be shown immediately with a refresh of the browser. – Johncl Aug 14 '16 at 14:05
  • 6
    When I add cshtml files as links, there's no intellisense and VS treats it like all Razor is "broken" with red lines under any code. I still haven't figured out how to work around that http://stackoverflow.com/questions/41511770/add-as-link-intellisense-for-views – Duderino9000 Jan 06 '17 at 23:43
  • 2
    @jleach, et al - Has anybody tried this method for MVC Razor views? The question is about Razor views in particular, so it'd be fitting to list the pros & cons of using this approach for those specifically. – Sean Jan 11 '19 at 18:32
  • Well done, I really like this alternative approach. Thanks for the well detailed info. Was just what I was looking for and wondering myself. – Edd Jan 05 '20 at 18:28
15

Three approaches:

  1. Share the Razor view source code using your version control system
  2. Compile the views into a separate DLL file for binary sharing.
  3. Create a NuGet package

See Compile your ASP.NET MVC Razor views into a separate DLL for how you do option 2.

For option 3, see Creating and Publishing a Package.

In fact, I think this is the original article on how to compile Razor views: Precompile your MVC Razor views using RazorGenerator

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Paul Taylor
  • 5,651
  • 5
  • 44
  • 68
  • Can I use Nuget here? I'm thinking about creating a custom nuget package. But not sure if that's the right option. – VJAI Dec 17 '13 at 10:43
  • With reference to the second article above, yes, it's on NuGet, currently called RazorGenerator.Mvc. – Paul Taylor Dec 17 '13 at 10:46
  • You misunderstood me. What I meant was, creating my own nuget package that packs all the razor files, css, images. In whatever MVC project I need the common layout, I'll install this custom nuget package. – VJAI Dec 17 '13 at 10:51
  • Sure you can, but that's a separate question (or maybe a third option): I'll include it above – Paul Taylor Dec 17 '13 at 10:52
  • 2
    @Mark: I wouldn't use a Nuget package unless you're sharing between projects in different solutions. If your projects are all in the same solution, just add a simple reference. Also, the CSS, images, etc. would be better placed on a static domain that each project could just pull from, if they're truly shared and not customized at all per project. – Chris Pratt Dec 17 '13 at 15:32
  • @ChrisPratt They all in different solutions – VJAI Dec 17 '13 at 18:12
  • 3
    Another way to do it would be through VS Build Events (project -> properties -> Build Events) - add some script to simply copy the View source file to your MVC project(s) View directory. – sming Apr 01 '15 at 14:07
  • 1
    [RazorGenerator](https://github.com/RazorGenerator/RazorGenerator/issues) has moved to github for anyone searching. – crush Jun 23 '15 at 17:37
0

There are new options (IMHO) better available. I would take advantage of organizing it as Feature splices in ASP MVC Core, this would save a lot of time down the road, I would recommend it in 2 steps.

  1. First, organize/put it an area called Features splices MSDN ref. wire it up as in the article and well explained.

    // you're telling ASP that you've other Feature areas that it should look
    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context,
        IEnumerable<string> viewLocations)
    {
        // Error checking removed for brevity
        var controllerActionDescriptor = context.ActionContext.ActionDescriptor as ControllerActionDescriptor;
        string featureName = controllerActionDescriptor.Properties["feature"] as string;
        foreach (var location in viewLocations)
        {
            yield return location.Replace("{3}", featureName);
        }
    }
    
  2. Second, embed Features in a Shared project or Portable Libraries. I have attached links on how to do this from R. Williams and MSDN.

In summary, since you already have it in a common area consider it to be a feature and embed it inside a portable lib or a Shared Project. A nice article by R. Williams.

enter image description here

Cerbrus
  • 70,800
  • 18
  • 132
  • 147
Transformer
  • 6,963
  • 2
  • 26
  • 52
  • 1
    The downside of sharing views via Shared Project also seems to be that ASP.NET MVC 5 (old stack) doesn't like it. Razor pukes with an error that relative path to the shared project is not valid (even though it shows an absolute path in the error message). I have found out just yet how to resolve this. Anyone any ideas, links? – Manfred Apr 09 '18 at 21:42