DataTemplating In ASP.NET MVC

Thursday, 16 July 2009 19:33:48 UTC

The expressiveness of WPF is amazing. I particularly like the databinding and templating features. The ability to selectively render an object based on its type is very strong.

When I recently began working with ASP.NET MVC (which I like so far), I quickly ran into a scenario where I would have liked to have WPF's DataTemplates at my disposal. Maybe it's just because I've become used to WPF, but I missed the feature and set out to find out if something similar is possible in ASP.NET MVC.

Before we dive into that, I'd like to present the 'problem' in WPF terms, but the underlying View Model that I want to expose will be shared between both solutions.

PresentationModel

The main point is that the Items property exposes a polymorphic list. While all items in this list share a common property (Name), they are otherwise different; one contains a piece of Text, one contains a Color, and one is a complex item that contains child items.

When I render this list, I want each item to render according to its type.

In WPF, this is fairly easy to accomplish with DataTemplates:

<ListBox.Resources>
    <DataTemplate DataType="{x:Type pm:NamedTextItem}">
        <StackPanel>
            <TextBlock Text="{Binding Path=Name}"
                       FontWeight="bold" />
            <TextBlock Text="{Binding Path=Text}" />
        </StackPanel>
    </DataTemplate>
    <DataTemplate DataType="{x:Type pm:NamedColorItem}">
        <StackPanel>
            <TextBlock Text="{Binding Path=Name}"
                       FontWeight="bold" />
            <Ellipse Height="25" Width="25"
                     HorizontalAlignment="Left"
                     Fill="{Binding Path=Brush}"
                     Stroke="DarkGray" />
        </StackPanel>
    </DataTemplate>
    <DataTemplate DataType="{x:Type pm:NamedComplexItem}">
        <StackPanel>
            <TextBlock Text="{Binding Path=Name}"
                       FontWeight="bold" />
            <ListBox ItemsSource="{Binding Path=Children}"
                     BorderThickness="0">
                <ListBox.Resources>
                    <DataTemplate
                        DataType="{x:Type pm:ChildItem}">
                        <TextBlock
                            Text="{Binding Path=Text}" />
                    </DataTemplate>
                </ListBox.Resources>
            </ListBox>
        </StackPanel>
    </DataTemplate>
</ListBox.Resources>

Each DataTemplate is contained within a ListBox. When the ListBox binds to each item in the Items list, it automatically picks the correct template for the item.

The result is something like this:

WpfApp

The NamedTextItem is rendered as a box containing the Name and the Text on two separate lines; the NamedColorItem is rendered as a box containing the Name and a circle filled with the Color defined by the item; and the NamedComplexItem is rendered as a box with the Name and each child of the Children list.

This is all implemented declaratively without a single line of imperative UI code.

Is it possible to do the same in ASP.NET MVC?

