code comments edit

UPDATE (12/26): I updated this post to use the href instead of the rel attribute

It’s Christmas day, and yes, I’m partaking in the usual holiday fun such as watching Basketball, hanging out with the family and eating our traditional Alaskan king crab Christmas dinner. But of course it wouldn’t be a complete day without writing a tiny bit of code!

code

Today I’ve been working on improving the UI here and there in Subtext. One common task I run into over and over is using an anchor tag to trigger the hiding of another element such as a DIV. It happens so often that I get pretty tired of hooking up each and every link to the element it must hide. Being the lazy bastard that I am, I thought I’d try to come up with a way to do this once and for all with jQuery and a bit of convention.

Here’s what I came up with. The following HTML shows a DIV element with an associated link that when clicked, should hide the DIV.

<div id="hide-this">
    This here DIV will be hidden when you click on 
    the link
</div>
<a href="#hide-this" class="close">This is the link that hides the DIV</a>

The convention here is that any anchor tag with a class “close” is going to have its click event hooked up to close another element. That element is identified by the anchor tag’s rel href attribute, which contains the id of the element to hide. This was based on a suggestion by a couple of commenters to the original version of this post where I used a rel attribute. I like this much better for two reasons:

  • The href value is a hash which is already in the correct format to be a CSS selector for an ID.
  • I’m not using the href value in the first place, so might as well make use of it.

Yeah, this is probably an abuse of this attribute, but in this case it’s one I can live with due to the benefits it produces. The rel attribute is supposed to define the relationship of the current document to the document referenced by the anchor tag. Browsers don’t do anything with this attribute, but search engines do as in the case with therel value of “no-follow”~~.~~

However in this case, I feel my usage is in the spirit of this attribute as I’m defining the relationship of the anchor tag to another element in the document. Also, search engines are going to ignore the value I put in there unless the id happens to match a valid value, so no animals will be harmed by this.

Now I just need a little jQuery script to make the magic happen and hook up this behavior.

$(function() {
    $('a.close').click(function() {
        $($(this).attr('href')).slideUp();
        return false;
    });
});

I happened to choose the slide up effect for hiding the element in this case, but you could choose the hide method or fadeOut if you prefer.

I put up a simple demo here if you want to see it in action.

I’m just curious how others handle this sort of thing. If you have a better way, do let me know. :)

Tags: jQuery, JavaScript

personal comments edit

Just wanted to wish you all a Merry Christmas, Happy Holidays, or a Happy whatever you are celebrating at this time of year. I hope you are spending it well with family and friends! :)

As you can see, I’m still hard at work watching the kids on paternity leave.

Playing Call of Duty Modern Warfare 2 With
Mia

My brother is a drug dealer and the name of the drug is Call of Duty: Modern Warfare 2 for the X-Box 360. I’m totally hooked right now, and I don’t usually get so hooked on games.

At least I am managing to still get some fresh air outside and enjoy the weather. Here I’m walking with my wife (taking the photo), my mother, my son, and my brother.

033 Of course, every walk we go on ends up with me lugging my son around.

042

I wouldn’t trade it for anything. :)

asp.net, asp.net mvc, code comments edit

When we released ASP.NET MVC 2 Beta back in November, I addressed the issue of support for Visual Studio 2010 Beta 2.

Unfortunately, because Visual Studio 2010 Beta 2 and ASP.NET MVC 2 Beta share components which are currently not in sync, running ASP.NET MVC 2 Beta on VS10 Beta 2 is not supported.

The release candidate for ASP.NET MVC 2 does not change the situation, but I wasn’t as clear as I could have been about what the situation is exactly. In this post, I hope to clear up the confusion (and hopefully not add any more new confusion) and explain what is and isn’t supported and why that’s the case.

why

Part of the confusion may lie in the fact that ASP.NET MVC 2 consists of two components, the runtime and what we call “Tooling”. The runtime is simply the System.Web.Mvc.dll which contains the framework code which you would reference and deploy as part of your ASP.NET MVC application.

The Tooling consists of the installer, the project templates, and all the features in Visual Studio such as the Add View and Add Area dialogs. Much as ASP.NET 4 is different from Visual Studio 2010, the ASP.NET MVC 2 tooling is different from the runtime. The difference is that we primarily release both components in one package.

The reason I bring this up is to point out that when I said that ASP.NET MVC 2 RC is not supported on machines with Visual Studio 2010 Beta 2, I’m really referring to the tooling.

The ASP.NET MVC 2 RC runtime is fully supported with the ASP.NET 4 runtime. As I mentioned before, we are not compiling a different version of the runtime for ASP.NET 4. It’s the same runtime. So you can create an ASP.NET empty web application project, for example, add in the RC of System.Web.Mvc.dll as a reference, and go to town.

The problem of course is that you won’t have the full tooling experience at your disposal in VS2010 such as project templates and dialogs. This is definitely a pain point and very unfortunate.

Why don’t we ship updated installers for Visual Studio 2010 Beta 2?

This is a fair question. What it comes down to is that this would add a lot of extra work for our small team, and we’re already working hard to release the core features we have planned for this release.

Add this extra work and something would have to give. It would have to come at the cost of feature work and bug fixes and we felt those were a higher priority than temporary support for interim releases of VS2010.

Why would this add overhead? Eilon Lipton, lead developer on the ASP.NET MVC feature team, covers this well in his comment on my last post.

Regarding Visual Studio 2010 and .NET 4 support, that is unfortunately not a feasible option. The most recent public release of VS2010 and .NET 4 is Beta 2. However, our internal builds of MVC 2 for VS2010 and .NET 4 depend on features that were available only after Beta 2. In other words, if we released what we have right now for VS2010 and .NET 4 then it wouldn’t even run.

We are constantly syncing our internal builds with the latest builds of Visual Studio 2010. As Eilon points out, to support VS 10 Beta 2, we’d have to have two separate builds for VS10, one for Beta 2 and one for the latest internal build. Keep in mind, this is on top of the build for Visual Studio 2008 we’re doing.

Trying to sync our tooling against two different versions of Visual Studio is hard enough. Doing it against three makes it much more difficult.

As I mentioned before, the ASP.NET MVC 2 project schedule isn’t aligned with the Visual Studio 2010 schedule exactly. Heck, when ASP.NET MVC 1.0 was shipped, work on VS 10 was already underway, so we were playing catch-up to catch the VS 10 ship train. Thus when the Beta 2 was code complete, we weren’t done with our Beta. When we were done with Beta, we were already building our tools against a newer build of VS10. The same thing applies to the RC.

What about Visual Studio 2010 RC?

Funny thing is, since I’ve been on leave, I pretty much found out that we were even having a public Release Candidate for Visual Studio 2010 the same time you probably did via ScottGu’s Blog post on the subject.

The good news is that the Visual Studio 2010 Release Candidate will include a newer version of ASP.NET MVC 2. We’re still working out the details of which exact version we will include, though I’d really like it to be the RC of ASP.NET MVC, assuming the logistics and schedule line up properly.

And of course, the Visual Studio 2010 RTM will include the ASP.NET MVC 2 RTM and at that point, all will be well with the world as installing tooling for ASP.NET MVC 2 will be supported on both VS 2008 and VS 2010 at the same time.

