dotnet, vs comments edit

If you’ve enabled FxCop to run on your projects in Visual Studio, chances are you’ve seen the dreaded CA0060 warning:

MSBUILD : warning : CA0060 : The indirectly-referenced assembly ‘SomeAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=abcdef1234567890’ could not be found. This assembly is not required for analysis, however, analysis results could be incomplete. This assembly was referenced by: C:\Path\To\Some\Dependency.dll.

The MSDN docs on this warning say that you should just add a reference to the indirectly referenced assembly so FxCop can find it. The problem is, if you already have a reference to a later version of the indirect dependency, you can’t really reference both versions.

I found a forum post that explains that you can change the behavior of FxCop to allow resolution of dependency assemblies to look at the strong name info but ignore the version. You do that by adding the following to FxCopCmd.exe.config in the C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop folder:

<add key="AssemblyReferenceResolveMode" value="StrongNameIgnoringVersion" />

Of course, if you do that, it affects every single solution on your machine. Plus, you have to tell every developer on your team to make the same change, and… ugh. No.

A little Reflectoring shows that you can actually specify a lot more on the command line than running FxCopCmd /? says you can. Here are the ones I found that don’t show up:

  • assemblycomparemode
  • dump
  • failonassert
  • outputculture
  • targetframeworkversion
  • trace
  • tracefile

That assemblycomparemode one is what ties to the AssemblyResolveReferenceMode value from FxCopCmd.exe.config. In fact, you can pass this value in on the command line if you were running FxCopCmd.exe manually:

FxCopCmd.exe /assemblycomparemode:StrongNameIgnoringVersion [and the rest of your parameters]

Except, you’re running from inside Visual Studio, so you don’t have access to the command line… or do you?

Poking through the C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\CodeAnalysis\Microsoft.CodeAnalysis.Targets file that gets installed with Visual Studio (and is what runs FxCop), it turns out that if you provide a property called $(CodeAnalysisAdditionalOptions) with the list of additional command line options you want for FxCop, they’ll be passed in. You just have to do a little manual .csproj hacking to add the property.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <!-- This is the first PropertyGroup in your project. -->
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <!-- ...and all the other stuff, then before the group end: -->
    <CodeAnalysisAdditionalOptions>/assemblycomparemode:StrongNameIgnoringVersion</CodeAnalysisAdditionalOptions>
  </PropertyGroup>
  <!-- ...and then the rest of your project file. -->
</Project>

Now when FxCop runs, that command line parameter list will be passed in along with everything else and the CA0060 warning will go away. Plus, the setting is transported along with the individual project, so it doesn’t affect your installed config files and you don’t have to get any developers to do anything to their machines. Done!

home comments edit

I’m pissed off with home improvement.

See, the thing is, I’m not really handy. I like to think I am. I can put up a new light fixture with the best of them. Tightening screws on squeaky chair legs or whatever, I have that covered. Much more than that… I’m sort of at a loss.

About three weeks back my dad helped me fix some baseboards that had water damage. At the time, I figured I had put off this crown moulding project in our downstairs bathroom for seven years already and it was probably time to undertake that, so I decided to pick up some crown moulding to put up. Couldn’t be that much different than baseboards, right? Just baseboards at the top of your wall instead of the bottom, right?

The best advice I can give you: If you want to put up crown moulding, call The Guy.

When I say “The Guy,” I’m talking about any contractor who will come in with experience in the crown moulding arena and put it up for you in a professional fashion. In conversation, you might refer to this person as “your crown moulding guy” when you hand a poor sap like me his (or her) business card.

I had what I thought to be all the right equipment. I had the compound miter saw. I had the angle measuring tool. I was all set to go.

I measured out the first couple of pieces and the angle between the walls, cut them out, and put them up. They looked awesome. See? I even took a picture:

The start of my crown moulding
project.

Nice crisp corners, all professional. I was stoked.

Then I tried to fit the next piece in. I could get one corner in place, but the other corner… didn’t fit quite right. It wasn’t too far off, though, and I figured a little caulk and I’d be good. I muscled forward.

Corner after corner, things started getting further and further off. That was when I noticed something:

My walls aren’t flat, my ceiling isn’t flat, and the corners between the walls and the ceiling isn’t square.