To my knowledge (but please correct me if I'm wrong), ASP.NET MVC has no explicit concept of a DataTemplate, so we will have to mimic it. The following describes the best I've been able to come up with so far.

In ASP.NET MVC, there's no declarative databinding, so we will need to loop through the list of items. My View page derives from ViewPage<MyViewModel>, so I can write

<% foreach (var item in this.Model.Items)
   { %>
   <div class="ploeh">
   <% // Render each item %>
   </div>
<% } %>

The challenge is to figure out how to render each item according to its own template.

To define the templates, I create a UserControl for each item. The NamedTextItemUserControl derives from ViewUserControl<NamedTextItem>, which gives me a strongly typed Model:

<div><strong><%= this.Model.Name %></strong></div>
<div><%= this.Model.Text %></div>

The other two UserControls are implemented similarly.

A UserControl can be rendered using the RenderPartial extension method, so the only thing left is to select the correct UserControl name for each item. It would be nice to be able to do this in markup, like WPF, but I'm not aware of any way that is possible.

I will have to resort to code, but we can at least strive for code that is as declarative in style as possible.

First, I need to define the map from type to UserControl:

<%
    var dataTemplates = new Dictionary<Type, string>();
    dataTemplates[typeof(NamedTextItem)] =
        "NamedTextItemUserControl";
    dataTemplates[typeof(NamedColorItem)] =
        "NamedColorItemUserControl";
    dataTemplates[typeof(NamedComplexItem)] =
        "NamedComplexItemUserControl";
%>

Next, I can use this map to render each item correctly:

<% foreach (var item in this.Model.Items)
   { %>
   <div class="ploeh">
   <% // Render each item %>
   <% this.Html.RenderPartial(dataTemplates[item.GetType()],
                            item); %>
   </div>
<% } %>

This is definitely less pretty than with WPF, but if you overlook the aesthetics and focus on the structure of the code, it's darn close to markup. The Cyclomatic Complexity of the page is only 2, and that's even because of the foreach statement that we need in any case.

The resulting page looks like this:

AspNetMvcApp

My HTML skills aren't good enough to draw circles with markup, so I had to replace them with blocks, but apart from that, the result is pretty much the same.

A potential improvement on this technique could be to embed the knowledge of the UserControl into each item. ASP.NET MVC Controllers already know of Views in an abstract sense, so letting the View Model know about a UserControl (identified as a string) may be conceptually sound.

The advantage would be that we could get rid of the Dictionary in the ViewPage and instead let the item itself tell us the name of the UserControl that should be used to render it.

The disadvantage would be that we lose some flexibility. It would then require a recompilation of the application if we wanted to render an item using a different UserControl.

The technique outlined here represents an explorative work in progress, so comments are welcome.


Comments

David C #
In MVC, data templates are really either Editor or Display templates. In your Shared Views Folder, you can create an EditorTemplates folder and a DisplayTemplates folder. These are snippets which can be either ASP or Razor syntax. By default they run on convention. So if you create a String.cshtml, then anytime you do a Html.EditorFor(x=>x.SomeModelVariableThatIsAString) it will automatically use your template for it. If you only need to display it, not edit it, you can do Html.DisplayFor(x=>x.SomeModelVariableThatIsAString). Assuming you have a String.cshtml in your DisplayTemplates folder as well. You can also optionally specify a specific template, such as Html.DisplayFor(x=>x.SomeModelVariableThatIsAString,"PrettyListItem"), and it will look for PrettyListItem.cshtml as the template to render your <li>. Generally you would simply add a css class name to the markup in that instance of the template <li class="purty">, and do all your styling in CSS, which is of course optimal for Web development.

Here is a fairly detailed introduction to using Templates in MVC. It is a bit old but the concepts still hold.
http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html

BTW: Your custom implementation was pretty tight, not bad at all :)
2012-09-05 19:38 UTC

AutoFixture .8.4 And Roadmap

Saturday, 11 July 2009 20:35:34 UTC

A couple of days ago I released AutoFixture .8.4. It contains a few small feature additions and a bug fix. You can get it at the AutoFixture CodePlex site as usual.

You may have noticed that I'm frequently releasing incremental versions these days. This is because we have begun using AutoFixture for writing production software at Safewhere. So far, it has been a pleasure to use AutoFixture in my daily work, and watch colleagues pick it up and run with it.

Such intensive usage obviously uncovers missing features as well as a few bugs, which is the driving force behind the frequent releases. I've been happy to observe that so far, there have been only a few bugs, and the general API is very expressive and useful.

After we ship the first product written with AutoFixture, I plan to upgrade it to version .9 (beta). That should hopefully happen in the autumn of 2009.


AutoFixture As Test Data Builder

Wednesday, 01 July 2009 06:19:00 UTC

Some time ago, my good friend Martin Gildenpfennig from Ative made me aware that AutoFixture (among other things) is an generic implementation of the Test Data Builder pattern, and indeed it is.

In the original Gang of Four definition of a Design Pattern, several people must independently have arrived at the same general solution to a given problem before we can call a coding idiom a true Pattern. In this spirit, the Test Data Builder pattern is on the verge of becoming a true Design Pattern, since I came up with AutoFixture without having heard about Test Data Builder :)

The problem is the same: How do we create semantically correct test objects in a manner that is flexible and yet hides away irrelevant complexity?

Like others before me, I tried the Object Mother (anti?)pattern and found it lacking. To me the answer was AutoFixture, a library that heuristically builds object graphs using Reflection and built-in rules for specific types.

Although my original approach was different, you can certainly use AutoFixture as a generic Test Data Builder.

To demonstrate this, let's work with this (oversimplified) Order object model:

image

Assuming that we have an instance of the Fixture class (called fixture), we can create a new instance of the Order class with a ShippingAddress in Denmark:

var order = fixture.Build<Order>()
    .With(o => o.ShippingAddress, 
        fixture.Build<Address>()
        .With(a => a.Country, "Denmark")
        .CreateAnonymous())
    .CreateAnonymous();

While this works and follows the Test Data Builder pattern, I find this more concise and readable:

var order = fixture.CreateAnonymous<Order>();
order.ShippingAddress.Country = "Denmark";

The result is the same.

We can also add anonymous order lines to the order using this fluent interface:

var order = fixture.Build<Order>()
    .Do(o => fixture.AddManyTo(o.OrderLines))
    .CreateAnonymous();

but again, I find it easier to simply let AutoFixture create a fully anonymous Order instance, and then afterwards modify the relevant parts:

var order = fixture.CreateAnonymous<Order>();
fixture.AddManyTo(order.OrderLines);

Whether you prefer one style over the other, AutoFixture supports them both.


Custom Tokens Over Non-HTTP Transports

Monday, 22 June 2009 19:48:42 UTC

About a year ago, one of my readers asked me about how to make custom tokens work over TPC in WCF. Here's the question again:

"i'm trying to implement the CustomToken over tcp. The original used the SymmetricSecurityBindingElement and the transport http, this works fine, but when i change URI's and and the transport, it gives an error saying:

"Binding 'CustomBinding' doesn't support creating any channel types. This often indicates that the BindingElements in a CustomBinding have been stacked incorrectly or in the wrong order. A Transport is required at the bottom of the stack. The recommended order for BindingElements is: TransactionFlow, ReliableSession, Security, CompositeDuplex, OneWay, StreamSecurity, MessageEncoding, Transport."

As it turns out, this seems to be a general issue with more transports than just TCP - at least, I've seen the exact same behavior for the Named Pipes transport.

When I originally received the question, it seemed that no-one knew the answer, and neither did I. Now, about a year later, I've managed to find a solution, and it's really simple.

If you build up your CustomBinding in code, all you need to do is set the TransferMode property to Streamed:

var pipeTransport = new NamedPipeTransportBindingElement();
pipeTransport.TransferMode = TransferMode.Streamed;

In this example, I'm setting the property on a Named Pipe transport, but you can do exactly the same with a TCP transport.

Although I wasn't able to find any documentation to that effect, experimentation seems to indicate that you can also set the property in a .config file (at least, it works on my computer):

<namedPipeTransport transferMode="Streamed" />

I will not claim that I fully understand this fix/workaround, or that it applies in every situation, but I hope that it might prove helpful to some of my readers some day.


AutoFixture .8.3 Released

Saturday, 20 June 2009 08:34:30 UTC

It was only earlier this week that I released AutoFixture .8.2, but now I'm releasing version .8.3 - not that there was anything wrong with .8.2 (that I know of), but I had some time to implement new features, and I wanted to properly release those.

In the future I will blog about these new features (along with all the other AutoFixture features I haven't introduced yet).

Get it at the AutoFixture CodePlex site as usual.


AutoFixture .8.2 Released

Thursday, 18 June 2009 19:11:39 UTC

Yesterday I created a new release (.8.2) of AutoFixture; this time with a new feature that I recently discovered that I needed, and about which I will blog later.

There are no breaking changes and no known bugs.


Calling Methods While Building Anonymous Variables With AutoFixture

Tuesday, 09 June 2009 17:50:54 UTC

Previously, we saw how you can set property values while building anonymous variables with AutoFixture. While I insinuated that I consider this a somewhat atypical scenario, we can now safely venture forth to the truly exotic :)

Imagine that you want to build an anonymous instance of a type that requires you to call a certain method before you can start assigning properties. It's difficult to come up with a reasonable example of this, but although I consider it quite bad design, I've seen interfaces that include an Initialize method that must be called before any other member. In our example, let's call this interface IBadDesign.

Let's say that we have a class called SomeImp that implements IBadDesign. Here's the relevant part of the class:

#region IBadDesign Members
 
public string Message
{
    get { return this.message; }
    set
    {
        if (this.mc == null)
        {
            throw new InvalidOperationException("...");
        }
 
        this.message = value;
        this.transformedMessage = this.mc.DoStuff(value);
    }
}
 
public void Initialize(MyClass mc)
{
    this.mc = mc;
}
 
#endregion

This is a rather ridiculous example, but I couldn't think of a better one. The main point here is that given a brand-new instance of SomeImp, this usage is invalid:

something.Message = "Ploeh";

While the above code snippet will throw an InvalidOperationException, this will work:

something.Initialize(new MyClass());
something.Message = "Ploeh";

The problem is that by default, AutoFixture ignores methods and only assigns properties, which means that this is also going to throw:

var imp = fixture.CreateAnonymous<SomeImp>();

As we saw with properties, we can use the Build method to customize how the type is being created. Properties can be set with the With method, while methods can be invoked with the Do method, so this is all it takes:

var imp = fixture.Build<SomeImp>()
    .Do(s => s.Initialize(new MyClass()))
    .CreateAnonymous();    

We don't have to explicitly set the Message property, as AutoFixture is going to do this automatically, and all implicit assignments happen after explicit actions defined by With or Do (and in case you were wondering, you can mix With and Do, and ObjectBuilder<T> will preserve the ordering).

In most cases, having to use the Do method probably constitutes a design smell of the SUT, but the method is there if you need it.


Tweet

Friday, 05 June 2009 19:12:49 UTC

Lately, several people have implied to me that I should consider start using Twitter, so here I am, with only a vague idea about what to do with it...


Testability Is Really The Open/Closed Principle

Friday, 05 June 2009 07:56:19 UTC

When I talk with people about TDD and unit testing, the discussion often moves into the area of Testability - that is, the software's susceptibility to unit testing. A couple of years back, Roy even discussed the seemingly opposable forces of Object-Oriented Design and Testability.

Lately, it has been occurring to me that there really isn't any conflict. Encapsulation is important because it manifests expert knowledge so that other developers can effectively leverage that knowledge, and it does so in a way that minimizes misuse.

However, too much encapsulation goes against the Open/Closed Principle (that states that objects should be open for extension, but closed for modification). From a Testability perspective, the Open/Closed Principle pulls object-oriented design in the desired direction. Equivalently, done correctly, making your API Testable is simply opening it up for extensibility.

As an example, consider a simple WPF ViewModel class called MainWindowViewModel. This class has an ICommand property that, when invoked, should show a message box. Showing a message box is good example of breaking testability, because if the SUT were to show a message box, it would be very hard to automatically verify and we wouldn't have fully automated tests.

For this reason, we need to introduce an abstraction that basically models an action with a string as input. Although we could define an interface for that, an Action<string> fits the bill perfectly.

To enable that feature, I decide to use Constructor Injection to inject that abstraction into the MainWindowViewModel class:

public MainWindowViewModel(Action<string> notify)
{
    this.ButtonCommand = new RelayCommand(p => 
    { notify("Button was clicked!"); });
}

When I recently did that at a public talk I gave, one member of the audience initially reacted by assuming that I was now introducing test-specific code into my SUT, but that's not the case.

What I'm really doing here is opening the MainWindowViewModel class for extensibility. It can still be used with message boxes:

var vm = new MainWindowViewModel(s => MessageBox.Show(s));

but now we also have the option of notifying by sending off an email; writing to a database; or whatever else we can think of.

It just so happens that one of the things we can do instead of showing a message box, is unit testing by passing in a Test Double.

// Fixture setup
var mockNotify = 
    MockRepository.GenerateMock<Action<string>>();
mockNotify.Expect(a => a("Button was clicked!"));
 
var sut = new MainWindowViewModel(mockNotify);
// Exercise system
sut.ButtonCommand.Execute(new object());
// Verify outcome
mockNotify.VerifyAllExpectations();
// Teardown

Once again, TDD has lead to better design. In this case it prompted me to open the class for extensibility. There really isn't a need for Testability as a specific concept; the Open/Closed Principle should be enough to drive us in the right direction.

Pragmatically, that's not the case, so we use TDD to drive us towards the Open/Closed Principle, but I think it's important to note that we are not only doing this to enable testing: We are creating a better and more flexible API at the same time.


AutoFixture Cheat Sheet

Thursday, 04 June 2009 21:15:08 UTC

To make it a bit easier to get started with AutoFixture without having to trawl through all my blog posts, I've added a Cheat Sheet over at the AutoFixture CodePlex site.

As I add more posts on AutoFixture, I'll update the Cheat Sheet with the essentials. Please let me know if you think something's missing.


Page 70 of 73

"Our team wholeheartedly endorses Mark. His expert service provides tremendous value."
Hire me!