Introduction

Two of the greatest additions to the .NET ecosystem the past few years is undoubtedly the NuGet package manager, and the ASP.NET MVC framework. NuGet makes it easy and painless to plug in third-party libraries and functionality into a project. The MVC framework makes it straight-forward and intuitive to create web applications with a proper layering, both horizontally and vertically.

What if you could combine these two technologies to create pluggable “MVC packages” that you can simply drop into an existing web application project? Basically adding a whole sub-application, simply by adding a NuGet package. In this post I will show a simple (albeit proof-of-concept) way to do this.

Creating a packageable MVC application

One of the really cool features of ASP.NET MVC is the concept of areas. Areas were introduced in MVC 2 as a way of partitioning large applications into separate and more manageable chunks. Instead of having all of your various Models, Views and Controllers live in the same /Models, /Views and /Controllers folders, you can separate distinct functional areas into their own area folders. Each “area” is more or less an application in itself: it is separated from any other areas, and has it’s own Models, Views and Controllers. This structure lends itself very well to creating a “pluggable MVC package”.

Create an empty ASP.NET MVC application and add an area (right-click on project, select Add Area). You’ll get a structure like this:

Add a new Controller:

And a View for the Index action:

Hit CTRL+F5, navigate to /Areas/Area51/Aliens, and you’ll get something like this:

Nothing fancy here, just a simple MVC application that gives you a list of some well-known fictional aliens. Now, let’s make it packageable. Make sure you have NuGet.exe in your path or in the MvcApplication1 project root. Add an empty text file to the project root called MvcApplication1.nuspec with the following contents:

<?xml version="1.0"?> <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MvcApplication1</id> <version>1.0.4</version> <title>MvcApplication1</title> <authors>retinalamps</authors> <description>I'm not saying it was aliens, but... it was aliens.</description> </metadata> <files> <file src="bin/MvcApplication1.dll" target="lib" /> <file src="Areas/Area51/Views/**/*.*" target="content" /> </files> </package>

This is a very minimal package specification. The metadata section should be fairly self-explanatory, so I won’t go into that (check the Nuspec reference for details). The files section defines what our package should contain. First, we must of course include the binary. Setting the target to “lib” will make it be added as a reference when we add the package to another project. The second <file> element will include all of the files in the area’s Views folder. Setting the target to “content” will make it be added as content items in the root of the project.

Start a console, go to the root folder of MvcApplication1, and run: NuGet.exe pack MvcApplication1.nuspec

This will generate a NuGet package file with the name MvcApplication1.1.0.4.nupkg. Since we won’t be uploading this package to a remote package repository, move this file to C:\NuGet\ (or some other path of your choice). Then open the Package Manager Settings in Visual Studio, go to Package Sources, and add C:\NuGet\ as a package source:

Adding the package to another MVC application

Create another empty ASP.NET MVC project. Open the NuGet package manager for the project, and choose the local package source you just defined. You should now see the MvcApplication1 package that we created.

Add it to the project. You should now have a reference to MvcApplication1.dll, as well as the Area51 Views in your project.

Set the new project as your start-up project, hit CTRL+F5, and navigate to /Areas/Area51/Aliens. You should now get the same list of aliens that you got when you ran the original project!

Improvements

This is just a proof-of-concept, and admittedly I haven’t tried it out yet in a real production scenario. Some things that are worth exploring that I haven’t yet tried:

Adding the package to a non-MVC web application project. This should work just fine, since WebForms and MVC (and other frameworks like Nancy) can live side-by-side within the same application nowadays. As long as the package specification includes the required MVC dependencies, it shouldn’t be a problem. The areas will also need to be registered at application start. Either you add this manually, or you could add a dependency to WebActivator and do it in a PreApplicationStartMethod.

This should work just fine, since WebForms and MVC (and other frameworks like Nancy) can live side-by-side within the same application nowadays. As long as the package specification includes the required MVC dependencies, it shouldn’t be a problem. The areas will also need to be registered at application start. Either you add this manually, or you could add a dependency to WebActivator and do it in a PreApplicationStartMethod. Adding dependencies to other NuGet packages. If your packaged application depends on some third-party frameworks, you will have to be careful about which range of versions you specify in the Nuspec file. For example, if the packaged application depends explicitly on NLog 2.0.1.2, but the target application depends on NLog 2.1.0+, you will probably run into problems. This can possibly be mitigated by accepting a wider range of versions in the package specification.

I hope you found this little hack to be as cool as I did when I first tried it! If you have any suggestions for improvements, either to the article itself or the solution, please drop a line in the comments!