Scott Hanselman

Updating and Publishing a NuGet Package - Plus making NuGet packages smarter and avoiding source edits with WebActivator

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

I wrote a post a few days ago called "Creating a NuGet Package in 7 easy steps - Plus using NuGet to integrate ASP.NET MVC 3 into existing Web Forms applications." Long enough title? I think so.

The post exists for two reasons: First to show folks how insanely easy it is to create a NuGet package (and prompt you to make some yourself) and second to share with you some experiments where one enables new/interesting functionality after File|New Project. In that example, we had an existing ASP.NET WebForms application and added ASP.NET MVC to it in one line, making it an easy hybrid application.

install-package AddMvc3ToWebForms

Well, not really one line. In version 0.5 of the AddMvc3ToWebForms package you still have to hook up the Areas, Routes and Filters yourself in the Global.asax. I made a helper method that gets it done to one additional line, but still, it's ever so slightly lame.

Now, to THIS post that exists for two reasons: First, to show you how to create an update to a package, and what the update process looks like for the consumer. Second, to show you how (and why) you should put a tiny bit more effort in your packages up front so that things "just work" for the user.

Creating an Update to a NuGet Package

Step 1 - Update the NuSpec file

I opened up my AddMvc3ToWebForms.nuspec file and changed the version a notch to 0.6. I also added a dependency to another NuGet package called WebActivator that I'm going to use to make my package just work and avoid the need for that extra line of code. I'm being specific and asking for WebActivator 1.1 or higher because that version has a specific feature I need.

<?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.6</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>
<dependencies>
<dependency id="WebActivator" version="1.1" />
</dependencies>
</metadata>
</package>

Step 2 - Make your new changes

When bringing in multiple NuGet packages it's common to want to have a few things run at application startup. Perhaps setting some context, connection strings, defaults for software factories, or dependency resolvers. There are a number of packages that need this functionality, and David Ebbo created the WebActivator package to make it easier. It's a formalized wrapper around a new ASP.NET 4 attributed called "PreApplicationStartMethod," and David also enables a PostApplicationStartMethod.

In my new version of the AddMvc3ToWebForms package I created a new file called AppStart_RegisterRoutesAreasFilters.cs.pp. Note the .pp extension that signals to NuGet to preprocess the file and replace tokens like $rootnamespace$, kind of like a mini-mini-code-generator.

The rest should look familiar; we're registering the Areas, GlobalFilters and Routes. The informal naming convention is to prefix the class and file with AppStart_ so that projects that include packages that add an AppStart_*.* will group the files together.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Web.Infrastructure;

[assembly: WebActivator.PostApplicationStartMethod(typeof($rootnamespace$.AppStart_RegisterRoutesAreasFilters), "Start")]