So again, we do understand this is an unfortunate situation and apologize for the inconvenience this may cause some of you. Aftor all, I feel the same pain! I want to install both versions on my machine just like you do. Fortunately, it’s only a temporary situation and will all be a bad memory when VS2010 RTM is released to the world. Thanks for listening.

asp.net, asp.net mvc comments edit

Paternity leave is not all fun and games. Mostly it’s soothing an irate baby and toddler while dealing with explosive poo episodes. Believe me when I say the term “blow out” is apt. That’s probably not the imagery you were hoping for in a technical blog post, but I think you can handle it. ;)066 What!? It’s already time for an RC?! I think I need to be changed.

While I’m on leave, the ASP.NET MVC team continues its hard work and is now ready to announce the release candidate for ASP.NET MVC 2. Go get it now!

Download ASP.NET MVC 2 Release Candidate

As always, the release notes provide a summary of what’s changed. Also, stay tuned as I expect we’ll see one of those epic ScottGu blog posts on the release soon.

Highlights

As you might expect from a release candidate, most of the work focused on bug fixes and improvements to existing features. We also spent a lot of time on performance profiling and optimization.

Much of the focus on this release was in the client validation scripts. For example, the validation script was moved into its own file and can be included at the top or bottom of the page. Client validation also now supports globalization.

The other change related to validation is that the ValidationSummary now supports overloads where only model-level errors are displayed. This is useful if you are displaying validation messages inline next to each form field. Previously, these messages would be duplicated in the validation summary. With these new changes, you can have the summary display an overall validation message (ex. “There were errors in your form submission”) as well as a list of validation messages which don’t apply to a specific field.

What’s Next?

RTM of course! The RTM release of ASP.NET MVC will be included in the RTM release of Visual Studio 2010, which is slated for some time in March. The VS2008 version of ASP.NET MVC 2 might release earlier than that. We’re still working out those details.

code comments edit

Many web applications (such as this blog) allow users to enter HTML as a comment. For security reasons, the set of allowed tags is tightly constrained by logic running on the server. Because of this, it’s helpful to provide a preview of what the comment will look like as the user is typing the comment.

sneak peek - by ArminH on
sxc.huThat’s exactly what my live preview jQuery plugin does.

See it in action

This is the first jQuery Plugin I’ve written, so I welcome feedback. I was in the process of converting a bunch of JavaScript code in Subtext to make use of jQuery, significantly reducing the amount of hand-written code in the project. Needless to say, it was a lot of fun. I decided to take our existing live preview code and completely rewrite it using JavaScript.

All you need for the HTML is an input, typically a TEXTAREA and an element to use as the preview, typically a DIV

<textarea class="source"></textarea>

<label>Preview Area</label>
<div class="preview"></div>

And the following script demonstrates one way to hook up the preview to the textarea.

$(function() {
    $('textarea.source').livePreview({
        previewElement: $('div.preview'),
        allowedTags: ['p', 'strong', 'br', 'em', 'strike'],
        interval: 20
    });
});

One thing that’s different between this implementation and others I’ve seen is you can specify a set of allowed tags. When typing in the textbox, the preview will render any tags in that list. If the user types in tags which are not in that list, the preview will HTML encode the tags.

Keep in mind that this plugin is for previewing what comments will look like and should not be used as validation! The preview might not exactly match your server-side logic.

Also for fun, I’m hosting the source code on GitHub as a way to force myself to learn what all the fuss is about GIT.

Thanks to Bohdan Zograf, this blog post is also available in Belarusian.

personal, code comments edit

Ok, it wasn’t necessarily my ass that was saved, but it was years worth of images which were important to me!

As I wrote yesterday, my blog’s hosting server had a hard-drive failure effectively wiping out my virtual machine, taking my blog down with it. Fortunately, I was able to get back up with a static archive of my site provided by Rich Skrenta, but I was missing all my images and other content (code samples).

As Jeff mentions,

I have learned the hard way that there are almost no organizations spidering and storing images on the web.

Keep in mind that the images are not just mere eye candy. In many cases, they serve to illustrate key concepts: “As you can see in the screenshot above, if the screenshot were still to exist, but through the sheer ineptitude of Phil you’ll have to guess at the knowledge it would have conveyed.

As I was lamenting the loss of these files, I started poking around my browser cache (finding this great tool for exporting the Google Chrome cache by the way which can retain directory structure) looking for stray images.

I then started thinking about alternative tools that might cache web content such as a client RSS reader, etc. Then it occurred to me, didn’t I run the IIS SEO Toolkit against my site recently (click to enlarge)?

SEO Toolkit
ScreenshotThe first time I saw the SEO Toolkit was when Carlos Aguilar gave me a demo a long while ago. Back then it was just something he put together over the weekend. As soon as I saw it I begged him (quite annoyingly I must say) to let me have a private build to try out. Eventually it was released and I was able to run it against Haacked.com to see how much I sucked.

Well it’s a good thing I ran it back in August! This tool stores a local cache of images. Oddly enough, it appends a .txt extension to every cached file.

cached-images No worries! Using a bit of DOS command magic, I was able to strip off the .txt extension from every file (note I ran this from the command line. If you put this in a batch file, you’ll need to double up on the % character).

for /r %x in (*.c) do ren “%x” “%~nx”

That stripped off the extensions. Afterwards I uploaded the images and am now only missing images for 18 blog posts, the posts written in August, September, and October of 2009. Those shouldn’t be too hard to recreate manually (though if you happen to have those images in your browser or RSS cache, I do appreciate you sending them to me! My email at Microsoft is philha)

Looks like I caught a lucky break this time in finding and leveraging the previously undocumented “Back up a website for dummies” feature in the IIS SEO Toolkit. Carlos, I owe you one! :)

UPDATE: If you were wondering why the cached files were stored with a .txt extension appended, Carlos revealed the mystery to me in an email.

Oh I forgot to explain that silly thing we do with file extensions is a “naïve-silly attempt” to reduce the accident of double-clicking a javascript, exe, or let the shell try to display ‘malign image’ that might come from external sites. Since in theory we consider that a ‘private’ cache we decided to do this silly trick to prevent any funky games with somebody generating an ‘brittney-spears-nude-picture.jpg.exe’ with the icon of a JPG file that lured someone into running it.

Agreed its pretty silly, but it was a simple ‘cheesy security feature’ easy to add for our ‘hidden cache’.

Basically it helps protect the double-click happy folks out there from hurting themselves accidentally.

personal comments edit

Yeah, the past few days have been a pretty low moment for me and this blog. Long story short, on December 11, a hard-drive failure took down the managed dedicated server which hosts my blog among other sites.

(The following image is a dramatization of actual events and is not the actual hard drive)

Crufty
Hard-DriveThis is a server that Jeff Atwood and I share (we each host a Virtual Server on the machine), thus all of the following sites were brought down by the hardware malfunction:

That list doesn’t include my personal Subversion server (yes, I’m planning to switch to GitHub for that).

The good news is that my hosting provider, CrystalTech, was taking regular backups of the machine. The bad news is that all of these sites were hosted in virtual machines. The Virtual Hard Drive files (usually referred to as VHD files) which contain the actual data for our virtual machines were always in use and were not being backed up, silently failing each time.

