Building a Self Updating Site Using NuGet

asp.net mvc, open source, nuget 0 comments suggest edit

For those of you who enjoy learning about a technology via screencast, I’ve recorded a video to accompany and complement this blog post. The screencast shows you what this package does, and the blog post covers more of the implementation details.

A key feature of any package manager is the ability to let you know when there’s an update available for a package and let you easily install that update.

For example, when we deployed the release candidate for NuGet, the Visual Studio Extension Manager displayed the release in the Updates section.

Extension Manager Displaying NuGet as an Available
Updates

Likewise, NuGet lets you easily see updates for installed packages. You can either run the List-Package –Updates command:

list-package-updates

Or you can click on the Updates node of the Add Package dialog:

updates-tab

This feature is very handy when using Visual Studio to develop software such as Subtext, an open source blog engine I run in my spare time. But I started thinking about the users of Subtext and the hoops they jump through to upgrade Subtext itself.

Wouldn’t it be nice if Subtext could notify users when a new version is available and let them install it directly from the admin section of the running website completely outside of Visual Studio? Why yes, that would be nice.

NuGet to the Rescue!

Well my friends, that’s where NuGet comes into play. While most people know NuGet as a Visual Studio extension for pulling in and referencing libraries in your project, there’s a core API that’s completely agnostic of the hosting environment whether it be Visual Studio, PowerShell, or other. That core API is implemented in the assemly, NuGet.Core.dll.

This assembly allows us to take advantage of many of the features of NuGet outside of Visual Studio such as within a running web site!

The basic concept is this:

  1. Package up the first version of a website as a NuGet package.
  2. Install this package in the website itself. I know, crazy talk, right?
  3. Add a custom NuGet client that runs inside the website and checks for updates to the one package that’s installed.
  4. When the next version of the website is ready, package it up and deploy it to the package feed for the website. Now, the users of the website can be notified that an update is available.s

I should point out a brief note about step #2, because this is going to be confusing. When I say install the package in the website, I mean to contrast that with installing a package into your Web Application Project for the website.

When you install a package into your Web Application Project, you use the standard NuGet client within Visual Studio. But when you deploy your website, the custom NuGet client within the live website will install the website package into a different location. In the example I’ll show you, that location is within the App_Data\packages folder.

The AutoUpdate Package

Earlier this week, I gave an online presentation to the Community For MVC (C4MVC) user’s group on NuGet. During that talk I demonstrated a prototype package I wrote called AutoUpdate. This package adds a new area to the target website named “Installation”. It also adds a nuspec file to the root of the application to make it easy to package up the website as a NuGet Package.

The steps to use the package are very easy.

  1. Install-Package AutoUpdate.
  2. In Web.config, modify the appSetting PackageSource to point to your package source. In my demo, I just pointed it to a folder on my machine for demonstration purposes. But this source is where you would publish updates for your package.
  3. In the Package Console, run the New-Package script (This creates packages up the website in a NuPkg file).
  4. Copy the package into the App_Data\Packages folder of the site.
  5. When you are ready to publish the next version as an update, increment the version number in the nuspec file and run the New-Package script again.
  6. Deploy the updated package to the package source.
  7. Now, when your users visit /installation/updates/check within the web site, they’ll be notified that an update is available and will be able to install the update.

The Results

Lets see the results of installing the AutoUpdate package and I’ll highlight some of the code that makes the package work. The following screenshot shows a very basic sample application I wrote.

home-page

The homepage here has a link to check for updates which links to an action within the area installed by the AutoUpdate package. That action contains the logic to check for updates for this application’s package.

Clicking on that link requires me to login first and then I get to this page:

update-available

As I mentioned in the steps before, I packaged up the first version of the application as a package and “installed” it into the App_Data folder.

That yellow bar above is the result of an asynchronous JSON request to see if an update is available. It’s a little redundant on this page, but I could have it show up on every page within the admin as a notification.

Under the Hood

Let’s take a look at the controller that responds to that asynchronous request.