namespace $rootnamespace$ {
public static class AppStart_RegisterRoutesAreasFilters {
public static void Start() {
// Set everything up with you having to do any work.
// I'm doing this because it means that
// your app will just run. You might want to get rid of this
// and integrate with your own Global.asax.
// It's up to you.
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
}
}

Note the line:

[assembly: WebActivator.PostApplicationStartMethod(typeof($rootnamespace$.AppStart_RegisterRoutesAreasFilters), "Start")]

David added the "PostApplicationStart" option because PreApplicationStart happens too early in the process to register Areas, so for my package, I want things to run just after App_Start. This is all new and under development, so feel free to share with David if you have any thoughts, improvements or strong opinions.

Step 3 - Build a new NuPkg file

From the command line, call...

NuGet pack

...and you'll automatically get a new file, like this screenshot:

Building a new package - Look at all my packages in the explorer window. Cool.

Step 4 - Publish the Update to http://nuget.org (or any NuGet server or file share)

I could log in to my account and upload the file from the browser interface, but since I'm thinking I'll being making changes here and there, I figure it'd be nice to publish from the command line.

I'll grab my API key from the site...

image

..and use it to publish from the command line (using my magic new publish.bat) with contents like these:

nuget push AddMvc3ToWebForms.0.6.nupkg e5c2bbe6-xxxx

...and the result...

C:\AddMvc3ToWebForms>nuget push AddMvc3ToWebForms.0.6.nupkg e5c2bbe6-xxxx
Creating an entry for your package [ID:AddMvc3ToWebForms Ver:0.6]...
Your package was uploaded to the server but not published.
Publishing your package [ID:AddMvc3ToWebForms Ver:0.6] to the live feed...
Your package was published to the feed.

Now I'm set. I've got version 0.6 live now. What's the experience for the user of this library?

Getting an Update to a NuGet Package

There's two ways to find out what NuGet packages my project is using and update them.

Package Manager Console

From the package manager console I can type Get-Package...

PM> Get-Package

Id Version Description
-- ------- -----------
AddMvc3ToWebForms 0.5 A totally unsupported way to quickly add ASP.NET MVC 3 support to your WebForms Application. Works on my machine.

Looks like I have version 0.5. I can update it via...

PM> Update-Package AddMvc3ToWebForms
'WebActivator (≥ 1.1)' not installed. Attempting to retrieve dependency from source...
Done.
Successfully installed 'WebActivator 1.1.0.0'.
Successfully installed 'AddMvc3ToWebForms 0.6'.
Successfully removed 'AddMvc3ToWebForms 0.5' from WebApplication7.
Successfully uninstalled 'AddMvc3ToWebForms 0.5'.
Successfully added 'WebActivator 1.1.0.0' to WebApplication7.
Successfully added 'AddMvc3ToWebForms 0.6' to WebApplication7.

Notice that NuGet automatically removed AddMvc3ToWebForms 0.5 and installed AddMvc3ToWebForms 0.6. It also automatically brought in the dependency on WebActivator 1.1.

Add Library Reference

Alternatively, from Visual Studio right click on the References node in the Solution Explorer and select Add Library Reference (or select the same directly from the Tools menu).

Select Updates from the left side. A list of updates will appear. Click Update.

Updating Packages - Add Library Package Reference

It's all good. Now my AddMvc3ToWebForms NuGet Package can add ASP.NET MVC functionality to an ASP.NET WebForms projects with no additional lines of code. This makes for a nice out of the box experience, especially if I bring in other projects that use the same functionality.

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
Friday, February 18, 2011 8:58:44 AM UTC
TODO for the weekend: Create some simple NuGet package, I have all information I need.
Thank Scott
Wednesday, February 23, 2011 4:12:34 PM UTC
scott I have a question;

I have my local nuget library repository separately both for my personal and work releted class libraries.

I have created some of the nuget packages for the libraries which are no longer in development. I did olny for them because I do not know how to update them automatically as soon as my project is builded.

I have figured that all the work is being done by nuget command line with Visual Studio Command Prompt. So I can easily do the work I needed (of course I would know commands perfectly and I do not !)

basically I want the following works done on post-build event of my project

on project build,

-copying project dll into a specific folder (lib folder of the nuget package)
-updating nuspec file for new file version (my project is increasing the file version on every build)
-creating new nupkg file with new file version

Phil haccked show some of this feature but it is still on prototype and for project based as far as I have seen.
Wednesday, February 23, 2011 6:00:09 PM UTC
phil haccked replied this question on codeplex here is the link : http://nuget.codeplex.com/discussions/247235
Monday, March 07, 2011 10:52:34 AM UTC
Why not also add a dependency for MVC 3 itself, so it also gets downloaded when not present already?
Tuesday, March 08, 2011 8:15:55 PM UTC
MVC3 itself isn't in NuGet as a thing to be dependent on.
Wednesday, July 06, 2011 3:33:00 PM UTC
Thanks for this Scott, you've saved me a ton of research

Tuesday, September 27, 2011 7:24:17 PM UTC
Pure Gold.

I am not worthy...
Comments are closed.

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