Properly backing up a live virtual server requires taking advantage of Volume Shadow Copy Service (VSS) as described in this blog post to backup live virtual server VMs, but this was not in place, probably due to a lack of coordination between us and the hosting provider.

Recovery

A data recovery company was brought in to try and recover the data. They replaced the drive head assembly and took a forensic image from the drive and started trying to recover our data. So far the actual VHD files we need have not yet been recovered. However, they were able to recover an older VHD I had backed up in 2007. That allowed me to grab all my content files such as images and code samples from back in 2007.

Luckily, I had recently backed up my database locally a few months ago. Not only that, thanks to the helpful Rich Skrenta, I was able to have a static web archive of my blog up and running quickly. He had a cache of both my and Jeff’s (http://codinghorror.com) blog with the directory structure intact! That allowed me to retain my permalinks and have my content in a readonly state. I can only assume this cache is related to his search engine startup, http://blekko.com/.

From there, I started using grepWin against a copy of those static HTML files to strip out the relevant information and convert the blog posts I didn’t have in my database into one big T-SQL script which would insert all the blog posts and comments back into my database.

I had to upgrade my blog to an unreleased version of Subtext because I was in the process of testing the latest version against the copy of my database. That’s why I copied it locally in the first place, so there might be potential wonkiness if I made any mistakes in the upgrade.

At this point, most of the content for my blog is back up. I’m missing some comments left on the most recent post and many of the images on posts after 2007. Unfortunately getting cached images en masse is a pretty big challenge.

I’m also missing some code samples etc, but I can start posting those back up there when I have time.

Lessons Learned

In general, I’m not a fan of the blame game as blame can’t change the past. It sucks, but what’s done is done. I’ll certainly let my hosting provider know what they can do better, but I also share in some of the blame for letting this happen.

What’s more interesting to me is learning from the past to help realize a better future, since that is something I can affect. What lessons did I learn (and re-learned because the lesson didn’t make it through my thick skull the first time) from this?

First and foremost as many mentioned to me on Twitter (thanks!):

An untested backup strategy is no backup strategy at all! Test your backups!

I think a corollary to that is to try and have a backup strategy that’s easy to setup. I actually had a process for backing up my database and content regularly, but when I moved to the new hosting provider, I forgot to set it up again.

I think the other lesson is that even if you have managed hosting, you should have your own local backups of the important content in your site.

Backup Strategy

I’m setting up a much better back-up strategy which will include automatic backup verifications by setting up my site on a local machine so I can browse the backup locally. When I get it in place, I’ll write a follow-up post and hope to get good suggestions on how to improve it.

UPDATE:Looks like I am having an issue with comments not showing up and over-aggressive spam controls. This is the result of dogfooding the latest trunk build of my software. ;) Glad to find these issues now before releasing the latest version. :)

UPDATE: 12/14/2009Jeff Atwood declares today to be International Backup Awareness Day and gives his perspective on the server failure that affected us both and how he sucks. Yes, I must share in that suck too.

UPDATE 12/14/2009 10:19 PMI was able to recover most of my images through a lucky break. I wrote about how the IIS SEO Toolkit saves the day.

Technorati Tags: hosting,backups,crystaltech,blog

aspnetmvc localization validation comments edit

This is the fourth post in my series on ASP.NET MVC 2 and its new features.

  1. ASP.NET MVC 2 Beta Released (Release Announcement)
  2. Html.RenderAction and Html.Action
  3. ASP.NET MVC 2 Custom Validation
  4. Localizing ASP.NET MVC Validation

In my recent post on custom validation with ASP.NET MVC 2, several people asked about how to localize validation messages. They didn’t want their error messages hard-coded as an attribute value.

world-in-handsIt turns out that it’s pretty easy to do this. Localizing error messages is not specific to ASP.NET MVC, but is a feature of Data Annotations and ASP.NET. And everything I cover here works for ASP.NET MVC 1.0 (except for the part about client validation which is new to ASP.NET MVC 2).

I covered this feature a back in March at Mix 09 in my ASP.NET MVC Ninjas on Fire Black Belt Tips talk. If you want to see me walk through it step by step, check out the video. If you prefer to read about it, continue on!

Let’s start with the ProductViewModel I used in the last post

public class ProductViewModel {
  [Price(MinPrice = 1.99)]
  public double Price { get; set; }

  [Required]
  public string Title { get; set; }
}

If we’re going to localize the error messages for the two properties, we need to add resources to our project. To do this, right click on your ASP.NET MVC project and select Properties. This should bring up the properties window. Click on the Resources tab. You’ll see a message that says,

This project does not contain a default resources file. Click here to create one.

Obey the message. After you click on the link, you’ll see the resource editor.

resources-tab Make sure to change the Access Modifier to Public(it defaults to Internal).

resources-tab-access-modifier

Now enter your resource strings in the resource file.

resource-file

Hopefully my Spanish is not too bad. An ASP.NET build provider will create a new class named Resources behind the scenes with a property per resource string. In this case there’s a property named PriceIsNotRight and Required. You can see the new file in the Properties folder of your project.

solution-with-resources

The next step is to annotate the model so that it pulls the error messages from the resources.

public class ProductViewModel {
  [Required(ErrorMessageResourceType = typeof(Resources),
    ErrorMessageResourceName = "Required")]
  public string Title { get; set; }
  [Price(MinPrice = 3.99, ErrorMessageResourceType = typeof(Resources),
    ErrorMessageResourceName = "PriceIsNotRight")]
  public double Price { get; set; }
}

For the ErrorMessageResourceType, I just specify the type created by the build provider. In my case, the full type name is CustomValidationAttributeWeb.Properties.Resources.

For the ErrorMessageResourceName, I just use the name that I specified in the resource file. The name identifies which resource string to use.

Now when I submit invalid values, the error messages are pulled from the resource file and you can see they are in Spanish.

Client Validation - Windows Internet
Explorer

Localized Error Messages Custom Client Validation

Note that these localized error messages continue to work even if you enable client validation. However, if you were to try it with the original code I posted in my last validation example, the error message would not work for the custom price validation attribute.

Turns out I had a bug in the code, which is now corrected in the blog post with a note describing the fix. Just scroll down to the PriceValidator class.

As always, I have a code sample you can look at. It’s the same example as before, just updated. Download the sample!

Tags: aspnetmvc, asp.net, validation, localization, data annotations

asp.net, code comments edit

Good news! I have contributed my T4 template to the .less project. You can access it from the big download button on their homepage.

Pain is often a great motivator for invention, unless you become dull to the pain. I think CSS is one of those cases where there’s a lot of pain that we as web developers often take in stride.

Fortunately not everyone accepts that pain and efforts such as LESS are born. As the home page states:

LESS extends CSS with: variables, mixins, operations and nested rules.

Best of all, LESS uses existing CSS syntax. This means you can rename your current .css files .less and they’ll just work.

LESS solves a lot of the pain of duplication when writing CSS. Originally written as a Ruby gem, Christopher Owen, Erik van Brakel and Daniel Hoelbing ported a version to .NET not surprisingly called .less. Here are some examples from the .less homepage:

.Less implements LESS as an HttpHandler you add to your website mapped to the .less extension. I think this is a great approach when combined with the proper cache headers in the response.

However, sometimes I just want to have static CSS files. So I decided to write a T4 template for .less. Simply drop it in a folder that contains .less files and it will generate a .css file for each .less file.

Not only that, I also added a setting to then minimize the CSS using the YUI Compressor for .NET. This allows you to write your CSS using clear readable .LESS syntax, but deploy minified CSS. To turn off minification just edit the T4 file to change the value of the _minified variable.

Usage is very easy. The following screenshot shows a folder containing a .less file, one for each sample on the .LESS homepage. Notice that I don’t actually reference the YUI compression nor .LESS libraries. I just added them to a solution folder so you could see them (and so the T4 template can find them).

solution-without-t4

With this in place, I can simply drop my T4CSS.tt file into the Css directory and voila!

solution-with-t4

You can see the converted CSS files by expanding the T4CSS.tt node in the solution explorer as shown in the screenshot above.

In order to produce multiple output files, I used the approach that Damien Guard did in his post, Multiple outputs from T4 made easy – revisited. Basically I just embedded his T4 in mine.

You’ll notice there’s an extra file, T4CSS.log, that’s generated. Unfortunately using Damien’s approach, it’s not possible to suppress the default file generated by the T4 template, so I used that to log the operations.

Also note that at the time of this writing, there’s a bug in .LESS that causes one of the samples to throw an exception. I reported it to the developers so hopefully that gets fixed soon.

Lastly, there have been T4 changes in Visual Studio 2010. I didn’t try this template with VS10 yet. When importing the assemblies, you may need to either add them to the GAC or reference them with a full path. When I get some time I’ll play around with that to see how to get it to work.

I have contributed this T4 template to the .less project. You can access it from the big download button on their homepage.

comments edit

Just wanted to highlight a couple of podcasts that were suckersgracious enough to have me as a guest.

microphone

HerdingCode

In this podcast I join the fellas at HerdingCode. Although this podcast came out after the Hanselminutes one, it was actually recorded a long time prior to that one. Jon Galloway, who does the editing, probably has some lame excuse about life changing events keeping him busy.

I spent most of the time covering what’s new with ASP.NET MVC 2 Preview 2, how the community influences our project, and how we prioritize bugs. I also finally reveal the dirty truth about Rob Conery’s departure from Microsoft.

What’s notable about this episode is the introduction of a brand new segment, “Abusive Questions from Twitter”. I was having problems with my Borg implant and there was disruption of the transmission of marketing answer from the mother ship. Hear me stumble and ramble through the answer to that one when all I really meant to say was “I think ASP.NET MVC has a lot going for it, but use what makes you happy.” These guys are great at putting you on the spot. :)

Listen: Herding Code 64: Phil Haack on MVC 2

Hanselminutes

In this one I chat with my friend and co-worker Scott Hanselman, who is as great an interviewer as he is a speaker.

We spend most of the interview talking about ASP.NET MVC 2 Beta.

This one is notable as the interview is interrupted by a call from the one and only ScottGu who says some words about me (audible on the podcast) that you never want to hear about you coming from your VP.

He was only joking. (Right Scott? Ha ha ha… It was a joke, right? Ha ha ha…. Ha?)

Listen: Hanselminutes Show #188: ASP.NET MVC 2 Beta with Phil Haack

I hope you enjoy them and if you hated them, I welcome constructive criticism. It’s so much easier to gather your thoughts when writing than when being interviewed. I’m impressed that these guys all do so well to be quick witted and come up with great questions time and time again.

Technorati Tags: asp.net,aspnetmvc,podcast

comments edit

UPDATE: I’ve updated this post to cover changes to client validation made in ASP.NET MVC 2 RC 2.

This is the third post in my series ASP.NET MVC 2 Beta and its new features.

  1. ASP.NET MVC 2 Beta Released (Release Announcement)
  2. Html.RenderAction and Html.Action
  3. ASP.NET MVC 2 Custom Validation

In this post I will cover validation.

storage.canoe No, not that kind of validation, though I do think you’re good enough, you’re smart enough, and doggone it, people like you.

Rather, I want to cover building a custom validation attribute using the base classes available in System.ComponentModel.DataAnnotations. ASP.NET MVC 2 has built-in support for data annotation validation attributes for doing validation on a server. For details on how data annotations work with ASP.NET MVC 2, check out Brad’s blog post.

But I won’t stop there. I’ll then cover how to hook into ASP.NET MVC 2’s client validation extensibility so you can have validation logic run as JavaScript on the client.

Finally I will cover some of changes we still want to make for the release candidate.

Of course, the first thing I need is a contrived scenario. Due to my lack of imagination, I’ll build a PriceAttribute that validates that a value is greater than the specified price and that it ends in 99 cents. Thus $20.00 is not valid, but $19.99 is valid.

Here’s the code for the attribute:

public class PriceAttribute : ValidationAttribute {
  public double MinPrice { get; set; }
    
  public override bool IsValid(object value) {
    if (value == null) {
      return true;
    }
    var price = (double)value;
    if (price < MinPrice) {
      return false;
    }
    double cents = price - Math.Truncate(price);
    if(cents < 0.99 || cents >= 0.995) {
      return false;
    }
       
    return true;
  }
}

Notice that if the value is null, we return true. This attribute is not intended to validate required fields. I’ll defer to the RequiredAttribute to validate whether the value is required or not. This allows me to place this attribute on an optional value and not have it show an error when the user leaves the field blank.

We can test this out quickly by creating a view model and applying this attribute to the model. Here’s an example of the model.

public class ProductViewModel {
  [Price(MinPrice = 1.99)]
  public double Price { get; set; }

  [Required]
  public string Title { get; set; }
}

And let’s quickly write a view (Index.aspx) that will display an edit form which we can use to edit the product.

<%@ Page Language="C#" Inherits="ViewPage<ProductViewModel>" %>

<% using (Html.BeginForm()) { %>

  <%= Html.TextBoxFor(m => m.Title) %>
    <%= Html.ValidationMessageFor(m => m.Title) %>
  <%= Html.TextBoxFor(m => m.Price) %>
    <%= Html.ValidationMessageFor(m => m.Price) %>
    
    <input type="submit" />
<% } %>
   

Now we just need a controller with two actions, one which will render the edit view and the other which will receive the posted ProductViewModel. For the sake of demonstration, these methods are exceedingly simple and don’t do anything useful really.

[HandleError]
public class HomeController : Controller {
  public ActionResult Index() {
    return View();
  }

  [HttpPost]
  public ActionResult Index(ProductViewModel model) {
    return View(model);
  }
}

We haven’t enabled client validation yet, but let’s see what happens when we view this page and try to submit some values.

price-invalid

As expected, it posts the form to the server and we see the error messages.

Making It Work In The Client

Great, now we have it working on the server, but how do we get this working with client validation?

The first step is to reference the appropriate scripts. In Site.master, I’ve added the following two script references.

<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"
></script>

The next step is to enable client validation for the form by calling EnableClientValidation before**we call BeginForm. Under the hood, this sets a flag in the new FormContext which lets the BeginForm method know that client validation is enabled. That way, if you set an id for the form, we’ll know which ID to use when hooking up client validation. If you don’t, the form will render one for you.

