Scott Hanselman

Cheesy ASP.NET MVC Project Upgrader for Visual Studio 2010 Beta 1

July 11, '09 Comments [8] Posted in ASP.NET MVC
Sponsored By

WARNING: This is obscure and you likely don't care.

As Phil mentioned a little while back, ASP.NET MVC didn't ship with Visual Studio 2010 Beta 1, but will ship with Visual Studio 2010 Beta 2 (and beyond.)

When VS10 Beta 2 comes out, you won’t need to download a separate standalone installer to get ASP.NET MVC (though a standalone installer will be made available for VS2008 users that will run on ASP.NET 3.5 SP1).

If you're using Visual Studio 2010 Beta 1 and want to use ASP.NET MVC, you can go get a drop of MVC for just this purpose, up on CodePlex.

This particular version of MVC is ONLY for use on Visual Studio 2010 Beta and is temporary. As such, it's got a placeholder version of 1.1, rather than 1.0.

If you have existing ASP.NET MVC 1.0 applications under .NET 3.5 lying around that you want to run them on VS 2010 Beta 1, you'll have to make some version number changes in your web.config.

I had a bunch of existing MVC apps lying around so I did this little upgrader application. It's poop, but it Works On My Machine©. Enjoy.

The code is here and is likely a blot on my soul. It will update the version numbers in the main web.config as well as the one in ~\views. It'll also make up to two backups, just in case.

The app is a .NET 4.0 Beta 1 Application and is zipped up here. You just run ASPNETMVCUpgrader "c:\path to your app"

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ASPNETMVCUpgrader
{
class Program
{
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Usage: ASPNETMVCUpgrader c:\\pathtomyprojectdir");
System.Environment.Exit(1);
}

//Remember there's TWO, count 'em, TWO web.configs. Madness!
TidyUpFile(Path.Combine(args[0], "web.config"));
TidyUpFile(Path.Combine(args[0], "Views\\web.config"));
}

private static void TidyUpFile(string filename)
{
string oldMvcType = "System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35";
string newMvcType = "System.Web.Mvc, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35";

string oldRoutingLine = "<add name=\"UrlRoutingModule\" type=\"System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>";
string newRoutingLine = "<add name=\"UrlRoutingModule\" type=\"System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>";

if (!File.Exists(filename))
{
Console.WriteLine(String.Format("Can't find {0}. You sure it's there?", filename));
System.Environment.Exit(1);
}

//Fix up the references!
string webconfigtext = File.ReadAllText(filename);
string newwebconfigtext = webconfigtext.Replace(oldMvcType, newMvcType);
newwebconfigtext = newwebconfigtext.Replace(oldRoutingLine, newRoutingLine);

//Keep up to two backups
string backupWebConfig = Path.ChangeExtension(filename, ".mvc10backup");
if (File.Exists(backupWebConfig))
{
var twoIsEnough = Path.ChangeExtension(filename, ".mvc10backup2");
File.Delete(twoIsEnough);
File.Copy(backupWebConfig,twoIsEnough);
File.Delete(backupWebConfig);
}
File.Copy(filename, backupWebConfig);

File.WriteAllText(filename, newwebconfigtext);

//Toot!
Console.WriteLine(String.Format("Updated MVC 1.0 references to MVC 1.1 for Dev10 Betas. \n Created a {0} backup. Toot.", filename));
}
}
}

Enjoy.

Extra Credit: If you'd like to show off for no reason, feel free to rewrite this application in as few lines as possible (but still in C#, Ruby people) and post in the comments.

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
Saturday, July 11, 2009 3:01:51 PM UTC
When you say "rewrite this application in as few lines as possible" I hope you didn't mean Perl style :-) keep it readable!
Sunday, July 12, 2009 7:54:48 PM UTC

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ASPNETMVCUpgrader
{
class Program
{
static void Main(string[] args)
{
if (!(args.Length == 1 )) {Console.WriteLine("Usage: ASPNETMVCUpgrader c:\\pathtomyprojectdir"); System.Environment.Exit(1); }
//Remember there's TWO, count 'em, TWO web.configs. Madness!
TidyUpFile(Path.Combine(args[0], "web.config"),Path.Combine(args[0], "Views\\web.config"));
}
private static void TidyUpFile(params string[] filename)
{
if (!filename.All(fn => File.Exists(fn)) )
{
// If it don't exist, don't bother creating strings.
Console.WriteLine(String.Format("Can't find {0} or {1}. You sure it's there?", filename[0],filename[1]));
System.Environment.Exit(1);
}
for(int i = 0; i < 2; i++) {
//Fix up the references!
String MvcType = "System.Web.Mvc, Version=1.{0}.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35";
String Routing = "<add name=\"UrlRoutingModule\" type=\"System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version={0}.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>";
string webconfigtext = File.ReadAllText(filename[i]);
string newwebconfigtext = webconfigtext.Replace(string.Format(MvcType,"0"),String.Format(MvcType,"1")); //(Old, New)
newwebconfigtext = newwebconfigtext.Replace(string.Format(Routing, "3.5"), String.Format(Routing, "4.0")); //(Old, New)
//Keep up to two backups
string backupWebConfig = Path.ChangeExtension(filename[i], ".mvc10backup");
if (File.Exists(backupWebConfig))
{
var twoIsEnough = Path.ChangeExtension(filename[i], ".mvc10backup2");
File.Delete(twoIsEnough);
File.Copy(backupWebConfig, twoIsEnough);
File.Delete(backupWebConfig);
}
File.Copy(filename[i], backupWebConfig);
File.WriteAllText(filename[i], newwebconfigtext);
//Toot!
Console.WriteLine(String.Format("Updated MVC 1.0 references to MVC 1.1 for Dev10 Betas. \n Created a {0} backup. Toot.", filename));
}
}
}
}
Adam Speight
Monday, July 13, 2009 7:17:55 AM UTC
I like how Adam did the strings. Here's a more functional approach:
        static void Main(string[] args)
{
if (args.Length != 1) { Console.WriteLine("Usage: ASPNETMVCUpgrader c:\\pathtomyprojectdir"); System.Environment.Exit(1); }
//Remember there's TWO, count 'em, TWO web.configs. Madness!
var messages = new[] { "web.config", @"Views\web.config" }
.Select(p => Path.Combine(args[0], p))
.Select(f => File.Exists(f) ? TidyUpFile(f) : String.Format("Can't find {0}. You sure it's there?", f));
foreach (var m in messages) Console.WriteLine(m);
}
private static String MvcType = "System.Web.Mvc, Version={0}.0.0,";
private static String Routing = "System.Web.Routing, Version={0}.0.0,";
private static string TidyUpFile(string filename)
{
//Fix up the references!
string newWebConfigText = File.ReadAllText(filename)
.Replace(string.Format(MvcType, "1.0"), String.Format(MvcType, "1.1")) //(Old, New)
.Replace(string.Format(Routing, "3.5"), String.Format(Routing, "4.0")); //(Old, New)
//Keep up to two backups
string backupWebConfig = Path.ChangeExtension(filename, ".mvc10backup");
if (File.Exists(backupWebConfig))
{
var twoIsEnough = Path.ChangeExtension(filename, ".mvc10backup2");
File.Delete(twoIsEnough);
File.Move(backupWebConfig, twoIsEnough);
}
File.Move(filename, backupWebConfig);
File.WriteAllText(filename, newWebConfigText);
//Toot!
return String.Format("Updated MVC 1.0 references to MVC 1.1 for Dev10 Betas. \n Created a {0} backup. Toot.", filename);
}