public ActionResult Check(string packageId) {
  var projectManager = GetProjectManager();
  var installed = GetInstalledPackage(projectManager, packageId);
  var update = projectManager.GetUpdate(installed);

  var installationState = new InstallationState {
    Installed = installed,
    Update = update
  };

  if (Request.IsAjaxRequest()) {
    var result = new { 
      Version = (update != null ? update.Version.ToString() : null), 
      UpdateAvailable = (update != null)
    };
    return Json(result, JsonRequestBehavior.AllowGet);
  }

  return View(installationState);
}

The logic here is pretty straightforward. We grab a project manager. We then grab a reference to the current installed package representing this application. And then we check to see if there’s an update available. If there isn’t an update, the GetUpdate method returns false. There’s a couple of methods here that I wrote we need to look at.

The first method very simply retrieves a project manager. I encapsulated it into a method since I call it in a couple different places.

private WebProjectManager GetProjectManager() {
  string feedUrl = @"D:\dev\hg\AutoUpdateDemo\test-package-source";
  string siteRoot = Request.MapPath("~/");

  return new WebProjectManager(feedUrl, siteRoot);
}

There’s a couple things to note here. I hard coded the feedUrl for demonstration purposes to point to a directory on my machine. This is a nice demonstrations that NuGet can simply treat a directory containing packages as a package source.

For your auto-updating web application, that should point to a custom feed you host specifically for your website. Or, point it to the official NuGet feed and put your website up there. It’s up to you.

This method returns an instance of WebProjectManager. This is a class that I had to copy from the System.Web.WebPages.Administration.dll assembly because it’s marked internal. I don’t know why it’s internal, so I’ll see if we can fix that. It’s not my fault so please direct your hate mail elsewhere. Smile

What is the web project manager? Well the WebMatrix product which includes the ASP.NET Web Pages framework includes a web-based NuGet client for simple web sites. This allows packages to be installed into a running website. I’m just stealing that code and re-purposing it for my own needs.

Now, we just need to use the project manager to query the package source to see if there’s an update available. This is really easy.

private IPackage GetInstalledPackage(WebProjectManager projectManager,     string packageId) {
  var installed = projectManager.GetInstalledPackages("AutoUpdate.Web")    .Where(p => p.Id == packageId);

  var installedPackages = installed.ToList();
  return installedPackages.First();
}

What’s really cool is that we can just send a LINQ query to the server because we’re running OData on the server, it’ll run that query on the server and send us back the packages that fulfill the query.

That’s all the code necessary to check for updates. The next step is to write an action method to handle the upgrade. That’s pretty easy too.

public ActionResult Upgrade(string packageId) {
  var projectManager = GetProjectManager();
  var installed = GetInstalledPackage(projectManager, packageId);
  var update = projectManager.GetUpdate(installed);
  projectManager.UpdatePackage(update);

  if (Request.IsAjaxRequest()) {
    return Json(new { 
      Success = true, 
      Version = update.Version.ToString()
    }, JsonRequestBehavior.AllowGet);
  }
  return View(update);
}

This code starts off the same way that our code to check for the update does, but instead of simply returning the update, we call projectManager.UpdatePackage on the update. That method call updates the website to the latest version.

The rest of the method is simply concerned with returning the result of the upgrade.

Try it Yourself

If you would like to try it yourself, please keep a one big caveat in mind. This is rough proof of concept quality code. I hope to shape it into something more robust over time and publish it in the main package feed. Until then, I’ll post it here for people to try out. If there’s a lot of interest, I’ll post the source on CodePlex.com.

So with that in mind, give the AutoUpdate package a try

install-package AutoUpdate

and give me some feedback!

UPDATE: I upgraded the project to target ASP.NET MVC 4 and posted the source on GitHub. I have no idea if it still works, so please do submit pull requests if you find bugs you would like to have fixed.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