The corners from wall to wall are square, but that’s the only thing in the bathroom that is. There’s one wall where the ceiling makes sort of a “wave” where it connects to the wall, going up and down rather than straight. On another wall it’s even worse - you take the crown moulding, run it from one corner to another, and there’s a gap between the crown moulding and the ceiling so big I can put my fingers in there.

But I would not be deterred! I could flex the moulding into place! I could fill that gigantic gap with some patching plaster! It would work!

Two or three hours a night after work for a week and we get to the weekend. I stand back and look at the horrendous corners, the places on the ceiling where I got a little carried away with the patching plaster and filled in the texture, and the ridiculously obvious use of wood filler in areas, and… it was unsalvageable. I showed Jenn and she concurred.

I tore the moulding down, took it out back, and chopped the shit out of it with an axe. You know, so it’d fit in the garbage can better. Right? Right?

I chipped the patching plaster away from the ceiling, spackled up the nail holes, and retextured the ceiling where the plaster got out of hand. All we had left to do was paint the spackle areas…

…Except Home Depot doesn’t sell the paint we used for that bathroom anymore, so we had to get a color match. No problem there, we got the color matched perfectly…

…Except we didn’t get the sheen matched right, so we had some shiny spots and some matte spots where the different paint was used, which resulted in having to repaint the entire bathroom.

All of the patching and retexturing and painting and everything was another hour or two each night for a week. Two weeks, many hours, and around $100… and we’re back to square one. Maybe I could have just handed someone $100 to come over and kick me in the nuts and we could have called it a day.

What this boils down to is: Call The Guy.

I wish I could say this was the end of our current home improvement troubles, but it’s not.

A few nights ago we were sitting watching television and we heard a big “thump” like a bird hit the back sliding glass door. I went out back to see what was up and didn’t see any bird, so I went back inside. As I did, I tried to shut the screen door and it just wouldn’t shut. Investigating further, it turns out the frame on the door was flexed out of shape, dented in a certain spot, so now it doesn’t slide on the track right. Oh, and look over there, in the middle of the back porch there’s a river rock the size of a baseball. How the heck did that get there? (Putting two and two together, I’m guessing someone threw it, so I’m glad it just hit my screen door and not the glass, but still.) So now I have to get a new screen door ($45) which is not a huge deal except that I can’t actually fit a screen door into my car, so I have to get some help trucking that home. It’s never simple.

Oh, and our Scooba just died, so I’m going to have to get a new one of those. And Jenn’s car has something up with some belt or another, so that’s gotta get fixed. Man, it’s always something.

traffic comments edit

Dear Stop Light Idler:

I do not understand why you think it’s good to stop six car lengths back from the stop light and idle slowly forward, occasionally tapping the brakes, until you get to the actual stop line. I’m writing you today to ask your help so I can understand.

Do you feel you’re somehow being safer? That actually stopping at the line is not quite as safe as stopping 25m before the line?

Or is it that you don’t trust your brakes? I might - might - actually understand this one, since you do tap them several times during your idle-up-to-the-line, almost like you have to verify they’re still working; that, yes, the brakes will, in fact, continue to stop the car.

Maybe it’s that you’re trying to get some sort of “running start” at the light when it signals you to go. You know, so you can “beat” the car in the other lane off the line? Is that it? The drag racer in you?

Honestly, I’m at a loss. From back here, behind you, watching you inch-forward-and-stop, inch-forward-and-stop, inch-forward-and-stop… from back here, it just looks like you’re not paying attention. It also looks like you have no consideration for the line of cars behind you who would like to just sit at the signal and wait for it to change rather than constantly trying to keep up with your inching. Because you know that if the rest of the line doesn’t inch up with you, that the one driver who doesn’t move forward looks like a big douche for being the guy who’s got six car lengths in front of him and isn’t moving up.

You probably also don’t realize that some traffic signals are timed, but some are magnetically-sensitive. If you don’t actually get your car into that little box up there by the stop line, the signal won’t change. Or maybe you do, and that’s part of your daily plan to piss off the other drivers behind you.

Can you explain why you’re doing this? Is there even a reason? (If there is, are you sure it’s a good one?) Because, honestly, when I’m behind you, you ride my road rage nerve. If someone - and I’m not saying me, but someone - pulled you out of the car and punched you in the throat, I might not mind so much. Just sayin’.

