Tim Scott's Blog

November 30, 2009

A Question Of Astonishment

Filed under: FluentHtml, Programming — Tim Scott @ 5:26 pm

Steve Michelotti recently found a very subtle bug in MvcContrib.FluentHtml.   It provides us with a rather interesting case of applying the Principle Of Least Astonishment (a.k.a. Rule Of Least Surprise).

It turns out that FluentHtml’s select helper lets the user express his intent vaguely.  Consider whether this test should pass:

[Test]
public void when_determining_selected_values_select_should_ignore_selected_method_if_any_options_are_marked_selected()
{
    var list = new List<SelectListItem>
    {
        new SelectListItem { Text = "Acura", Value = "1", Selected = true },
        new SelectListItem { Text = "BMW", Value = "2" },
    };

    var select = new Select("foo.Bar").Selected(2).Options(list);

    var optionNodes select.ToString().ShouldHaveHtmlNode("foo_Bar").ShouldHaveChildNodesCount(2);
    optionNodes[0].ShouldBeSelectedOption(1, "Acura");
    optionNodes[1].ShouldBeUnSelectedOption(2, "BMW");
}

See what we have done here? We have allowed the user to express which options should be selected in two, possibly contradictory ways. In the call to Options, the user has specified that Acura should be selected. In the call to Selected, she has specified that Honda should be selected. How should we interpret what she really wants?

The first path to consider is to change the API to remove the chance for vaugeness. In most cases this is highly preferable. In this case, however, the cat is already out of the bag so to speak. That is, changing the API in this way would be a big breaking change.  Furthermore, it is deliberate and I believe very useful that the API offers a lot of ways to specify select options.

That leaves us to invoke the Rule Of Least Surprise. When a user specifies vague intent, in the manner that we have described, I can see five reasonable outcomes:

  1. Selected items are only those expressed via Selected
  2. Selected items are only those expressed via Options
  3. Selected items are a union of those expressed via Selected and Options
  4. Selected items are only those expressed via Options or Selected, whichever is called last
  5. Selected items are only those expressed via Options unless none, then those expressed via Selected

I will reject #4 out of hand.  FluentHtml helpers are essentially builders.  And with builders, order should never be important.  #1 and #2 are the next to go.  I cannot think of a better argument for either, and so the choice would be arbitrary.  It’s a rather close call between #3 and #5, but I will choose #5.  Here is the thinking.   If the user has specified selected items within the options themselves, then calling Selected is clearly a mistake on his part and he should expect it to be ignored.  On the other hand, if he did not specify selected items within the options list, then he could reasonably expect the call to Selected to be honored.

Would you make a different choice?

November 5, 2009

MVC 2 Areas Gotchas

Filed under: MS MVC — Tim Scott @ 12:24 am

I am adding ASP.NET MVC to a legacy WebForms application. Hallelujah! 

The process has gone very well.  I am here to report, do not fear the hybrid application!  At first we put the MVC parts directly into the legacy app.  It only required a bit of fiddling around to create a custom view engine. Later we decided to move the MVC parts into an “area project” using the new MVC 2.  This MSDN walkthrough was our guide.  The purpose of this post is to report a couple tricky gotchas that we encountered along the way.

GOTCHA #1:  By default, the area folder is named after the assembly, not the area name.

The walkthrough shows code for an AreaRegistration class:

public class Routes : AreaRegistration
{
    public override string AreaName
    {
        get { return "Store"; }
    }

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            "Store_Default",
            "Store/{controller}/{action}/{id}",
            new { controller = "Products", action = "List", id = "" }
        );
    }
}

Notice that the Name property is “Store” which matches the first node of the route.  It might seem that this is significant, but as far as I can tell it is not.  What is significant is that the project name “Store” matches the first node of the route.  So route needs to start with your assembly name.  

Okay, but what if my porject is named “Foo.Bar.Store”?  I don’t want my route to be “Foo.Bar.Store/{controller}/{action}/{id}”.  Fortuantely you can change this.  Here’s how.

The walkthrough gives instructions to modify the project files, which includes adding the following AfterBuild task to your “area project:”

