Scott Hanselman

Creating a NuGet Package in 7 easy steps - Plus using NuGet to integrate ASP.NET MVC 3 into existing Web Forms applications

February 15, '11 Comments [33] Posted in ASP.NET | ASP.NET MVC | NuGet | VS2010
Sponsored By

UPDATE: Check out my follow up post where I remove the need for editing the Global.asax.cs and show up to Update and Publish a NuGet package.

Last month I wrote a post called Integrating ASP.NET MVC 3 into existing upgraded ASP.NET 4 Web Forms applications where I showed a very manual and very painful way to add ASP.NET MVC support to an existing ASP.NET WebForms application. You'd then have a lovely hybrid that is both MVC and WebForms.

One of my readers, Yannick said:

This screeaaams NuGet

Indeed it did, er, does. He's saying that this is just the kind of awful boring work that NuGet should make easier. So I did it. Thanks Yannick for just the sassy comment I needed to jump into action.

install-package AddMvc3ToWebForms

First, what I built, then how I built it. I'd like you, Dear Reader, to take a moment and create your own NuGet packages.

Adding ASP.NET MVC to an ASP.NET WebForms project with NuGet

Step 0 - Get NuGet 1.1 by going here. It's like 300k, just take a second.

Step 1 - Open Visual Studio 2010 and make a default ASP.NET (WebForms) Application.

VS2010 Default WebForms App

Step 2 - Right click on References and click Add Library Package Reference. Click Online on the left side, and in the Search box at upper right type in "WebForms" and look for my face. Oh yes. My face. Click Install.

(Alternatively, open the Package Manager Console and type "install-package AddMvc3ToWebForms" and watch the magic. The package is hosted on NuGet.org. You can too!)

Add Library NuGet Dialog

Step 2a - Check out the stuff that's been added to your project.

WebForms app with MVC bits integrated

What's that HookMeUpNow.cs? That's all the routing stuff that I would have needed to edit your Global.asax.cs for. You'll need to add one line of code to Global.asax yourself to make this work now.

Step 3 - Hook up Routes and Everything

Add Mvc3Utilities.RegisterEverything() to your Application_Start. Feel free to rename whatever you like.

Added Mvc3Utilities.RegisterEverything() to the Global.asax

Now run it. You can hit both Default.aspx and /Home/About.

WebForms and MVC together in the same app, shown in the browser

Step 4 - Profit!

Sweet.

How I made my own NuGet package and you should too

Step 0 - Go get the NuGet.exe command line here. Put it in the Path or somewhere.

Step 1 - Make a folder for your new package, go there via the commmand line and run "nuget spec"

C:\Users\Scott\Desktop\AddMvc3ToWebForms>nuget spec
Created 'Package.nuspec' successfully.

C:\Users\Scott\Desktop\AddMvc3ToWebForms>dir Package.nuspec
Directory of C:\Users\Scott\Desktop\AddMvc3ToWebForms

02/15/2011  02:23 AM               813 Package.nuspec
               1 File(s)            813 bytes

Now, I changed this file's name and edited it thusly.

<?xml version="1.0"?>
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<id>AddMvc3ToWebForms</id>
<version>0.4</version>
<authors>Scott Hanselman</authors>
<owners>Scott Hanselman</owners>
<iconUrl>http://www.hanselman.com/images/nugeticon.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A totally unsupported way to quickly add ASP.NET MVC 3 support to your WebForms Application. Works on my machine.</description>
<tags>MVC MVC3 ASP.NET WebForms</tags>
</metadata>
</package>

Step 2 - Add stuff to your Content Folder

Since I want my NuGet package to add stuff to folders in my target Web Application, I put whatever I want in a folder called Content. Anything in that will show up in the root of my target project. This can be CSS, JS, CS or VB files, whatever. These files will all get dropped onto the project your package is applied to.

In my project I took the folders from an MVC application and put them in my NuGet folder structure. So, Content, Controllers, Models, Scripts, Views. Copied them right over from an existing blank ASP.NET MVC project.

My NuGet directory where I'm building the package

Step 3 - Decide what needs to be Pre-Processed

However, when my HomeController shows up in your project, Dear Reader, I don't want it to be in the namespace ScottMvcApplication! You want it in MvcApplication54 or whatever your project name is. I need pre-process the source a little to use your project's context, names, namespaces, etc.