Please, I implore you, stop being a traffic asshole. Just pull up to the damn light (or a reasonable distance behind the next car in front of you) and stop. No need to inch. No need to tap the brakes. Just hang out. Be zen about it.

Love,

Travis

home comments edit

Had a bit of a home improvement weekend.

We have these water fountains for the cats - one upstairs, one downstairs. We noticed that the one upstairs was getting filled a lot more often over the course of a week than it had been and figured it was just that the cats were more thirsty or something. No, turns out the fountain was leaking.

The short version is that the carpet was a bit wet and everything was generally OK except for the baseboards near the fountain, which had expanded (yay, pressboard!) and were basically water damaged so we had to replace them.

If you have to replace your baseboards in your house, just assume that Home Depot and Lowes will not have the exact type you have installed. They just won’t. I don’t care if you bought it there last week, that trim is now out of style and you’ll get something really close to what you had, but it won’t be exact. This will cause you to have to replace a bigger section than you really wanted to because they have to match. If you are unlucky, this means the entire room. (We were lucky and only had to replace a small corner by the door.)

Over the course of last week I got the new baseboard painted and got all the tools ready for the weekend job. Saturday my dad came over and showed me how to use the complex miter saw that I inherited a while ago but have basically ignored since I got it. Learning! Anyway, with his help we got the new section up and it looks like new. Actually, slightly better than new because the replacement I bought was the same pattern but a bit thicker and better quality than the baseboards originally in the room.

Of course, neither of us are professionals at this so replacing like four feet of baseboards took something like three hours. No cursing or drinking was involved/required, though. It went smoothly.

After that, my dad and I took a break and played the last few levels of Gears of War 2 on co-op, which was fun, while Jenn and my mom went shopping.

That was Saturday.

Lego Imperial Shuttle

Sunday, other than the little chores that need to get done because you’re lazy about them all week, I finally got the opportunity to sit down with my new Lego set that I got thanks to the tax return. It’s a big 2503-piece behemoth Star Wars ship. (My favorite ship, in fact, from the Star Wars universe, which is why I bought it.) Phillips Double Chocolate Porter, my recently-acquired Reboot DVDs, and Legos. That’s a recipe for a nice afternoon, right there.

The Lego set has four separate instruction manuals. I only really got through the first 2/3 of the first manual in a couple of hours, so it looks like this will be a long project, which is fine. I like building Legos. It’s like putting together a super cool 3D puzzle. I’m recording it with our video camera so I can make a time-lapse video of the construction.

Slightly related: At the same time I bought the new baseboards, I also bought the crown moulding for the bathroom that we painted back in 2004. At the time we totally intended to put up crown moulding and then somehow it never happened. We didn’t have a saw, we didn’t have time, we didn’t have inclination. Well, now that I have the saw, I know how to use it, and I’m already in that DIY mode, I figure it’s time. I’ve got the boards, they’re painted, they just need to be cut and put up.

dotnet, coderush, aspnet comments edit

I’m a huge CodeRush and Refactor user and DevExpress fan, but my day job is developing web sites so I thought I’d give the DevExpress MVC Extensions a run to see how they work.

The DevExpress MVC Extensions are sort of like web controls - like HtmlHelper methods combined with some client-side script - that allow you to easily provide rich client-side widgetry in your MVC applications. I’m always interested in easy ways to provide a nice experience, so this sounds pretty good to me.

The first thing I noticed, even before I got a chance to use the extensions, was the seamless install process. I had already installed CodeRush/Refactor using the separate DevExpress IDE Tools installer, but when I ran the full DX Universal installer it totally picked up that I had some components installed and went to a “Modify” operation rather than not seeing the previously installed tools and telling me to re-install. I had actually built up in my head that I was going to have trouble with this, but it was totally cool. It’s the little things, right?

After installing, I decided to start up a new project to test things out in. There is an article on DevExpress that explains how to integrate with your existing site, but I really wanted to start a clean project to mess around in. The article explaining how to integrate with an existing project is, admittedly, a little intimidating. Much is just one-time setup, adding assembly references and so forth, but it’s not a short list of steps. Luckily, for new projects, DevExpress adds some project templates that allow you to start up with everything pre-wired.