And a bonus: Unlimited* backups! (* within reason)
            var backupPaths = Enumerable.Repeat<int?>(null, 1)
.Concat(Enumerable.Range(2, int.MaxValue - 2).Select(i => (int?)i))
.Select(i => Path.ChangeExtension(filename, ".mvc10backup" + i));
string toCopy = filename;
foreach (var f in backupPaths.TakeWhile(_ => toCopy != null))
{
string temp = null;
if (File.Exists(f))
File.Move(f, temp = f + "TEMP");
File.Move(toCopy, f);
toCopy = temp;
}
File.WriteAllText(filename, newWebConfigText);

I don't like the TEMP hack, but it will do for now.
Monday, July 13, 2009 7:18:32 AM UTC
Beta 1, Beta 2...
RC1, RC2.. ...
I like the RTM :)
Tuesday, July 14, 2009 1:00:10 AM UTC
Great rewrites! I love the use of LINQ. I'll need to do a post on your versions!
Tuesday, July 14, 2009 10:59:56 AM UTC
private static void TidyUpFileShort(string filename)
{
if (!File.Exists(filename)){
Console.WriteLine(String.Format("Can't find {0}. You sure it's there?", filename));
System.Environment.Exit(1);
}

string webconfigtext = File.ReadAllText(filename).Replace("System.Web.Mvc, Version=1.0.0.0,", "System.Web.Mvc, Version=1.1.0.0,").Replace("System.Web.Routing, Version=3.5.0.0", "System.Web.Routing, Version=4.0.0.0"); ;

if (File.Exists(Path.ChangeExtension(filename, ".mvc10backup"))){
File.Replace(filename, Path.ChangeExtension(filename, ".mvc10backup"), Path.ChangeExtension(filename, ".mvc10backup2"));
}
else{
File.Move(filename, Path.ChangeExtension(filename, ".mvc10backup"));
}

File.WriteAllText(filename, webconfigtext);

Console.WriteLine(String.Format("Updated MVC 1.0 references to MVC 1.1 for Dev10 Betas. \n Created a {0} backup. Toot.", filename));
}
Tomas
Wednesday, July 15, 2009 9:04:45 PM UTC
Here's my regex version:


static void Main(string[] args)
{
if (args.Length == 0) Console.WriteLine("Usage: ASPNETMVCUpgrader pathToProject1 [pathToProject2] [pathToProject3]");

Regex regex1 = new Regex(@"(?<1>System.Web.Mvc, Version=)1.0(?<2>.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35)", RegexOptions.Compiled);
Regex regex2 = new Regex(@"(?<1><add name=""UrlRoutingModule"" type=""System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=)3.5(?<2>.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"" />)", RegexOptions.Compiled);

foreach (var file in args
.Select(p => new { Both = new[] { Path.Combine(p, "web.config"), Path.Combine(p, @"Views\web.config") } })
.SelectMany(p => p.Both)
.Select(p => new { Path = p, Content = File.ReadAllText(p) }))
{
try
{
File.Move(file.Path, Enumerable.Range(0, 100).Select(p => string.Format("{0}.backup_{1:00}", file.Path, p)).First(p => !File.Exists(p)));
File.WriteAllText(file.Path, regex1.Replace(regex2.Replace(file.Content, "${1}4.0${2}"), "${1}1.1${2}"));
Console.WriteLine("Done converting: {0}", file.Path);
}
catch (Exception ex) { Console.WriteLine("Error with: {0}" + Environment.NewLine + "Exception: {1}", file.Path, ex.Message); }
}
}
Dušan Radovanović
Comments are closed.

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