<%@ Page Language="C#" Inherits="ViewPage<ProductViewModel>" %>

<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) { %>

  <%= Html.TextBoxFor(m => m.Title) %>
    <%= Html.ValidationMessageFor(m => m.Title) %>
  <%= Html.TextBoxFor(m => m.Price) %>
    <%= Html.ValidationMessageFor(m => m.Price) %>
    
    <input type="submit" />
<% } %>
   

If you try this now, you’ll notice that the Title field validates on the client, but the Price field doesn’t. We need to take advantage of the validation extensibility available to hook in a client validation function for the price validation attribute we wrote earlier.

The first step is to write a ModelValidator associated with the attribute. Since the attribute is a data annotation, I can simply derive from DataAnnotationsModelValidator<PriceAttribute> like so.

public class PriceValidator : DataAnnotationsModelValidator<PriceAttribute> 
{
  double _minPrice;
  string _message;

  public PriceValidator(ModelMetadata metadata, ControllerContext context
    , PriceAttribute attribute)
    : base(metadata, context, attribute) 
  {
    _minPrice = attribute.MinPrice;
    _message = attribute.ErrorMessage;
  }

  public override IEnumerable<ModelClientValidationRule>   GetClientValidationRules() 
  {
    var rule = new ModelClientValidationRule {
      ErrorMessage = _message,
      ValidationType = "price"
    };
    rule.ValidationParameters.Add("min", _minPrice);

    return new[] { rule };
  }
}

The method GetValidationRules returns an array of ModelClientValidationRule instances. Each of these instances represents metadata for a validation rule that is written in JavaScript and will be run in the client. This is purely metadata at this point and the array will get converted into JSON and emitted in the client so that client validation can hook up all the correct rules.

In this case, we only have one rule and we are calling its validation type “price”. This fact will come into play later.

The next step is for us to now register this validator. Since we wrote this as a Data Annotations validator, we can register it in Application_Start as demonstrated by the following code snippet. If you you’re using another model validation provider such as the one for the Enterprise Library’s Validation Block, it might have its own means of registration.

protected void Application_Start() {
  RegisterRoutes(RouteTable.Routes);
  DataAnnotationsModelValidatorProvider
    .RegisterAdapter(typeof(PriceAttribute), typeof(PriceValidator));
}

At this point, we still need to write the actual JavaScript validation logic as well as the hookup to the JSON metadata. For the purposes of this demo, I’ll put the script inline with the view.

<script type="text/javascript">
  Sys.Mvc.ValidatorRegistry.validators["price"] = function(rule) {
    // initialization code can go here.
    var minValue = rule.ValidationParameters["min"];

    // we return the function that actually does the validation 
    return function(value, context) {
      if (value > minValue) {
        var cents = value - Math.floor(value);
        if (cents >= 0.99 && cents < 0.995) {
          return true; /* success */
        }
      }

      return rule.ErrorMessage;
    };
  };
</script>

Now when I run the demo, I can see validation take effect as I tab out of each field. Note that to get the required field validation to fire, you’ll need to type something in the field and then clear it before tabbing out.

Let’s pause for a moment and take a deeper look at what’s going on the code above. At a high level, we’re adding a client validator to a dictionary of validators using the key “price”. You may recall that “price” is the validation type we defined when writing the PriceValidator. That’s how we hook up this client function to the server validation attribute.

You’ll notice that the function we add to the validators itself returns a function which does the actual validation. Why is there this seemingly extra level of indirection? Why not simply add a function that does the validation directly to the dictionary?

This approach allows us to run some initialization code at the time the validator is being hooked up to the metadata (as opposed to every time validation occurs). This is helpful if you have expensive initialization logic. The validate method of the object we return in that initialization method may get called multiple times when the form is being validated.

Notice that in this case, the initialization code grabs the min value from the ValidationParameters dictionary. This is the same dictionary created in the PriceValidator class, but now living on the client.

We then run through similar logic as we did in the server side validation code. The difference here is we return null to indicate that no error occurred and we return an array of error messages if an error occurred.

Validation using jQuery Validation?

Client validation in ASP.NET MVC is meant to be extremely extensible. At the core, we emit some JSON metadata describing what fields to validate and what type of validation to perform. This makes it possible to build adapters which can hook up any client validation library to ASP.NET MVC.

For example, if you’re a fan of using jQuery it’s quite easy to use our adapter to hook up jQuery Validation library to perform client validation.

First, reference the following scripts.

<script src="/Scripts/jquery-1.4.1.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcJQueryValidation.js" type="text/javascript">
</script>

When we emit the JSON in the page, we define it as part of an array which we declare inline. If you view source you’ll see something like this (truncated for brevity):