For the files I want pre-processed automatically by NuGet, I add a .pp extension. In my example, HomeController.cs.pp.

Preprocessor files with a .pp extension

Then I add a few tokens I want replaced at install-time for that package. For example $rootnamespace$ or $assemblyname$. You can use any Visual Studio Project Property per the NuGet docs.

namespace $rootnamespace$.Controllers
{
public class HomeController : Controller
{
//snip
}
}

Step 4 - Decide what XML elements need to be merged (usually into web.config)

The next preprocessing that is common is adding elements to web.config. This is a nice little feature of NuGet because you just need to make a web.config.transform with the new elements and it will automatically and non-destructively add (and remove) them as needed. Here's my web.config.transform, for reference. Note this is not a full web.config. This is the one I added to my package in the control folder.

<configuration>
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>

<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>
<pages>
<namespaces>
<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>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>

<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

Step 5 - Add any PowerShell script you might need, especially for adding references

Almost done. Most package won't need much PowerShell, but some do. You can have an install.ps1 and an uninstall.ps1 and do lots of things. These go in a folder called Tools that's next to Content (not inside.)

Here's my install.ps1.

NOTE: Currently today there's no way to STOP the installation of a package while it's happening, so if you try to install mine on NuGet 1.0 I'll just warn you and ask you to uninstall. In the future there will likely be a pre-install or a dependency check. Hence the version check there.

param($installPath, $toolsPath, $package, $project)

if ($host.Version.Major -eq 1 -and $host.Version.Minor -lt 1)
{
"NOTICE: This package only works with NuGet 1.1 or above. Please update your NuGet install at http://nuget.codeplex.com. Sorry, but you're now in a weird state. Please 'uninstall-package AddMvc3ToWebForms' now."
}
else
{
$project.Object.References.Add("Microsoft.CSharp");
$project.Object.References.Add("System.Web.Mvc");
$project.Object.References.Add("Microsoft.Web.Infrastructure");
$project.Object.References.Add("System.Web.WebPages");
$project.Object.References.Add("System.Web.Razor");
$project.Object.References.Add("System.ComponentModel.DataAnnotations");
}

Note that in (the future) NuGet 1.2 I won't need this code, I'll just add the references in my NuSpec file directly.

Step 6 - Pack it up

Go back to the command line and run nuget pack

C:\Users\Scott\Desktop\AddMvc3ToWebForms>nuget pack
Attempting to build package from 'AddMvc3ToWebForms.nuspec'.
Successfully created package 'C:\Users\Scott\Desktop\AddMvc3ToWebForms\AddMvc3ToWebForms.0.4.nupkg'.

Step 7 - Submit your package

Next, login to the NuGet Gallery (beta) and Contribute Your Package. Just walk through the wizard and upload the nupkg. You can also get an API Key and use the command line tool to do this automatically, perhaps as part of a build process.

Submitting my app to the NuGet Gallery

That's it. If you've got an open source library or something interesting or useful, get it up on NuGet before your blog commenters shame you into it!

P.S. Yes I didn't count Step 0.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Tuesday, February 15, 2011 10:59:19 AM UTC
You should say your younger face, your current face looks, uhm... more distinguished.
Tuesday, February 15, 2011 11:06:03 AM UTC
Great post Scott, thanks. Nice to see a blog post on creating packages following Phil Haack's MVC Conf session about NuGet. One minor thing... step 0 says get the NuGet command line tool here, but there's no hyperlink.
yeurch
Tuesday, February 15, 2011 11:48:40 AM UTC
Fixed the bad link.
Tuesday, February 15, 2011 6:19:38 PM UTC
Yannick will be soooooo happy.
Sanjeev Mundluru
Tuesday, February 15, 2011 8:53:29 PM UTC
The nuget package feed isn't serving any data - http://packages.nuget.org/v1/FeedService.svc/ ???
Tuesday, February 15, 2011 9:46:18 PM UTC
Error 87 The type or namespace name 'GlobalFilterCollection' could not be found (are you missing a using directive or an assembly reference?) c:\users\jeroen\documents\visual studio 2010\Projects\WebForms\WebForms\HOOK ME UP NOW.cs 16 48 WebForms
Wednesday, February 16, 2011 1:07:28 AM UTC
Works great! Except ... the application is not an MVC app insofar as Visual Studio is concerned, i.e. the context menus don't work. That is, if I right click on the "Controllers" folder, the magical "Add Controller" link doesn't appear.