<CreateAreaManifest AreaName=”$(AssemblyName)” AreaType=”ChildAreaPath=”$(ProjectDir)” ManifestPath=”$(AreasManifestDir)” ContentFiles=”@(Content)” />

Change it to this:

<CreateAreaManifest AreaName=”StoreAreaType=”ChildAreaPath=”$(ProjectDir)” ManifestPath=”$(AreasManifestDir)” ContentFiles=”@(Content)” />

What this does is tells MSBuild to copy the view folders from the “area project” into the parent project to a location named “Views/Areas/Store” rather than “Views/Areas/Foo.Bar.Store”.

GOTCHA #2: Manifest files are not recreated with every build.

The CreateAreaManifest task does not actually tell MS Build where to copy the view files and folders.  Rather it tells MSBuild how to create a manifest file.  This file contains the details that MSBuild will later use to copy the view files and folders.  But there is a gotcha.  Once a manifest file has been created, subsequent builds add to it, rather than to trash it and create a fresh one.  Therefore, if you change the CreateManifestArea task in the project file, you will need to manually delete the corresponding manifest file. This is a real pain, and maybe there’s some way around it, but not that I know about.

September 29, 2009

The Tale Of The Tape

Filed under: Programming — Tim Scott @ 4:44 am

Joel Spolsky recently set off another flurry of discussion in the blogosphere with his post extolling the noble duct tape programmer.  Most of it was not too bad.  But what could have been a nice rant against architecture astronouts was ruined when he drew a false dichotomy between overwrought architecture and duct tape.

Which brings me to my story.

Just today I came across a charming little piece of duct tape. Here’s how I imagine it got there.  During construction of the system some tester reported a problem: “When I do [x] I get an ugly error, and I cannot complete the task.”  The job of fixing the error was quickly dispatched to a clever duct tape programmer who “solved” it equally quickly by wrapping about 100 lines of code in a try-catch block that swallows the exception.  Before you groan too loudly I should mention that this code has been in production for a year or more.  Does that prove that duct tape was the right tool?

Not so fast.  Back to what happened today.  A colleague and I spent about an hour scratching our heads over a failing acceptance test.  It turned out that this little piece of tape was masking a problem elsewhere in the code.  What should have taken five minutes to solve took two person hours.

Is it a good trade off?  Absolutely!  Um well, unless the business needs to change.  The thing is, it does need to change.  It needs to change a lot.  I will venture to say that all businesses need to change all the time.  This particular system was built by a team of duct tapers.  So our little struggle today is repeated over and over all day every day.  The net result is that it takes many times longer than it “should” to maintain and extend the system.  Indeed, some extenstions seem out of reach.  Conclusion: while duct tape systems may get to v1 faster, they can be very very expensive over the long term in terms of programming labor and worse yet in terms of  lost opportunity.

July 17, 2009

ShouldIt Gets More Fluent

Filed under: C#, Test Driven Development, Unit Testing — Tim Scott @ 3:26 am

ShouldIt now gives you the option to use a more fluent syntax.  For example, the following:

result.ShouldNotBeNull();

Can now be expressed as:

result.Should().Not.Be.Null();

You can still chain asserts as before.  So this:

personList
    .ShouldCount(1)
    .ShouldContainOne(x => x.Id == exptected.Id)
    .FirstName.ShouldEqual("Jim")

Can now alternatively be expressed as:

shouldList
    .Should().Count.Exactly(1)
    .Should().Contain.One(x => x.Id == exptected.Id)
    .FirstName.Should().Equal("Jim");

The new syntax can be found in the ShouldIt.Clr.Fluent namespace in the Should.Clr assembly.

Why the new syntax?  Whether it’s more or less readable is largely a matter of taste.  For me, words separated by dots are an improvement over Pascal cased phrases.    However, the extra parentheses surely do not help. (Anyone else wish that parens were optional for calls to methods with no parameters?)  Nonetheless, I think that the new syntax has some nice advantages.

  1. Better Intellisense. With the old style, Intellisense offers a long list of every possible assertion for the target type.  It’s annoying to scroll through the list and/or type the entire word “should” plus one more letter before the list shirinks.  Using the new style, only one extension method appears at first.   As you type each new node, the list remains very small until you narrow down to the assertion that you want.   Overall I believe that this will facilitate faster and more accurate coding.
  2. More Maintainable And Extensible. The original extension methods all live together in one big fat static class.  The new code is more object oriented and spreads responsibilities over more small classes.  While this does not immediately provide any value to the user, it will make it easier to add nice features over time.