<script type="text/javascript"> 
//<![CDATA[
if (!window.mvcClientValidationMetadata) {
  window.mvcClientValidationMetadata = []; 
}
window.mvcClientValidationMetadata.push({
  {"Fields":[{"FieldName":"Title",...,
    "ValidationRules":
      [{"ErrorMessage":"This field is required",...,        "ValidationType":"required"}]},
   ...);
//]]>
</script>

Note the array named window.mvcClientValidationMetadata.

Simply by referencing the MicrosoftMvcJQueryValidation script, you’ve hooked up jQuery validation to that metadata. Both of the validation adapter scripts look for the existence of the special array and consumes the JSON within the array.

How about a demo?

And before I forget, here’s a demo application demonstrating the attribute described in this post.

Tags: aspnetmvc, validation, client validation, asp.net

comments edit

One of the upcoming new features being added to ASP.NET MVC 2 Beta is a little helper method called Html.RenderAction and its counterpart, Html.Action. This has been a part of our ASP.NET MVC Futures library for a while, but is now being added to the core product.

Both of these methods allow you to call into an action method from a view and output the results of the action in place within the view. The difference between the two is that Html.RenderAction will render the result directly to the Response (which is more efficient if the action returns a large amount of HTML) whereas Html.Action returns a string with the result.

For the sake of brevity, I’ll use the term RenderAction to refer to both of these methods. Here’s a quick look at how you might use this method. Suppose you have the following controller.

public class MyController {
  public ActionResult Index() {
    return View();
  }
  
  [ChildActionOnly]
  public ActionResult Menu() {
    var menu = GetMenuFromSomewhere();
      return PartialView(menu);
  }
}

The Menu action grabs the Menu model and returns a partial view with just the menu.

<%@ Control Inherits="System.Web.Mvc.ViewUserControl<Menu>" %>
<ul>
<% foreach(var item in Model.MenuItem) { %>
  <li><%= item %></li>
<% } %>
</ul>

In your Index.aspx view, you can now call into the Menu action to display the menu:

<%@ Page %>
<html>
<head><title></title></head>
<body>
  <%= Html.Action("Menu") %>
  <h1>Welcome to the Index View</h1>
</body>
</html>

Notice that the Menu action is marked with a ChildActionOnlyAttribute. This attribute indicates that this action should not be callable directly via the URL. It’s not required for an action to be callable via RenderAction.

We also added a new property to ControllerContext named IsChildAction. This lets you know whether the action method is being called via a RenderAction call or via the URL.

This is used by some of our action filters which should do not get called when applied to an action being called via RenderAction such as AuthorizeAttribute and OutputCacheAttribute.

Passing Values With RenderAction

Because these methods are being used to call action methods much like an ASP.NET Request does, it’s possible to specify route values when calling RenderAction. What’s really cool about this is you can pass in complex objects.

For example, suppose we want to supply the menu with some options. We can define a new class, MenuOptions like so.

public class MenuOptions {
    public int Width { get; set; }
    public int Height { get; set; }
}

Next, we’ll change the Menu action method to accept this as a parameter.

[ChildActionOnly]
public ActionResult Menu(MenuOptions options) {
    return PartialView(options);
}

And now we can pass in menu options from our action call in the view

<%= Html.Action("Menu", 
  new { options = new MenuOptions { Width=400, Height=500} })%>

Cooperating with the ActionName attribute {.clear}

Another thing to note is that RenderAction honors the ActionName attribute when calling an action name. Thus if you annotate the action like so.

[ChildActionOnly]
[ActionName("CoolMenu")]
public ActionResult Menu(MenuOptions options) {
    return PartialView(options);
}

You’ll need to make sure to use “CoolMenu” as the action name and not “Menu” when calling RenderAction.

Cooperating With Output Caching

Note that in previous previews of the RenderAction method, there was an issue where calling RenderAction to render an action method that had the OutputCache attribute would cause the whole view to be cached. We fixed that issue by by changing the OutputCache attribute to not cache if it’s part of a child request.

If you want to output cache the portion of the page rendered by the call to RenderAction, you can use a technique I mentioned here where you place the call to RenderAction in a ViewUserControl which has its OutputCache directive set.

Summary

Let us know how this feature works for you. I think it could really help simplify some scenarios when composing a user interface from small parts.

comments edit

This is the first in a series on ASP.NET MVC 2 Beta

  1. ASP.NET MVC 2 Beta Released (Release Announcement)
  2. Html.RenderAction and Html.Action
  3. ASP.NET MVC 2 Custom Validation

Today at PDC09 (the keynote was streaming live), Bob Muglia announced the release of ASP.NET MVC 2 Beta. Feel free to download it right away! While you do that I want to present this public service message.

fptopsecret

The Beta release includes tooling for Visual Studio 2008 SP1. We did not ship updated tooling for Visual Studio 2010 because ASP.NET MVC 2 is now included as a part of VS10, which is on its own schedule.

Unfortunately, because Visual Studio 2010 Beta 2 and ASP.NET MVC 2 Beta share components which are currently not in sync, running ASP.NET MVC 2 Beta on VS10 Beta 2 is not supported.

Here are some highlights of what’s new in ASP.NET MVC 2.

  • RenderAction (and Action)
  • AsyncController
  • Expression Based Helpers (TextBoxFor, TextAreaFor, etc.)
  • Client Validation Improvements (validation summary)
  • Add Area Dialog
  • Empty Project Template
  • And More!

Go Live

ASP.NET MVC 2 Beta also includes an explicit go-live clause within the EULA. You should make sure to read it has an interesting clause which references the operation of nuclear facilities, aircraft navigation, etc. ;)

More Details Please!

You can find more details about this release in the release notes. Also be on the look out for one of ScottGu’s trademark blog posts covering what’s new

I’ve started working on a series of blog posts where I will cover features of ASP.NET MVC 2 in more detail. I’ll start publishing these posts one at a time soon.

Next Stop: RC

Our next release is going to be the release candidate hopefully before the year’s end. The work from now to RC will consist almost solely of bug fixes with a few minor feature improvements and changes.

Please do play with the Beta. If you run into an issue that’s serious enough, there’s still time to consider changes for RC. Otherwise it will have to wait for ASP.NET MVC 3 which I’m just starting to think about.

I’m thinking, “man, I can’t believe I’m already thinking about version 3”!”

Tags: aspnetmvc, asp.net

comments edit

I learned something new yesterday about interface inheritance in .NET as compared to implementation inheritance. To illustrate this difference, here’s a simple demonstration.

I’ll start with two concrete classes, one which inherits from the other. Each class defines a property. In this case, we’re dealing with implementation inheritance.

public class Person {
    public string Name { get; set; }
}

public class SuperHero : Person {
    public string Alias { get; set; }
}

We can now use two different techniques to print out the properties of the SuperHero type: type descriptors and reflection. Here’s a little console app that does this. Note the code I’m showing below doesn’t include a few Console.WriteLine calls that I have in the actual app.

static void Main(string[] args) {
  // type descriptor
  var properties = TypeDescriptor.GetProperties(typeof(SuperHero));
  foreach (PropertyDescriptor property in properties) {
    Console.WriteLine(property.Name);
  }

  // reflection
  var reflectedProperties = typeof(SuperHero).GetProperties();
  foreach (var property in reflectedProperties) {
    Console.WriteLine(property.Name);
  }
}

Let’s look at the output of this code.

impl-inheritance

No surprises there.

The SuperHero type has two properties, Alias defined on SuperHero and the Name property inherited from its base type.

But now, let’s change these classes into interfaces so that we’re now dealing with interface inheritance. Notice that ISupeHero now derives from IPerson.

public interface IPerson {
  string Name { get; set; }
}

public interface ISuperHero : IPerson {
  string Alias { get; set; }
}

I’ve also made the corresponding changes to the console app.

var properties = TypeDescriptor.GetProperties(typeof(ISuperHero));
foreach (PropertyDescriptor property in properties) {
  Console.WriteLine(property.Name);
}

// reflection
var reflectedProperties = typeof(ISuperHero).GetProperties();
foreach (var property in reflectedProperties) {
  Console.WriteLine(property.Name);
}

Before looking at the next screenshot, take a moment to answer the question, what is the output of the program now?

interface-inheritance Well it should be obvious that the output is different otherwise I wouldn’t be writing this blog post in the first place, right?

When I first tried this out, I found the behavior surprising. However, it’s probably not surprising to anyone who has an encyclopedic knowledge of the ECMA-335 Common Language Infrastructure specification (PDF) such as Levi, one of the ASP.NET MVC developers who pointed me to section 8.9.11 of the spec when I asked about this behavior:

8.9.11 Interface type derivation Interface types can require the implementation of one or more other interfaces. Any type that implements support for an interface type shall also implement support for any required interfaces specified by that interface. This is different from object type inheritance in two ways:

  • Object types form a single inheritance tree; interface types do not.
  • Object type inheritance specifies how implementations are inherited; required interfaces do not, since interfaces do not define implementation. Required interfaces specify additional contracts that an implementing object type shall support.

To highlight the last difference, consider an interface, IFoo, that has a single method. An interface, IBar, which derives from it, is requiring that any object type that supports IBar also support IFoo. It does not say anything about which methods IBar itself will have.

The last paragraph provides a great example of why the code I wrote behaves as it does. The fact that ISuperHero inherits from IPerson doesn’t mean the ISuperHero interface type inherits the properties of IPerson because interfaces do not define implementation.

Rather, what it means is that any class that implements ISuperHero must also implement the IPerson interface. Thus if I wrote an implementation of ISuperHero such as:

public class Groo : ISuperHero {
  public string Name {get; set;}
  public string Alias {get; set;}
}

The Groo type must implement both ISuperHero and IPerson and iterating over its properties would show both properties.

Implications for ASP.NET MVC Model Binding

You probably could have guessed this part was coming. Let’s say you’re trying to use model binding to bind the Name property of an ISuperHero. Since our model binder uses type descriptors under the hood, we won’t be able to bind that property for the reasons stated above.

I learned of this detail investigating a bug reported in StackOverflow. It turns out this behavior is by design. In the context of sending a view model to the view, that view model should be a simple carrier of data. Thus it makes sense to use concrete types on your view model, in contrast to your domain models which will more likely be interface based.

comments edit

I was stepping through some code in a debugger today and noticed a neat little feature of Visual Studio 2010 that I hadn’t noticed before.

When debugging, you can easily examine the value of a variably by highlighting it with your mouse. Nothing new there. But then I noticed a little pin next to it, which I’ve never seen before.

debugger-value

So what do you see when you see a pin? You click on it!

pinned-quick-watch

As you might expect, that pins the quick watch in place. So now I hit the play button, continue running my app in the debugger, and the next time I hit that breakpoint:

pinne-watch-changed

I can clearly see the value changed since the last time. I think this may come in useful when walking through code as a way of seeing the value of important variables right next to where they are declared. I thought that was pretty neat.

asp.net, code comments edit

This code has been incorporated into a new RouteMagic library I wrote which includes Source Code on CodePlex.com as well as a NuGet package!

I saw a bug on Connect today in which someone offers the suggestion that the PageRouteHandler (new in ASP.NET 4) should handle IHttpHandler as well as Page.

I don’t really agree with the suggestion because while a Page is an IHttpHandler, an IHttpHandler is not a Page. What I this person really wants is a new handler specifically for http handlers. Let’s give it the tongue twisting name: IHttpHandlerRouteHandler.

Unfortunately, it’s too late to add this for ASP.NET 4, but it turns out such a thing is trivially easy to write. In fact, here it is.

public class HttpHandlerRouteHandler<THandler> 
    : IRouteHandler where THandler : IHttpHandler, new() {
  public IHttpHandler GetHttpHandler(RequestContext requestContext) {
    return new THandler();
  }
}

Of course, by itself it’s not all that useful. We need extension methods to make it really easy to register routes for http handlers. I wrote a set of those, but will only post two examples here on my blog. To get the full set download the sample project at the very end of this post.

public static class HttpHandlerExtensions {
  public static void MapHttpHandler<THandler>(this RouteCollection routes,     string url) where THandler : IHttpHandler, new() {
    routes.MapHttpHandler<THandler>(null, url, null, null);
  }
  //...
  public static void MapHttpHandler<THandler>(this RouteCollection routes, 
      string name, string url, object defaults, object constraints) 
      where THandler : IHttpHandler, new() { 
    var route = new Route(url, new HttpHandlerRouteHandler<THandler>());
    route.Defaults = new RouteValueDictionary(defaults);
    route.Constraints = new RouteValueDictionary(constraints);
    routes.Add(name, route);
  }
}

This now allows me to register a route which is handled by an IHttpHandler very easily. In this case, I’m registering a route that will use my SimpleHttpHandler to handle any two segment URL.

public static void RegisterRoutes(RouteCollection routes) {
    routes.MapHttpHandler<SampleHttpHandler>("{foo}/{bar}");
}

And here’s the code for SampleHttpHandler for completeness. All it does is print out the route values.

public class SampleHttpHandler : IHttpHandler {
  public bool IsReusable {
    get { return false; }
  }

  public void ProcessRequest(HttpContext context) {
    var routeValues = context.Request.RequestContext.RouteData.Values;
    string message = "I saw foo='{0}' and bar='{1}'";
    message = string.Format(message, routeValues["foo"], routeValues["bar"]);

    context.Response.Write(message);
  }
}

When I make a request for /testing/yo I’ll see the message

I saw foo=’testing’ and bar=’yo’

in my browser. Very cool.

Limitation

One limitation here is that my http handler has to have a parameterless constructor. That’s not really that bad of a limitation since to register an HTTP Handler in the old way you had to make sure that the handler had an empty constructor.

However, this code that I wrote for this blog post is based on code that I added to Subtext. In that code, I am passing an IKernel (I’m using Ninject) to my HttpRouteHandler. That way, my route handler will use Ninject to instantiate the http handler and thus my http handlers aren’t required to have a parameterless constructor.

Try it out!

The RouteMagic solution includes a sample project that demonstrates all this.

asp.net, code, asp.net mvc comments edit

This is the second in a three part series related to HTML encoding blocks, aka the <%: ... %> syntax.

In a recent blog post, I introduced ASP.NET 4’s new HTML Encoding code block syntax as well as the corresponding IHtmlString interface and HtmlString class. I also mentioned that ASP.NET MVC 2 would support this new syntax when running on ASP.NET 4.

In fact, you can try it out now by downloading and installing Visual Studio 2010 Beta 2.

I’ve also mentioned in the past that we are not conditionally compiling ASP.NET MVC 2 for each platform. Instead, we’re building System.Web.Mvc.dll against ASP.NET 3.5 SP1 and simply including that one in VS08 and VS10. Thus when you’re running ASP.NET MVC 2 on ASP.NET 4, it’s the same byte for byte assembly as the same one you would run on ASP.NET 3.5 SP1.

This fact ought to raise a question in your mind. If ASP.NET MVC 2 is built against ASP.NET 3.5 SP1, how the heck does it take advantage of the new HTML encoding blocks which require that you implement an interface introduced in ASP.NET 4?

The answer involves a tiny bit of voodoo black magic we’re doing in ASP.NET MVC 2.voodoo

We introduced a new type MvcHtmlString which is created via a factory method, MvcHtmlString.Create. When this method determines that it is being called from an ASP.NET 4 application, it uses Reflection.Emit to dynamically generate a derived type which implements IHtmlString.

If you look at the source code for ASP.NET MVC 2 Preview 2, you’ll see the following method call when we are instantiating an MvcHtmlString:

Type dynamicType = DynamicTypeGenerator.
  GenerateType("DynamicMvcHtmlString", 
    typeof(MvcHtmlString), new Type[] {

Note that we’re using a new internal class, DynamicTypeGenerator, to generate a brand new type named DynamicMvcHtmlString. This type derives from MvcHtmlString and implements IHtmlString. We’ll return this instance instead of a standard MvcHtmlString when running on ASP.NET 4.

When running on ASP.NET 3.5 SP1, we simply new up an MvcHtmlString and return that, completely bypassing the Reflection.Emit logic. Note that we only generate this type once per AppDomain so you only pay the Reflection Emit cost once.

The code in DynamicTypeGenerater is standard Reflection.Emit stuff which at runtime creates an assembly at runtime, adds this new type to it, and returns a lambda used to instantiate the new type. If you’ve never seen Reflection.Emit code, it’s worth a look.

In general, we really frown on this sort of “tricky” code as it’s often hard to maintain and a potential bug magnet. For example, since System.Web.Mvc.dll is security transparent, we needed to make sure that the assembly we generate is marked with the SecurityTransparentAttribute. This is something that would be easy to overlook until you start testing in medium trust scenarios.

However, in this case, the type we’re generating is very small and very simple. Not only that, we only need to keep this code for one version of ASP.NET MVC. ASP.NET MVC 3 will be compiled against ASP.NET 4 only (no support for ASP.NET 3.5 planned) and we’ll be able to remove this “clever” code and have much more straightforward code. I’m looking forward to that. :)

In any case, the point of this post was to fulfill a promise I made in an earlier post where I said I’d give some more details on how ASP.NET MVC 2 works with the new Html encoding block feature.

This is all behind-the-scenes detail that’s not necessary to understand to use ASP.NET MVC, but might be interesting to some of you. Especially those who ever find themselves in a situation where you need to support forward compatibility.

asp.net comments edit

Have you ever needed to quickly spawn a web server against a local folder to preview a web application? If not, what would you say you do here?

This is actually quite common for me since I receive a lot of zip files containing web applications which reproduce a bug. After I unzip the repro, I need a way to quickly point a web server at the folder and run the web site.

A while back I wrote about a useful registry hack to do just this. It adds a right click menu to start a web server (Cassini) pointing to any folder. This was based on a shell extension by Robert McLaws.

Well that was soooo 2008. It’s almost 2010 and Visual Studio 2010 Beta 2 is out which means it’s time to update this shell extension to run an ASP.NET 4 web server.

add-web-server-here

Obviously this is not rocket science as I merely copied my old settings and updated the paths. But if you’re too lazy to look up the new file paths, you can just copy these settings (changes are in bold).

32 bit (x86)

Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\VS2010 WebServer]
@="ASP.NET 4 Web Server Here"
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\VS2010 WebServer\command]
@="C:\\Program Files\\Common Files\\microsoft shared\\DevServer
\\10.0\\Webdev.WebServer40.exe /port:8081 /path:\"%1\""

64 bit (x64)

Windows Registry Editor Version 5.00
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\VS2010 WebServer]
@="ASP.NET 4 Web Server Here"
 
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\VS2010 WebServer\command]
@="C:\\Program Files (x86)\\Common Files\\microsoft shared\\DevServer
\\10.0\\Webdev.WebServer40.exe /port:8081 /path:\"%1\""