65 responses

  1. Avatar for Chris
    Chris January 15th, 2011

    Funny. I had this thought a while back. http://twitter.com/#/claco/status/20599774260502528
    Will the install.ps1 files still be executed?

  2. Avatar for haacked
    haacked January 15th, 2011

    @Chris heh, so did I. Took me a while to get around to blogging around it.
    No, the install.ps1 scripts will not run in this environment because it's running as part of your website, which doesn't have a PS environment like VS does.

  3. Avatar for NC
    NC January 15th, 2011

    You've missed a closing tag on your post and it's screwed up all the comments in Firefox 4 beta and Opera 11.

  4. Avatar for NC
    NC January 15th, 2011

    Where you have the title "Try it yourself" you have:
    <h2 /> <--- screwing up browsers.
    <h2>Try it Yourself</h2>

  5. Avatar for haacked
    haacked January 15th, 2011

    @NC Thanks! Fixed!

  6. Avatar for Mikael Henriksson
    Mikael Henriksson January 15th, 2011

    Phil, this is brilliant!! I was just a few weeks ago asking my hosting provider for a better alternative than ftp upload triggered from local machine.
    Would this work in Medium++ trust? Either way I'd love to see the source code for this. The MvcScaffolding project that Sanderson just blogged about opened my eyes to NuGet, haven't really used it before.

  7. Avatar for Asad. Gharighi
    Asad. Gharighi January 15th, 2011

    It's quite useful to have such easy process. Thanks for sharing the idea and actually doing it.
    I was thinking, if we had a way to do this autoupdates in a partial manner that would me more useful. You can see here and there some of the features of a new version maybe in conflict with someone's way of arranging things. Does that mean we should have a package manager inside the package manager? Maybe the original package should be maintaiend very carefully.
    Thanks pal anyway.

  8. Avatar for Ben Foster
    Ben Foster January 15th, 2011

    Phil, this looks great. It would good to extend this concept further to create a way of deploying and maintaining features/plugins within an application. There are so many OSS projects that would benefit from a standardised way of doing this.
    Orchard already has something like this - are they using Nuget.Core too?

  9. Avatar for VDMT
    VDMT January 15th, 2011

    Hi Phil, I like! This is awesome I'm looking forward to using this - not that you would normally do this but, would it be possible to extend this to revert back to a previous version?

  10. Avatar for Richard Kimber
    Richard Kimber January 15th, 2011

    This is fantastic. One of the features I've always loved about WordPress is autoupdate, now I can do it on my own apps.
    Rich

  11. Avatar for Mike
    Mike January 15th, 2011

    How to handle permissions to update files, and how to handle database schema updates?

  12. Avatar for Corey Coto
    Corey Coto January 16th, 2011

    Fantastic post!
    How would this work in a IIS Web Server farm? Would it only update a single instance or all of the nodes in the farm?

  13. Avatar for haacked
    haacked January 16th, 2011

    @Mikael Medium trust should be no problem. It's really an issue of whether you allow write permissions to the web directory.
    @Ben yes, look at what the ASP.NET Web Pages + Web Matrix does. They use this to add features/plugins via a web admin.
    @VDMT in theory, yes you could revert. But I probably wouldn't trust it. ;)
    @Mike Updating databases is tricky. What we do in Subtext is have an embedded resource with SQL scripts and we run the scripts when we do an update. You'd have to handle that in the code of your package somehow.
    @Corey good point. It would only update a single instance. For a Web Farm, you'd have to have some way of syncing such changes across the farm.

  14. Avatar for Gregor Suttie
    Gregor Suttie January 16th, 2011

    This is a superb addition!

  15. Avatar for Bob
    Bob January 16th, 2011

    Great post!! Videos always make it easier to learn. 720p video is a must for showing things on a computer screen. You've definitely elevated your level of blogging. It will be hard to do a "quickie" blog post in the future though. The expectations are now set too high!!

  16. Avatar for Robert Muehsig
    Robert Muehsig January 16th, 2011

    Very impressive demo, but I´m a bit confused: I thought NuGet would be a kind of library repository. In your demo you use it for a whole web application - which is very cool. But should this "deployment task" not handled via WebDeploy? If I want to build a system like "Wordpress", should I upload new releases on MS WebApp Gallery for the Web Platform Installer AND on the NuGet Gallery?
    SRP violation? ;)

  17. Avatar for Robert
    Robert January 16th, 2011

    Excellent post!
    Please do make it available on Codeplex.

  18. Avatar for BobM
    BobM January 16th, 2011

    Interesting concept -- Pls make the code available. Can you think of any reason the same process could not be used to update windows services?

  19. Avatar for Martin
    Martin January 17th, 2011

    Could you please update the Mvc Futures on Nuget to the lateste version for MVC 3 RTM ? :)
    Would be really great.

  20. Avatar for Andrew Wrigley
    Andrew Wrigley January 17th, 2011

    Registering interest

  21. Avatar for Ben Foster
    Ben Foster January 17th, 2011

    "@Ben yes, look at what the ASP.NET Web Pages + Web Matrix does. They use this to add features/plugins via a web admin."
    Phil,
    Is this code (Web Matrix) open source?

  22. Avatar for Ira
    Ira January 17th, 2011

    This is quite an awesome idea. I for one really hope you release the source and make this a project on codeplex because I can think of a bunch of scenarios this would be useful in.

  23. Avatar for Jeff
    Jeff January 18th, 2011

    This is pretty cool for personal blogs and sites where downtime is acceptable. However, inevitable a breaking change will be introduced by one of the dependencies and then "BOOM"!

  24. Avatar for Lee Hull
    Lee Hull January 18th, 2011

    Very nice concept, unfortunately I'm getting an error..
    "Could not load file or assembly 'NuGet.Core, Version=1.0.10128.89, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified."
    However I do have NuGet.Core installed and referenced in website but not that exact version, I have NuGet.Core v1.0.11220.104

  25. Avatar for Hans Kruse
    Hans Kruse January 19th, 2011

    Can this be easily transformed into something useful for use from msbuild?
    Now using nuget in VS.NET but a "sharedlibs" folder on the TFS buildserver due to lack of time.

  26. Avatar for haacked
    haacked January 19th, 2011

    @Robert I suppose it depends. Let's say you set up a blog for your mom. Do you expect her to use Web Deploy to deploy an updated version of that blog? I'm guessing no. It'd be nice if the blog could let her click a button in the website and upgrade itself.
    Let's say you're at work and ready to deploy version 2 of your flagship website. Are you going to use this AutoUpdate NuGet package? Of course not. You'd use web deploy or something similar.
    Every tool has its place.
    @BobM I doubt this would work for Windows Services as a service needs to be stopped to be updated AFAIK. That's out of scope of NuGet.
    @Ben WebMatrix is not open source. WebMatrix refers to the simple IDE we released.
    @Jeff true. I probably wouldn't do enterprise deployments this way. But for web apps that are distributed, it's a neat idea.

  27. Avatar for Lee Hull
    Lee Hull January 19th, 2011

    Got it working..
    Really nice, would be nice if you could get update if local one does not exist. Since I publish to IIS, App_Data doesn't always get copied over

  28. Avatar for Oisín G.
    Oisín G. January 20th, 2011

    It's Get-Package now Phil, not List-Package ;-)

  29. Avatar for Cyriel
    Cyriel January 27th, 2011

    Hi Phil,
    Let me start by saying: nice idea!
    Anyway,
    I was wondering what would happen in a scenario where multiple users have permission to update the application, and all of them get notified and click the upgrade link in the notification. Will the second (or third or whatever) request be terminated if the first one is in progress?

  30. Avatar for haacked
    haacked January 28th, 2011

    @Cyriel that's not built into my proof-of-concept, but it's something that could easily be accomplished in the UI by setting some value in the database before starting the upgrade and always checking that value beforehand.

  31. Avatar for Joshua
    Joshua February 9th, 2011

    This is an excellent idea Phil! I'd love to see this taken further.
    Even for a simple blog website however, you still have a database to manage and I'm not sure how you would control database updates between versions? You would need a way of being able to pull down the appropriate sql migration script and run it on the database as part of a post build task or something.
    Slight segway but I am also interested to see how the EF team handle code first migration.
    I would love to see this proof of concept "AutoUpdater" project taken further. Just goes to show how awesome NuGet is.

  32. Avatar for Cody Toombs
    Cody Toombs February 13th, 2011

    I don't really see database updates being that challenging, they just require a bit of a workaround. Deploy the update script as part of your package and throw a little code into global.asax Application_Start to check a variable that records the last run version number. If the stored version number is older than the current version number, check if there's an update script and run it if so.
    Certainly, it would be better to have this functionality baked into the update mechanism, which doesn't seem too hard or very involved. While it's probably not necessary, I have a feeling people might have more than a couple lines of SQL to run, so a little prescriptive design might encourage putting their update code into an assembly that is simply run as an automatic last stage of the updater.

  33. Avatar for haacked
    haacked February 14th, 2011

    @Cody, that's exactly how Subtext does it today and exactly how I'd probably do it with this package.

  34. Avatar for Patrick
    Patrick February 19th, 2011

    This is exactly the type of thing I have been looking for. Any chance you can share the source?

  35. Avatar for Fabio Franzini
    Fabio Franzini March 21st, 2011

    I created a demo project in web form at this address: www.fabiofranzini.com/...
    Fabio

  36. Avatar for adrian
    adrian April 15th, 2011

    This is great! Luckily I did a google search before trying to implement it myself from scratch :) Codeplex is the right place for this one!

  37. Avatar for adrian
    adrian April 15th, 2011

    Please make the code available on Codeplex!
    I got this error: [InvalidOperationException: The 'schemaVersion' attribute is not declared.]

  38. Avatar for Lasse Edsvik
    Lasse Edsvik May 1st, 2011

    Seems no controllers gets created when installing it to a mvc 3 site :) Could you fix that? :)

  39. Avatar for Attila Szomor
    Attila Szomor May 5th, 2011

    Hi Phil,
    Your article was very useful for me and I am interesting for solutions such as AutoUpdate.
    Please let me inform about what happened since you published this article.
    Are you post (or will be) AutoUpdate into CodePlex?
    Best Regards,
    Attila.

  40. Avatar for Germ&#225;n
    Germ&#225;n June 3rd, 2011

    Phil, great article.
    By the way, i´m getting "Access denied" all the time because the selfupdater tries to delete a bin\.dll file used by the website, more specifically when trying to delete with "NuGet.PhysicalFileSystem.DeleteFile"
    i`m getting a big "System.UnauthorizedAccessException: Access to the path 'D:\MySite\bin\MySite.dll' is denied."
    How can you get through this ?

  41. Avatar for Nikos Miliotis
    Nikos Miliotis June 18th, 2011

    I have installed the package but no nuspec file is created either the views. (MVC 3) Am i missing something? I have watched the video but a lot of files are missing.

  42. Avatar for Mike
    Mike July 16th, 2011

    Awesome, but if this works, then what did we learn web deploy for?

  43. Avatar for Mike
    Mike July 16th, 2011

    "This method returns an instance of WebProjectManager. This is a class that I had to copy from the System.Web.WebPages.Administration.dll assembly because it’s marked internal. I don’t know why it’s internal, so I’ll see if we can fix that. It’s not my fault so please direct your hate mail elsewhere. "
    Sure, but I'm not sure where Microsoft will direct the lawyers when I use AutoUpdate with code from copyrighted code...

  44. Avatar for David
    David July 26th, 2011

    Is there anything special you have to do with the package repository (D:\temp\packages)? I can't seem to get it to figure out that I have any updates even though I've put two nupkg files in there.

  45. Avatar for Paul Mendoza
    Paul Mendoza July 26th, 2011

    Hi Phil,
    Can you post this project to Codeplex? I'm really interested in using this.
    Thanks,
    Paul Mendoza

  46. Avatar for Husain
    Husain October 13th, 2011

    Phil, am interested in the code. Could you please post this on Codeplex? Thanks.

  47. Avatar for Peter
    Peter October 15th, 2011

    Hi Phil,
    This is nifty stuff! Could you please post the code somewhere?
    Many thanks for this post.

  48. Avatar for Davide
    Davide November 11th, 2011

    Any news about this?
    Have you already published the source code? I've been looking for such a tool for a long time and only found half-baked overpriced commercial solutions.
    Your way utilizing NuGet looks very promising. :)

  49. Avatar for Dmitriy
    Dmitriy January 3rd, 2012

    Looking forward to see the code as well; this sounds very cool!

  50. Avatar for Dmitriy
    Dmitriy January 3rd, 2012

    After more research, found it here: http://nuget.org/packages/AutoUpdate
    Going to play around with this, thx.

  51. Avatar for Ryan Whitmire
    Ryan Whitmire January 10th, 2012

    Does this still work (as of nuget 1.6) or am I doing something wrong?

  52. Avatar for Yohann
    Yohann January 20th, 2012

    I think the version 0.21 (the latest) doesn't work anymore... damn it!

  53. Avatar for click
    click January 25th, 2012

    Thank you for your help.I think i am getting it. I was able to send a link in the email that would take me to the Edit Properties page of the form, But i was expecting to get the actual form itself.

  54. Avatar for Avioes a Venda
    Avioes a Venda February 1st, 2012

    I have watched the video but a lot of files are missing.

  55. Avatar for Aeronaves
    Aeronaves February 23rd, 2012

    Could you please post the code somewhere?
    Many thanks for this post.

  56. Avatar for marko
    marko April 9th, 2012

    Phil, please revisit this project of yours and publish it on some code sharing site (source code) so we can pick it up and maybe update it to work with the latest Nuget and maybe add functionality.

  57. Avatar for Harry McIntyre
    Harry McIntyre April 12th, 2013

    Did the source ever make it to Codeplex, or even Github?

  58. Avatar for India
    India May 9th, 2013

    return new WebProjectManager(packageSource, siteRoot); is giving me error "Method not found: 'NuGet.PackageSource NuGet.PackageSource.op_Implicit(System.String)'." Any help wil work

    I am using AutoUpdate 0.2.1 and NuGet.Core 2.5.40416.9020

    Thanks in Advance.

  59. Avatar for Deepak
    Deepak August 6th, 2013

    Please share test project

  60. Avatar for Deepak
    Deepak August 6th, 2013

    In the Package Console, run the New-Package script (This creates packages up the website in a NuPkg file).

    Please explain how to do this

  61. Avatar for Diomedes Domínguez
    Diomedes Domínguez October 5th, 2015

    New-Package -TargetFile [ProjectName][Version].nupkg

  62. Avatar for Ravi Rampariya
    Ravi Rampariya January 7th, 2017

    Hello,

    i just take new project of asp.net mvc and install package AutoUpdate, Package installed successfully. try to run project in browser with /Installation/Updates/Check

    i am getting below error , pleaes help me to figure this out. i am getting rid of that.

    http://prntscr.com/dsl79y

    Could not load file or assembly 'System.Web.WebPages.Administration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.

  63. Avatar for haacked
    haacked January 9th, 2017

    What version of ASP.NET MVC are you running. I only tried with ASP.NET MVC 4. A lot has changed since I wrote this and I'm not maintaining it.

  64. Avatar for Ravi Rampariya
    Ravi Rampariya January 10th, 2017

    i tied in ASP.NET MVC 4 as well 3 but not succeed. can you please help me to figure out the problem ?

  65. Avatar for Emanuell Paredes
    Emanuell Paredes April 8th, 2017

    Try the following comand in the console:

    Install-Package Microsoft.AspNet.WebPages.Administration