asp.net comments suggest edit

The ASP.NET Team is still looking for that QA person out there who shares our passion for technology and improving the means by which software is made.

Keep in mind that the QA position on our team is not someone who mindlessly follows a script hoping by sheer random luck to find bugs. Oh no no no my friends.

This is considered a software development position in which you will be responsible for improving the processes and tools we have in place for ensuring quality software. You’d be involved in improving the quality of all phases of product development as a valued member of a feature crew. Think broadly about the idea of software quality. Your role is to question whether we’re building the right product as much as it is to test the product once it is built.

Matt Osborn, a member of the ASP.NET MVC feature crew has a description of the position.

That’s right you read the title right the ASP.NET QA team is once again hosting ninja try outs. We are looking for someone who is able to help evolve the team processes, improve our tooling, and join us in the trenches as we test one of the best technologies out there. Overall the team is responsible for ASP.NET WebForms, ASP.NET MVC, Microsoft AJAX, and a whole slew of other technologies. Our technologies can be found in numerous large scale web sites such as MySpace.com, Dell.com andDeals.Woot.com.

Once again we would like to find someone that shares our passion for our technology and our trade and someone that has spent sometime in the trenches. So if this sounds like something you’re interested in polish your nun chucks, practice your disappearing skills, and slice your way through our job posting. In the meantime while your sword is out for sharpening send Mark Berryman (one of our managers) an email.

PS: If you listen to the Coding QA podcast you can get a good feel for what it is like being the frontline testing ninjas for ASP.NET. We had a great turn out last time and please feel free submit your resume again it can’t hurt.

Keep in mind we’re not looking for “test” ninjas as in “sample” ninjas. We’re looking for the real deal, brimming with throwing stars of bug finding. Ok, the analogy breaks down a bit there. But you get the picture.

And before I forget, here’s the direct link to the job description on the Microsoft careers site.

subtext, code comments suggest edit

This blog is experiencing technical difficulties. Do not adjust your browser.

Hi there. If you’ve tried to visit this blog recently you might have noticed it’s been down a lot in the last two days. My apologies for that, but hopefully you found what you needed via various online web caches.

I’ve been dogfooding the latest version of Subtext and as CodingHorror points out, dogfood tastes bad.

I’ve done a lot of testing on my local box, but there are a class of bugs that I’m only going to find on a high traffic real site, and boy have I found them!

Some of them might be peculiar to my specific data or environment, but others were due to assumptions I made that were wrong. For example, if you use ThreadPool.QueueUserWorkItem to launch a task, and that task throws an unhandled exception, that can bring your entire App Domain down. Keep that in mind if you think to use that method for a fire-and-forget style task.

In any case, the point of this post is to say that we’re not going to release the next version of Subtext until it’s rock solid. My blog going down occasionally is the cost I’m incurring in order to make sure the next version of Subtext is a beast that won’t quit.

code comments suggest edit

UPDATE: 12/30 I had transposed the rgb colors. I corrected the function.

I’ve been distracted by a new jQuery plugin that I’m writing. The plugin has certain situations where it sets various background and foreground colors. You can have it set those styles explicitly or you can have it set a CSS class, and let the CSS stylesheet do the work.

color-wheelI’m writing some unit tests to test the former behavior and ran into an annoying quirk. When testing the color value in IE, I’ll get something like #e0e0e0, but when testing it in FireFox, I get rgb(224, 224, 224).

Here’s a function I wrote that normalizes colors to the hex format. Thus if the specified color string is already hex, it returns the string. If it’s in rgb format, it converts it to hex.

function colorToHex(color) {
    if (color.substr(0, 1) === '#') {
        return color;
    }
    var digits = /(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(color);
    
    var red = parseInt(digits[2]);
    var green = parseInt(digits[3]);
    var blue = parseInt(digits[4]);
    
    var rgb = blue | (green << 8) | (red << 16);
    return digits[1] + '#' + rgb.toString(16);
};

Now, I can compare colors like so.

equals(colorToHex('rgb(120, 120, 240)'), '#7878f0');

I hope you find this useful. :)

code comments suggest 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 suggest 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 suggest 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 suggest 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 suggest 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 suggest 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 suggest 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 suggest 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 suggest 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 suggest 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 suggest 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