I chose a different port and name for this shell extension so that it lives side-by-side with my other one.

Of course, I wouldn’t even bother trying to copy these settings from this blog post since I conveniently zipped up .reg files you can run.

asp.net comments edit

You probably don’t need me to tell you that Visual Studio 2010 Beta 2 has been released as it’s been blogged to death all over the place. Definitely check out the many blog posts out there if you want more details on what’s included.

This post will focus more on what Visual Studio 2010 means to ASP.NET MVC and vice versa.

Important: If you installed ASP.NET MVC for Visual Studio 2010 Beta 1, make sure to uninstall it (and VS10 Beta 1) before installing Beta 2.

In the box baby!

Well one of the first things you’ll notice is that ASP.NET MVC 2 Preview 2 is included in VS10 Beta 2. When you select the File | New menu option, you’ll be greeted with an ASP.NET MVC 2 project template option under the Web node.

New
Project

Note that when you create your ASP.NET MVC 2 project with Visual Studio 2010, you can choose whether you wish to target ASP.NET 3.5 or ASP.NET 4.

multi-target

If you choose to target ASP.NET 4, you’ll be able to take advantage of the new HTML encoding code blocks with ASP.NET MVC which I wrote about earlier.

As an aside, you might find it interesting that the System.Web.Mvc.dll assembly we shipped in VS10 is the exact same binary we shipped out-of-band for VS2008 and .NET 3.5. How then does that assembly implement an interface that is new in ASP.NET 4? That’s a subject for another blog post.