Give it a try and let me know what you think.

May 31, 2009

Reusable “Should” Extensions

Filed under: Test Driven Development, Unit Testing — Tim Scott @ 4:06 am

Should Extensions

UPDATE (6/9/09): Get the code here.

Some months ago I started wrapping my test asserts in fluent “should” extensions, like this:

public static T ShouldEqual<T>(this T actual, T expected)
{
    Assert.AreEqual(expected, actual);
    return actual;
}

Some of these extensions do a little more than just wrap assertions, for example:

public static T ShouldContainOne<T>(this IEnumerable<T> e, Func<T, bool> predicate)
{
    var match = e.ShouldContainAtLeastOne(predicate);
    if (match.Count() != 1)
    {
        Assert.Fail("Expecting 1 matching item.  Found {0}.", match.Count());
    }
    return match.First();
}

Reuse Dilemma

I put these extension methods in a static class in a helper project for re-use across test projects within the application.  Then one day I began work on a new application for a new client.  I love my “should” extensions and felt I could not live without them. Cut-and-paste to the rescue. Yuck. Now I am on to another application. Cut-and-paste again. Get me off this merry-go-round!

I considered creating a common assembly to share across my projects. However, as a consultant I prefer not to leave behind binary bits with this client and that client.

Making matters worse, the aforementioned applications do not all use the same testing framework.

Solution

So I have started developing a library of reusable “should” extensions that I am planning to release as open source – tentatively named “ShouldIt.” It will plug-and-play with all the major unit testing frameworks – with zero configuration using MEF.  To use it, with NUnit for example, you will reference ShouldIt.Core, ShouldIt.Clr and ShouldIt.NUnit in your test project.

You might be wondering, what is ShouldIt.Clr, and why is it separate from ShouldIt.Core?  ShouldIt.Clr will provide extensions to the CLR base class library types.  This leaves room to add, for example, ShouldIt.Watin.

By the way I considered writing my own assertions instead of wrapping those provided by the testing framework.  Then I opened NUnit and MbUnit in Reflector.  Whew!  There’s a lot more to those simple-looking assertions than I had expected.

Challenges And Questions

The biggest challenge I foresee is managing multiple binary dependencies to the testing frameworks.  This is mitigated by the fact that references will not be version specific.  Hence, pain will only be felt when the Assert APIs, more specifically those methods that ShouldIt calls, are changed.  I expect that those APIs are fairly stable.  That said, we can expect major releases to have breaking changes, as we have seen recently with MbUnit 3 (Gallio).

My questions for you:

  1. Anyone else feeling this pain?
  2. Has someone solved this already and I just have not seen it?
  3. Can you think of a better name than “ShouldIt?”

May 18, 2009

Use MvcContrib.FluentHtml With Spark View Engine

Filed under: FluentHtml, MS MVC — Tim Scott @ 11:04 pm

Introduction

MvcContrib.FluentHtml is a library of extensible HTML helpers for MS MVC.  It works out of the box with the WebForms view engine. As it turns out, it’s not very hard to use with other view engines.  Read on to see how to use FluentHtml with the Spark view engine.

View Class

First, you need to add a class to your project, something like this:

public abstract class SparkModelViewPage<T> : SparkView<T>, IViewModelContainer<T> where T : class
{
    private readonly List<IBehaviorMarker> behaviors = new List<IBehaviorMarker>();

    protected SparkModelViewPage()
    {
        behaviors.Add(new ValidationBehavior(() => ViewData.ModelState));
        //add any other desired behaviors here
    }

    public string HtmlNamePrefix { get; set; }

    public T ViewModel
    {
        get { return Model; }
    }

    public IEnumerable<IBehaviorMarker> Behaviors
    {
        get { return behaviors; }
    }
}

NOTE: I updated this class since the original post. I removed constructors overrides that pass in behaviors ad htlmPrefix. You don’t need these unless you expect to further derive this class.

Configuration