I'm thinking I can hand-edit the .csproj file to hack in the project type GUID, but hopefully there's a better way. (And if I am adding a project type GUID, that suggests that your NuGet package can do the same, hint hint...)
Wednesday, February 16, 2011 1:15:03 AM UTC
Woot! I added the GUID {E53F8FEA-EAE0-44A6-8774-FFD645390401} to the ProjectTypeGuids node of the .csproj, and it's a bone fide MFC project with context menus in the Solution Explorer.

This is the result, with the new GUID underlined:

    <ProjectTypeGuids>{E53F8FEA-EAE0-44A6-8774-FFD645390401};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
Wednesday, February 16, 2011 1:29:21 AM UTC
Oops, it's a bona fide MVC project (not any type of bone project or MFC project).
Wednesday, February 16, 2011 2:37:27 AM UTC
James - Yes, I need to figure out how to add that Guid from Powershell. The tooling needs to see it.

Efosa - You sure it's not your browser?

Jeroen - Did I miss a using statement? What did you find?
Wednesday, February 16, 2011 3:21:21 AM UTC
What a wonderful little tutorial, i shall be trying this out later on today, thank you for your expertise
Wednesday, February 16, 2011 9:22:40 AM UTC
Could you not fix your global.asax issues with WebActivator/PreApplicationStartMethod ?
Betty
Wednesday, February 16, 2011 5:50:44 PM UTC
Have you ever tried something that you just couldn't get working properly I have now idea what I was doing wrong until now I could never get MVC and WebForms to work together. Way to go!!!!
both technology's have so many strong points on their own platform it seems logical to use both
All I had to do was install the package and add Mvc3Utilities.RegisterEverything(); in the Global.asax

Thanks Love your talks by the way great stuff very informative and entertaining
Keep up the good work
Wednesday, February 16, 2011 11:24:40 PM UTC
And the screaming subsides and the world is in balance as Scott puts this task in its proper place as a Nuget package.

Very cool Scott!!! It makes me happy.
Thursday, February 17, 2011 2:56:52 AM UTC
So, let's say that I have been using a open source library; but there is no NuGet package for it, am I able to create and upload a package for this library even though I am not the owner of the open source project?
Tyrone
Thursday, February 17, 2011 3:07:41 AM UTC
Turns out I was wrong, can't register areas in PreApplicationStart. Works fine for routes though.
Betty
Thursday, February 17, 2011 12:12:37 PM UTC
Hmm. I get 'This package (or one of its dependencies) contains PowerShell scripts and needs to be installed from the Package Manager Console.' I ran the 'install-package' command and everything looks sweet though.
Thursday, February 17, 2011 4:35:59 PM UTC
Could only get this to work for a C# site, not a VB one .. any ideas?
Thursday, February 17, 2011 5:07:19 PM UTC
Scott, Great idea.

Feature requests:
Your NuGet description needs a slight tweak. A better word choice that "application" in which could be confused with MVC3 bin application deployment, would be...

Also, please oh please put together an MVC3 bin application deployment Nuget.
Thursday, February 17, 2011 5:07:59 PM UTC
Kori Francis - There's a guy doing a VB version now.

Phil - Get the new NuGet 1.1?

Betty - I'm going to do a follow up that solves that problem and makes things totally drop in.
Thursday, February 17, 2011 9:04:05 PM UTC
Nice post. This totally rocks and covers a lot of ground here. I'm almost tempted to secretly bump up all web apps around here to ASP.NET MVC3 and watch the hilarity ensue.
Thursday, February 17, 2011 9:06:08 PM UTC
Would be great if it worked, but...
I get the following error on a clean new install of NuGet 1.1 and a new ASP.NET Web Application project

Any ideas?
Brinkie

PM> install-package AddMvc3ToWebForms
Successfully installed 'AddMvc3ToWebForms 0.5'.
Successfully added 'AddMvc3ToWebForms 0.5' to WebApplication1.
Install-Package : Exception calling "Add" with "1" argument(s): "Unspecified error (Exception from HRESULT: 0x80004005 (E_FAIL))"
At line:1 char:16
+ install-package <<<< AddMvc3ToWebForms
+ CategoryInfo : NotSpecified: (:) [Install-Package], MethodInvocationException
+ FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.Cmdlets.InstallPackageCmdlet
Thursday, February 17, 2011 10:18:05 PM UTC
My bad! Appearantly that's the outcome of not having MVC3 pre-installed. After installing MVC3 the process worked like a charm.