What about ASP.NET MVC 1.0?

Unfortunately, we have no plans to support ASP.NET MVC 1.0 tooling in Visual Studio 2010. When we were going through planning, we realized it would’ve taken a lot of work to update our 1.0 project templates. We felt that time would be better spent focused on ASP.NET MVC 2.

However, that doesn’t mean you can’t develop an ASP.NET MVC 1.0 application with Visual Studio 2010! All it means is you’ll have to do so without the nice ASP.NET MVC specific tooling such as the add controllerandadd viewdialogs. After all, at it’s core, an ASP.NET MVC project is a Web Application Project.

Eilon Lipton, the lead dev for ASP.NET MVC, wrote a blog post a while back describing how to open an ASP.NET MVC project without having ASP.NET MVC installed. All it requires is for you to edit the .csproj file and remove the following GUID from the <ProjectTypeGuids> element.

{603c0e0b-db56-11dc-be95-000d561079b0};

Once you do that, you’ll be able to open, code, and debug your project from VS10.

Upgrading ASP.NET MVC 1.0 to ASP.NET MVC 2

Another option is to upgrade your ASP.NET MVC 1.0 application to ASP.NET MVC 2 and then open the upgraded project with Visual Studio 2010 Beta 2.

Eilon has your back again as he’s written a handy little tool for upgrading existing ASP.NET MVC 1.0 applications to version 2.

After using this tool, your project will still be a Visual Studio 2008 project. But you can then open it with VS10 and it knows how to open and upgrade the project to be a VS10 project.

What about automatic upgrades?

We are investigating implementing a more automatic process for upgrading ASP.NET MVC 1.0 applications to ASP.NET MVC 2 when you try to open the existing project in Visual Studio 2010. We plan to have something in place by the RTM of VS10.

Ideally, when you try to open an ASP.NET MVC 1.0 project, instead of showing an error dialog, VS10 will provide a wizard to upgrade the project which will be somewhat based on the sample Eilon provided. So be sure to supply feedback on his wizard soon!

Tags: aspnetmvc, asp.net, visual studio 2010, visual studio

comments edit

Despite what your well intentioned elementary school teachers would have liked you to believe, there is such a thing as a stupid question, and you probably get them all the time via email or IM.

You also know that in half the time it takes to type the question, the person pestering you could have typed the query in their favorite search engine and received an answer immediately.

Let me Google that for you addressed this little annoyance by providing a passive aggressive means to tell annoying question askers to bugger off while at the same time teaching them the power of using a search engine to help themselves.

lmbtfyWhen I first heard about the Microsoft’s new search engine, Bing, I jumped at purchasing the domain name http://letmebingthatforyou.com/ (though I was remiss in not also registering lmbtfy.com as well. If you own that domain, may I buy it off of you?)

Unfortunately, being way too busy caused me to leave the domain name unused gathering dust until I put out a call on Twitter for help. Not long after Maarten Balliauw and Juliën Hanssens answered the call and put together the bulk of this ASP.NET MVC application using jQuery and jQuery UI.

I really like what they did in that the background image for http://letmebingthatforyou.com/ changes daily to match the one on bing.com. I finally found some time to review the code, do a bit of clean-up, fix some minor issues, and test it so I am now ready to deploy it.

Keep in mind that even though I’m employed by Microsoft, this site is a pet project I’m doing on the side in collaboration with Maarten and Juliën and is in not associated with Microsoft nor Bing in any official capacity. We’re just some folks doing this for fun.

Now go try it out and release your inner snarkiness.