Then apply a little configuration – either in the config file or in code. Refer to the Spark config documentation for details.

var settings = new SparkSettings()
    .SetPageBaseType("SparkModelViewPage")
    .AddAssembly("MvcContrib.FluentHtml")
    .AddNamespace("MvcContrib.FluentHtml")
    ...yadda yadda;
ViewEngines.Engines.Add(new SparkViewFactory(settings));

PageBaseType tells the Spark view engine to use your new class as the base class for all views.  The other two settings tell the Spark view engine to use FluentHtml in views.

Usage

That’s it.  Then you can use FluentHtml in your views like so:

<viewdata model="MyApp.Models.Person"/>  

<%=this.TextBox(x => x.FirstName).Label("First Name") %>
<%=this.TextBox(x => x.LastName).Label("Last Name") %>

Conclusion

I should add one caveat. I have tested only the most naive scenarios, and I have not used Spark for any production work at all. Please comment on any issues you encounter in using FluentHtml with Spark.

February 5, 2009

Eliminate Magic Strings In Javascript With MvcContrib.FluentHtml

Filed under: FluentHtml, MS MVC — Tim Scott @ 3:27 am

MvcContrib.FluentHtml provides a library of HTML helper methods that use expressions with strongly typed views to generate HTML elements. Not too long after that MS MVC beta introduced HtmlHelper<T> which allows users to create extension methods that use expressions in the same way.   The benefits are obvious.  By trading magic strings for expressions we gain compile time checking, better refactoring, etc.

So this:

<%=this.TextBox(x => x.User.FirstName)%>

Generates this:

<input type="text" name="User.FirstName" id="User_FirstName" value="Joe"/>

This is very nice, but what about all the other magic strings in our view?  I’m talking of course about Javascript. Does this look familiar?

$('#User_FirstName').change(doSomething);

Doh!  We just can’t escape those magic strings. Or can we?  How about this?

$('#<%=this.IdFor(x => x.User.FirstName)%>').change(doSomething);

MsMvc.FluentHtml has introduced IdFor and NameFor. Okay, so we won’t eliminate all magic string in Javascript but perhaps quite a few. Perhaps we give up a tiny bit of readability, but I think it’s worth it to stop fretting whether some refactor is going to break a bunch of Javascript.

I owe credit to Jimmy Bogard for planting this idea in my mind in one of his tweets.

January 13, 2009

Editing a Variable Length List Of Items With MvcContrib.FluentHtml – Take 2

Filed under: FluentHtml, MS MVC — Tim Scott @ 11:48 pm

In a previous post, I showed how to edit a variable length list using MvcContrib.FluentHtml.  The post was inspired by a post on the same topic by Steve Sanderson.  Steve commented on my post pointing out some limitations.  To address these limitations required some enhancements to MvcContrib.FluentHtml and some changes to my example.  So here we go with take 2.

MvcContrib.FluentHtml Enhancements

The limitations were mostly related to handling validation.  To support validation using Model State we have added to MvcContrib.FluentHtml:

  • Html Prefix Support
  • A Validation Helper
  • List Indexing Support

Html Prefix Support

HTML elements generated for strongly typed views have no prefix by default.  So elements for ModelViewPage<Person> might look something like this:

<input name="FirstName" id="FirstName" value="Jim" type="text"/>
<input name="LastName" id="LastName" value="Smith" type="text"/>

The problem is, neither MvcContrib’s NameValueSerializer nor MS MVC’s default model binder fully handle this scenario.   While NameValueDeserializer does the binding just fine, it does not place bind errors into ModelState.  The default model binder does not handle quite handle the binding — it does not deserialize enumerable properties when no prefix is used.

To bind everything correctly and get any errors into ModelState we need a prefix.  One way to handle this is to wrap our primary model in a view model. This is a valid pattern. It’s even a standard for some applications. However, we don’t want to have to do this just to get a prefix. So we provide a way to specify a prefix for a strongly typed view.

Either in the code-behind:

public class Index : ModelViewPage<IList<Gift>>
{
    public Index() : base("person") { }
}

Or in the view:

<%this.HtmlNamePrefix = "person"%>

Thus our HTML elements will be prefixed:

<input name="person.FirstName" id="person_FirstName" value="Jim" type="text"/>
<input name="person.LastName" id="person_LastName" value="Smith" type="text"/>

Then in our action method, we can use the default binder without any attribute.  Any bind errors will be captured in ModelState.

[AcceptPost]
public ViewResult Index(Person person)

New Validation Helper

We have added validation support to FluentHtml for strongly typed views. The following works basically the same as HtmlHelper’s ValidationMessage.

<%this.ValidationMessage(x => x.Price, "Price must be numeric.")%>

We have also added a behavior to ModelViewPage<T>, ModelViewMasterPage<T> and ModelViewUserControl<T> which basically mimics validation used by HtmlHelper.  That is, it adds a CSS class “input-validation-error” to any HTML element with an error in ModelState.  If you wish, you can remove this behavior or change the CSS class name in the derived class.

List Indexing Support

MS MVC uses a special technique to deserialize enumerable properties.  With this technique you set an arbitrary value in a specially named hidden element to signify that a group of elements belongs to a particular instance of the enumerable property. This has an advantage over using positional indexes in that it preserves the identity of an instance across posts, which is necessary for ModelState based validation to work properly.

Therefore, we have added support for this to MvcContrib.FluentHtml.  Let’s assume ModelViewPage<IList<Person>> with a prefix of “persons”.  Then this markup:

<%var id = Model[i].Id;%>
<%=this.Index(x => x).Value(id)%>
<%=this.TextBox(x => x[id].FirstName).Value(Model[i].FirstName)%>

Will generate HTML like this:

<input id="persons_Index_123" name="persons.Index" value="123" type="hidden"/>
<input id="persons[123]_FirstName" name="persons[123].FirstName" value="Jim" type="text"/>

Changes To Our Example

So based on these changes to FluentHtml we made a few changes to the “Gift Request Form” demo from the previous post. In the main view:

<%for (var i = 0; i < ViewData.Model.Count; i++) {%>
    <%ViewData["index"] = i;
    Html.RenderPartial("GiftLineItem");%>
<%}%>

And in the user control:

<%var i = (int)ViewData["index"];
  var gift = ViewModel == null ? null : ViewModel[i];
  var id = gift == null ? -1 * new Random().Next() : gift.Id;
  var name = gift == null ? null : gift.Name;
  var price = gift == null ? (decimal?)null : gift.Price;%>
<div class="giftLineItem">
    <%=this.Index(x => x, x => x[i].Id)%>
    <%=this.Hidden(x => x[id].Id).Value(id)%>
    <%=this.TextBox(x => x[id].Name).Value(name).Label("Name of gift:")%>
    <%=this.TextBox(x => x[id].Price).Value(price).Label("Price ($):")%>
    <%=this.ValidationMessage(x => x[id].Price, "Must be a number")%>
    <a href="" class="removeGift">Delete</a>
</div>

Viola, validation works:

showvalidationerror1

Note that we stole Steve’s technique of using random negative Ids for unsaved instances, which we will handle in the save method on the server.

GET THE REVISED CODE

January 2, 2009

Editing a Variable Length List Of Items With MvcContrib.FluentHtml

Filed under: FluentHtml, MS MVC — Tim Scott @ 9:28 pm

Steve Sanderson recently showed  a nifty way to edit variable length lists with MS MVC .  I commented that I liked his approach.  I also mentioned that MvcContrib.FluentHtml might be used to improve a bit of awkward code used to build HTML element names.  To illustrate my point I offered some code examples.   Steve responded by pointing out the shortcomings of  my examples.  He was correct.   I had not really thought it through.  While my examples illustrated the use of FluentHtml, they missed the mark in terms of showing a real solution.

Still I knew that the basic idea of was sound.  This article shows in detail how to use MvcContrib.FluentHtml to edit a variable length list of items.

Get The Code

I will use the same basic application as Steve did — a simple gift request form.

Setup

We start with the Gift entity:

public class Gift
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Render The View

Our view derives from MvcContrib.FluentHtml.ModelViewPage<IList<Gift>> and is rendered via a controller action:

[AcceptGet]
public ViewResult Index()
{
     ViewData.Model = new List<Gift>
     {
         new Gift {Id = 1, Name = "Tar Tinker", Price = 23.44m},
         new Gift {Id = 2, Name = "Flu Flooper", Price = 11.42m}
     };
     return View();
}

The view presents a list of the gifts:

<form action="<%=Html.BuildUrlFromExpression<HomeController>(x => x.Index(null))%>" method="post">
    <div id="addGiftItem">
        <a href="" id="addGift">Add</a>
    </div>
    <fieldset id="giftLineItems">
        <legend>Gifts</legend>
        <%for (var i = 0; i < ViewData.Model.Count; i++) {%>
            <%Html.RenderPartial("GiftLineItem", ViewData.Model, new ViewDataDictionary {{"index", i}});%>
        <%}%>
    </fieldset>
    <%=this.SubmitButton("Save")%>
</form>

GiftLineItem is a user control that derives from MvcContrib.FluentHtml.ViewModelUserControl<IList<Gift>>:

<%var i = (int)ViewData["index"];%>
<div class="giftLineItem">
    <%=this.Hidden(x => x[i].Id)%>
    <%=this.TextBox(x => x[i].Name).Label("Name of gift:")%>
    <%=this.TextBox(x => x[i].Price).Label("Price ($):")%>
    <a href="" class="removeGift">Delete</a>
</div>

You might observe that this user control uses IList<Gift> as its model whereas Steve’s uses Gift.   But the user control represents one gift, right?  Have I sacrificed cohesion? Yes, however a closer look shows that neither Steve’s user control nor mine is cohesive.  That is, neither stands alone outside of the context of a list.  We simply use different techniques to name the elements within the context of an owning list.

Here’s the rendered view (after clicking “Add” twice):

variablelineitemdemo1.gif

Add Behavior

Now we need to add behavior to the “Add” and “Delete” links.  For that we’ll use jQuery:

$(document).ready(function() {

    var nextGiftIndex = <%=ViewData.Model.Count%>;
    setRemoveLinks();

    $('#addGift').click(function() {
        $.get('/Home/AddGift?index=' + nextGiftIndex, 'html', function(lineItemHtml) {
            $('#giftLineItems').append(lineItemHtml);
            setRemoveLinks();
        });
        nextGiftIndex++;
        return false;
    });
});
function setRemoveLinks() {
    $('a.removeGift').click(function() {
        $(this).parent('div').remove();
        return false;
    });
}

Clicking the “Add” link calls the AddGift action asyncronously and passes the index of the item to be added.  The index value is initialized when the page is rendered and incremented on the client side with each addition.  The “Delete” links are wired up to a simple function that removes the parent div.

The AddGift action simply renders the user control using the specified index:

public ViewResult AddGift(int index)
{
    ViewData["index"] = index;
    return View("~/Views/Home/GiftLineItem.ascx");
}

Notice we have not specified a model for the user control, which means it will be null.  As a result, the name and price textboxes will be blank, which is what we want.  And by specifying the desired index, these textboxes will be named such that they will bind correctly when form is saved.

Save Changes

Clicking the “Save” button posts the form to the following action:

[AcceptPost]
public ViewResult Index([Deserialize]IList<Gift> gifts)
{
    //code to save the changes
    ViewData.Model = gifts;
    return View();
}

Notice that the parameter “gifts” is decorated with the Deserialize attribute. This attribute uses MvcContrib’s NameValueDeserializer to obtain our collection of gifts from the form post.  It does not require that collections be indexed purely in sequence. Thus it handles any holes left by deleted line items.

(NOTE: I expected that using [Bind(Prefix = "")] would work the same as [Deserialize], but it does not.  Seems to be a limitation.)

Conclusion

The solution presented here differs from Steve’s in that it uses FluentHtml. There are a few other differences, such as jQuery versus MS Ajax.  My point is not present a solution that is superior, rather just to show how it might be done using  FluentHtml and expressions to avoid some fiddly construction of HTML element names in views.

December 13, 2008

MvcFluentHtml Moved To MvcContrib

Filed under: MS MVC — Tags: , — Tim Scott @ 12:12 am

MvcFluentHtml, discussed in this blog post, has been moved to MvcContrib.

Older Posts »

Blog at WordPress.com.