Having this NuGet package makes it so much easier to migrate an existing ASP.NET Web Forms application to ASP.NET MVC3 at an easy pace.

Scott, nice job!
Tuesday, February 22, 2011 10:42:30 PM UTC
still running asp.net 3.5 - I'm getting this - any ideas?

'WebActivator 1.1.0.0' already installed.
'AddMvc3ToWebForms 0.6' already installed.
Unable to find assembly references that are compatible with the target framework '.NETFramework,Version=v3.5'.

Friday, February 25, 2011 8:02:35 PM UTC
Very handy article and NuGet package!!! Thank you!
AlexB
Monday, March 14, 2011 10:33:15 PM UTC
We have some functionality to bring bing maps to various LOB applications my team supports. right now we have problems because sometimes we find an issue in this common block and we forget to sync it back to the master for other apps to pickup and update to other client apps. Does it seem logical that NuGet could be means of at least publishing that common code ?
Thursday, June 09, 2011 2:04:38 PM UTC
Hello,

My attempt fails at the last step. It always says project unavailable. When I look at the solution, I can see that some of the MVC items were added. ie Controllers, Views etc.. I do not see HookMeUpNow.cs. If I right click within the controllers folder I have the option to add a new controller. So I believe the package was partially implemented.

Is there any way to try to finish this package by hand?
-- ie Make the change to the global.asax
-- and add the missing HookMeUpNow.cs.

Is there anything else that I may need that might not have been impemented??

Thanks for your help.
Thursday, June 16, 2011 7:16:51 PM UTC
Don - I've since updated the package. I think HookMeUpNow was actually moved into App_Start and renamed. Can you hit /home/about? If you can, it's working for you.
Tuesday, June 21, 2011 9:41:03 AM UTC
Hello,

I created a webforms application and then ran the AddMvc3ToWebForms. At the end i get an error message saying "Project unavailable. Rolling back". Am I missing something?

Attempting to resolve dependency 'WebActivator (≥ 1.3)'.
Successfully installed 'WebActivator 1.3.2'.
Successfully installed 'AddMvc3ToWebForms 0.9.1'.
Successfully added 'WebActivator 1.3.2' to MvcAspFormsMergeProject.
Successfully added 'AddMvc3ToWebForms 0.9.1' to MvcAspFormsMergeProject.
Executing script file 'C:\Test\MvcAspFormsMergeProject\packages\AddMvc3ToWebForms.0.9.1\tools\install.ps1'.
Install failed. Rolling back...
Project unavailable.

I have nuget ver. 1.4
Monday, July 11, 2011 8:44:04 PM UTC
Same thing as Robin here. Roll back isn't happening btw but you're left with a project that doesn't compile.

"The type or namespace name 'MvcApplication1' could not be found (are you missing a using directive or an assembly reference?)"
Thursday, August 04, 2011 2:57:26 AM UTC
Hi Yannick

I've just put the steps to get this awesome package working with a web site rather than application at http://delradiesdev.blogspot.com/2011/08/adding-mvc-3-to-aspnet-web-site.html

Hope this helps

Mark (@delradie)
Thursday, August 18, 2011 11:05:03 PM UTC
@yannick.

I had the same issues as you stated about however I just deleted the pre-made controllers, and views and created a new controller and view and everything compiled and ran properly.

From what I could see is it was a namespace issue, as in my project I had <rootnamespace>.WebApplication and got the error you explained above.

Howeveer when creating a new project (webforms) and using the nuget Package everything fired up correctly. I am not 100% is that was the issue however It does seem to have solved it!
Thursday, August 18, 2011 11:09:47 PM UTC
@scott

Great package, I have been wanting to convert my webforms to mvc3 but the daunting task of re-writing the entire solution has stopped me. I have made many past mvc3 projects, with my most recent one went very smoothly (insert link ad here! t-ny.co link shortening utility in mvc3

Thanks again, I got my massive project (2 years in development) now moving into mvc3 and running great.. Sometimes you just get overly sick of ASP.Net holding your hand...

Cheers, Nico
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.