[New Project dialog with DevExpress project templates. Click to
enlarge.

The project template generates something very similar to the standard MVC3 project, with a few placeholder items like the HomeController and Index views.

Default project structure for DevExpress MVC3
project.

You’ll also see several references to the DevExpress assemblies.

DevExpress assembly references in the MVC3
project.

If you look at the Home/Index view, there’s really nothing interesting there. What’s interesting is in the Site.Master, where you’ll see the stylesheet and script references that were added for the MVC extensions.

[Site.Master code generated by DevExpress template. Click to
enlarge.

When you fire up the site, the initial view (Home/Index) really doesn’t have anything on it - it’s a blank slate.

Initial view of DevExpress MVC3
project.

This, though, is where the fun begins.

First, let’s look at how the references in the Site.Master translate to rendered code:

[Initial script references. Click to
enlarge.

As you can see, there’s some script and CSS combining going on, so you only have one file transfer for script and one for CSS when you add the extensions. The default set of script/CSS provided a ~350KB script (a gzipped version of 1.5MB script) and a ~27KB CSS file (a gzipped version of a 278KB CSS file). Note that the script/CSS is only zipped, not minified, so I think there’s an opportunity for DevExpress to reduce the overhead further.

Now that we have a basic project skeleton in order, I figured I would do something slightly more robust than a standard “Hello World” to test these out. A simple contact list sounds like a reasonably simple, yet more than “Hello World,” solution, so that’s what I went for.

I’m going to yada yada over some of the details of putting the scaffolding in place because that part’s not interesting. Basically I added a one-table database with a Person object that has first and last name (strings), birthdate (DateTime), and a biography (HTML). (Here’s the metadata buddy class.)

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace DevExpressMvcApplication1.Models
{
  [MetadataType(typeof(PersonMetadata))]
  public partial class Person
  {
    public class PersonMetadata
    {
      [Required]
      [StringLength(50)]
      [DisplayName("First Name")]
      public object FirstName { get; set; }

      [Required]
      [StringLength(50)]
      [DisplayName("Last Name")]
      public object LastName { get; set; }

      [Required]
      [DataType(DataType.Date)]
      public object Birthdate { get; set; }

      [DataType(DataType.Html)]
      public object Biography { get; set; }
    }
  }
}

…as well as the controller actions and views for simple list/create/details/edit/delete operations.

First, the list view. For that, I exercised the GridView extension.

The GridView extension is an AJAX grid that appears to be an MVC-friendly wrapper around the extraordinarily robust ASPxGridView control. Adding a GridView via the extension has basically four steps:

  1. Add a partial view that contains the grid proper.
  2. In the main view, render the partial view with your grid.
  3. Add a controller action that returns just the grid partial view.
  4. In the grid definition, indicate which action renders your grid partial view so sort operations, etc., can do the appropriate callback.

I threw a couple of test people into my database and ran it. Here’s what I came out with:

Default GridView with no
enhancements.

That’s not too shabby for like two minutes’ worth of work. Clicking the little arrow or a different header changes the sort order/column as expected. Each click calls the controller action that returns the partial view, so it’s working a little like an UpdatePanel control in ASP.NET - rather than getting the data as JSON and client-side binding, the whole view is returned and replaces the grid.

That default grid is with a pretty minimal configuration:

<%
Html.DevExpress().GridView(
  settings =>
  {
    settings.Name = "indexList";
    settings.CallbackRouteValues = new { Controller = "Person", Action = "IndexListView" };
    settings.Width = 450;
    settings.Columns.Add("LastName").SortOrder = DevExpress.Data.ColumnSortOrder.Ascending;
    settings.Columns.Add("FirstName");
  })
  .Bind(Model)
  .Render();
%>

That Html.DevExpress() bit is common for the MVC Extensions - that’s how you access the DevExpress functionality. After that, you can see a pretty simple settings structure that shows the client ID of the tablet that will be generated, the callback info for the partial view rendering action, and info on which columns are displayed.

Something I thought interesting was that the sort order is managed entirely by the grid. When the partial view action gets called, you just hand the view the raw data and the grid deals with sorting it. I’m not sure how I feel about that. On the one hand, it’s nice to not have to worry about it and fiddle with it in my controller action; on the other hand, it’s sort of abstracted away, so if I want to do something different if a specific column is sorted or whatever, I’m into a more web forms style programming model where I’m handling events like DataBound.

Another thing I noticed was in looking at the column headers. The ALT text on the sort direction arrows was inserted for me, which is nice, but I couldn’t figure out how I’d localize that text.

<td style="width:100%;">Last Name</td><td style="padding-left:5px;"><img class="dxGridView_gvHeaderSortUp" src="/DXR.axd?r=1_3-uURn2" alt="(Ascending)" style="border-width:0px;" /></td>

I admittedly didn’t put a load of time into researching it, and with a settings object that has ~60 properties, I’m sure it’s possible… but I could spend all day on this thing and there is more stuff to look at, so I didn’t dwell on it. It did occur to me that with so many settings, there’s probably a heck of a learning curve figuring out what all of them do and when you’d use each one. Not a bad thing, just something to be aware of.

OK, so we have a grid. Let’s put some links to get to the “delete” and “details” views on people. I’ll make the last name column clickable so you can get to the details view from there. Doing this is simple if you know how, but it took me a while to figure it out. Again, we get a small taste of web forms style programming by setting column template contents using DataBinder.Eval and so forth. Not bad, just slightly different than that bare-metal-HTML feel you might be used to in MVC view creation. Same thing with adding a little delete link column - reasonably simple. Here’s the code we end up with…

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Person>>" %>
<%
  Html.DevExpress().GridView(
    settings =>
    {
      settings.Name = "indexList";
      settings.CallbackRouteValues = new { Controller = "Person", Action = "IndexListView" };
      var deleteColumn = settings.Columns.Add("", "");
      deleteColumn.HeaderStyle.HorizontalAlign = HorizontalAlign.Center;
      deleteColumn.CellStyle.HorizontalAlign = HorizontalAlign.Center;
      deleteColumn.SetDataItemTemplateContent(c =>
        {%>
        <a href="<%: Url.Action("Delete", new { Id = DataBinder.Eval(c.DataItem, "Id") }) %>">
          <img src="<%: Url.Content("~/Content/Delete.png") %>" alt="Delete" style="border: none;" />
        </a>
        <%});
      var lastNameColumn = settings.Columns.Add("LastName");
      lastNameColumn.SortOrder = DevExpress.Data.ColumnSortOrder.Ascending;
      lastNameColumn.SetDataItemTemplateContent(c =>
        {%>
        <%= Html.ActionLink(
            DataBinder.Eval(c.DataItem, "LastName").ToString(),
            "Details",
            new { Id = DataBinder.Eval(c.DataItem, "Id") })
        %>
        <%});
      settings.Columns.Add("FirstName");
    })
    .Bind(Model)
    .Render();
%>

…and here’s the resulting grid:

GridView with delete and details
links.

Nice. Now, you probably have two questions about this:

  1. Could I have accomplished this just using an HTML table and some foreach looping? Sure, but what I get by using the extension is the sorting, AJAX loading, and additional flexibility that the logic inside the GridView brings. It comes with a bit of a price in that you do dip your toe back in the web forms waters, so whether it’s appropriate for you will be a balance between your desire to remain pure and your desire for packaged super-functionality.
  2. Could I have added inline editing and deleting? Yes, I could have done everything right in the grid, adding editing templates and delete confirmations and all that right there. That might even have been a nicer user experience. On the other hand, it would have effectively sidestepped my experimentation with the rest of the controls, which is sort of the point here, so I’m doing things the long way.

Anyway, GridView is pretty slick and far beyond what I’d normally term “robust.” A little web-forms-ish, but if you’re trying to package up this kind of logic in some sort of reusable format, I’m not sure how else you’d do it. It also has a non-trivial learning curve, but wow, does it have features layered on features. Enough so it’s really difficult to even give it a fair evaluation because you’d spend weeks delving into it. Check out some of the demos on the DevExpress site to see the features I didn’t get into. What’s more robust than robust? Now you have the answer: the DevExpress MVC extensions GridView.

Now that we have the delete and edit links in place, let’s wire things up. There’s not a lot of interesting anything going on with the delete view, so I’m not going to go there. The good stuff is in the details and edit views, so let’s dig into those.

I’m a big fan of the DataAnnotations support in MVC and the whole Html.DisplayFor() method of displaying and editing models, so I figured I’d create a display and edit template for our Person model.

Easy enough to add a quick partial view in the DisplayTemplates folder for handling my Person model, but even with the option to scaffold some default details HTML in there to display the various fields, we can clean it up a bit. Let’s try the Rounded Panel extension to add just a little flair for fun. A quick bit of code in DisplayTemplates/Person.ascx…

<%
  Html.DevExpress().RoundPanel(
    settings =>
    {
      settings.Name = "personDetails";
      settings.HeaderText = String.Format("{0} {1}", this.Model.FirstName, this.Model.LastName);
      settings.ShowHeader = true;
      settings.View = DevExpress.Web.ASPxRoundPanel.View.Standard;
      settings.Width = 315;
      settings.SetContent(() =>
      {%>
        <div class="display-label">Birthdate</div>
        <div class="display-field"><%: String.Format("{0:d}", Model.Birthdate) %></div>
        <div class="display-label">Biography</div>
        <div class="display-field"><%= Model.Biography %></div>
      <%});
    })
    .Render();
%>

…and we have a nice little view:

Details view with a
RoundPanel.

It was at this point I decided I wanted to do some styling. For example, I wanted to make the person’s name in the header be bold and maybe a little larger. Simply throwing a CSS class on the header didn’t seem to fix it, though, since the HTML that the rounded panel generates is… a bit more complex than you might think.

Styling the MVC extensions is somewhat unintuitive and is a more involved process than you realize. The way you’re supposed to do what I want to do is to use the theme deployer tool to manually deploy the CSS used to style these controls (which is normally stored as embedded resources in an assembly) and then manually tweak the deployed files. I put out a call for help on this in the forums which confirmed this. It feels like overkill when I just want to style a single element. It also implies that these controls will probably not work easily with other styling tools like jQuery ThemeRoller (though, admittedly, I didn’t try). Note that in the forum response, they did mention they’re working on an easier way to do this.

OK, so, moving on. We have our details view, it’s in a nice RoundPanel, let’s create an editor view. I threw a link on the details page so we can get to the edit view, then added a simple editor template and view. It all starts out looking like this:

Default edit view. Not very
pretty.

Well, that’s not very pretty, so let’s add a little model metadata to clean up the display information and throw a RoundPanel around it to make it at least a bit consistent with the details view.

Edit view with a RoundPanel. Better, but still not
done.

Better, but not done. To make date editing nicer, I figured I’d try out the Date Edit MVC Extension. This is a nice date picker control that has a very good user experience. You can type the date in, pick it from a calendar, allow for character masking… it’s really pretty sweet. Definitely check out the demo on the DevExpress site on this one because there’s no way I can exercise it all right here.

Anyway, easiest way to get dates all editing the same way is to add an editor template for dates to my project, so that’s what I’ll do. I created a Shared/EditorTemplates folder and a DateTime.ascx control that has the following code in it:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime?>" %>
<%
  Html.DevExpress().DateEdit(
    settings =>
    {
      settings.Name = this.ViewData.ModelMetadata.PropertyName;
      settings.Properties.NullText = "MM/dd/yyyy";
      settings.Properties.EditFormat = EditFormat.Date;
      if (this.Model.HasValue)
      {
        settings.Date = this.Model.Value;
      }
    }
  )
  .Render();
%>

That ends up rendering the date picker like this, so you can click the dropdown arrow and get the calendar:

DevExpress date picker.
SHINY.

Niiiiice.

Adding date editing with the Date Edit extension was super simple. Really, the only challenging bit about it was setting the “Name” property since you have to do that manually rather than letting the framework infer it for you. This is an easy way of getting a nice, robust date picking/editing user experience into your site.

Good, so we have date editing covered for the birthdate field, let’s deal with editing the biography field. For this one, I want to have a nice, rich HTML editor so the biography can be formatted and not just text. (Yes, in real life this would open us up to XSS attacks, but we’re demoing here, so we’re not really focusing on security.)

The MVC extensions come witha super-rich HTML editor, so I figured I’d use that. Same drill as with the date editor - a new EditorTemplate for HTML data.

Except… looking at the HTML editor, it’s not quite as drop-in-and-go as all that. It’s closer to the GridView in setup, with a need for various callback actions and so forth. The key here is to start with the documentation rather than the demo code since the documentation provides a much simpler starting point that allows you to skip the extra bells and whistles and add them on later.

First thing I did was to add an Html.ascx in my Shared/EditorTemplates folder that will serve as the template for editing HTML fields. Inside that editor template, I added the call to Html.RenderPartial as outlined in the documentation.

Note: In setting this up, I encountered early on that due to the need to render a partial view from a partial view, when the HTML editor posts to the server to get an updated view you lose your model metadata. That means you have to propagate things like the model property name manually, and it’s sort of painful. You’ll see where I add in some ViewData settings and such to accommodate this.

So, the HTML editor template looks like this:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.String>" %>
<%
  this.ViewData["PropertyName"] = this.ViewData.ModelMetadata.PropertyName;
  Html.RenderPartial("HtmlEditorPartial");
%>

That’s not a very exciting view, but what it does is gets our editor template in place. Then I added a new partial view in the Shared folder called HtmlEditorPartial.ascx. That partial view is where I render the actual HTML editor.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.String>" %>
<%
  var propertyName = this.ViewData["PropertyName"].ToString();
  Html.DevExpress().HtmlEditor(
    settings =>
    {
      settings.Name = propertyName;
      settings.CallbackRouteValues = new { Controller = "HtmlEditor", Action = "HtmlEditorPart", PropertyName = propertyName };
      if (this.Model != null)
      {
        settings.Html = this.Model;
      }
    })
    .Render();
%>
<input type="hidden" name="<%= this.ViewData["PropertyName"].ToString() %>" />

Again, note how I’m getting the model metadata property name from a ViewData value I set manually. You have to do this due to the indirect partial-rendering-partial callback that goes on, and you have to keep that available.

I’ll explain that extra hidden field later. It has to do with a challenge I found around model binding. Anyway…

The last thing I did was add a controller that will handle the callbacks from the HTML editor. I called it HtmlEditorController and there’s only one action on it - HtmlEditorPart, which renders the editor’s partial view.

using System;
using System.Web.Mvc;

namespace DevExpressMvcApplication1.Controllers
{
  public class HtmlEditorController : Controller
  {
    public ActionResult HtmlEditorPart(string propertyName)
    {
      this.ViewData["PropertyName"] = propertyName;
      return PartialView("HtmlEditorPartial");
    }
  }
}

It was at this point I got stuck.

Even though I was setting the Name property on the HTML editor correctly (to, in this case, “Biography”), when I’d get the postback I’d have a ton of fields that all start with “Biography” (like “Biography_CurDialog,” “Biography_TD_T0CI,” “Biography$TD$T1$ITCNT0$ctl00,” and so on) but no actual field called “Biography” would come back in the POST. If you’re trying to get this to work with model binding, that’s sort of a showstopper. I posted a question to the forums and got pointed to an example that shows how to get the HTML back out of the editor - you need to use a special HtmlEditorExtension.GetHtml() method. That sort of throws a wrench in the works as far as model binding is concerned because it means I would have to manually extract the value in some sort of a controller action. Given the way EditorTemplates work, partial views and whatnot, that’s not so easy. (A later response pointed me to a class called DevExpressEditorsBinder that is used for binding data coming from other editor controls, but apparently it’s not yet updated to work with the HTML editor.)

I tried adding a custom model binder for HTML data types, but the problem you run into is that the HTML editor still doesn’t post a value with the right name so when model binding runs, it doesn’t see a field matching the name of the property (“Biography”) and doesn’t even run the binder. The way I ended up working around this is to add a hidden input field with an empty value to the HTML editor partial view and give that input field the name of the HTML editor. (That’s why you see it in the partial view earlier.) Since the HTML editor doesn’t generate any input field with that name, there’s no overlap, and it makes it so something with the appropriate property name gets posted back and model binding will run. Then I added a custom model binder that verifies the data type of the field being parsed and if it’s HTML, it uses that GetHtml method I mentioned earlier.

using System;
using System.Web.Mvc;
using DevExpress.Web.Mvc;

namespace DevExpressMvcApplication1
{
  public class HtmlModelBinder : IModelBinder
  {
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
      if (bindingContext.ModelMetadata.DataTypeName == "Html")
      {
        return HtmlEditorExtension.GetHtml(bindingContext.ModelName);
      }
      else
      {
        return ModelBinders.Binders.DefaultBinder.BindModel(controllerContext, bindingContext);
      }
    }
  }
}

You have to register that model binder at application startup for the System.String datatype so it’ll fire.

ModelBinders.Binders.Add(typeof(string), new HtmlModelBinder());

Now any string property marked with [DataType(DataType.Html)] will go through the appropriate model binder and have the HTML properly pulled out of the HTML editor control.

That was a little painful and not straightforward. I think the HTML editor is pretty cool, but I feel like I jumped through a few hoops on that one. Maybe this isn’t the primary use case for it or something.

The last thing I wanted to try was adding model validation in. This article’s running a bit on the long side already so I’ll cut right to it:

  • I wasn’t able to get the jQuery validation working. I fought with it for about an hour, but simply setting the web.config parameters and/or setting Html.EnableClientValidation() didn’t do it. The form always seemed to post, regardless of the validity of the fields, though the server would properly see model validation was incorrect. I ended up adding the original MicrosoftMvcValidation.js style validation back in and disabling the jQuery validation and that worked.
  • Thedemo showing validation using the MVC extensionssays it’s using standard DataAnnotations model validation but when you look at the demo code, it’s doing some really crazy custom stuff. (It appears the demos for the custom DevExpress validation and the DataAnnotations validation are the same.) I did not want to spend a ton of time on this but I have a feeling there was something I wasn’t wiring up properly, or that maybe there’s some flag or setting I wasn’t wiring up right.
  • Validation with the date picker was effortless. It validates just like a text box, no problems. I didn’t have to wire anything special up.
  • I didn’t try validation with the HTML editor. After working through the model binding issue, I didn’t want to get into the validation thing. It may have been easy, but somehow I’m thinking I’d have gotten into writing custom client-side adapters or trying to mix the DevExpress validation in with the DataAnnotations validation, which doesn’t sound like a five minute task.

So, given all that, the results of my spike with the DevExpress MVC Extensions:

  • They look really nice. Out of the box, the styles are really nice so it makes it simple to add some quick hotness to your site.
  • Custom styling isn’t fall-down easy. The controls can get a little complex so you do need to look at using the DevExpress themes that ship with the extensions, possibly with customizations. You probably won’t be able to get by just throwing a couple of quick overrides in a separate CSS file, and it may be a challenge to figure out what to change to achieve the results you want.
  • Simple use cases are a breeze. It was easy to sub the date picker in as my date editor and just as easy to get validation working in it.
  • Damn, I love that date picker. I just wanted to throw that in there again. I’d almost buy the package just for that really nice date picker.
  • The complex controls are very full-featured but can be complex to work with. The GridView and HTML editor have a ton of fantastic features, but they’re not really fall-down simple to work with. While there are a lot of demos, figuring out what each line in the demo does and whether or not it’s something you’re interested in doing in your own code is a challenge. The documentation is reasonable from an API standpoint but there could probably stand to be a bit more “how to” style docs. Not just demos, but more explanation of the various features, what they do, and how you use them. Model binding, as you saw, was also a challenge in the more complex controls (HTML editor), though hopefully that will get easier as new versions are released.
  • There’s still a touch of web forms in places. For example, the GridView exposing data binding events, working with DataBinder.Eval, and so forth, felt pretty web forms to me. I’m not sure what I’d like to see instead, but you’ve probably read in places that “data binding in MVC is a foreach loop” - it might be nice to see something closer to that level of simplicity.
  • Callback partial views can throw a wrench in the works. The GridView and HTML editor, being AJAX-y controls, need partial views that they can call back to and update their content. You saw how this made using the HTML editor a bit of a challenge in an EditorTemplate. I can see that it may get a little less than straightforward in other areas, too.
  • DevExpress support is awesome. I’ve had a great experience working with the DevExpress folks - community, tech support, devs - throughout my relationship with them using CodeRush and Refactor, and using the MVC Extensions is no different. You get quick answers in the forums, they’re receptive to input (they even filed an enhancement request based on my forum post!)… honestly, there are a small handful of companies that are a joy to work with like this. That counts for a lot.

Anyway, that was a bit longer than I thought it was going to turn out… but hopefully that helps you on your way to cooler web sites.