Customizing A Type's Builder With AutoFixture

Tuesday, 22 September 2009 14:53:48 UTC

In the previous post on AutoFixture, I demonstrated how it's possible to use a customized Builder to perform complex initialization when requesting an instance of a particular type. To recap, this was the solution I described:

var mc = fixture.CreateAnonymous<MyClass>();
var mvm = fixture.Build<MyViewModel>()
    .Do(x => x.AvailableItems.Add(mc))
    .With(x => x.SelectedItem, mc)
    .CreateAnonymous();

This code first creates an anonymous instance of MyClass that can be added to MyViewModel. It then initializes a Builder for a specific instance of MyViewModel, instructing it to

  1. add the anonymous MyClass instance to the list of AvailableItems
  2. assign the same instance to the SelectedItem property

While this works splendidly, it can get tiresome to write the same customization over and over again if you need to create multiple instances of the same type. It also violate the DRY principle.

When this is the case, you can alternatively register a customized Builder pipeline for the type in question (in this case MyViewModel). This is done with the Customize method:

var mc = fixture.CreateAnonymous<MyClass>();
fixture.Customize<MyViewModel>(ob => ob
    .Do(x => x.AvailableItems.Add(mc))
    .With(x => x.SelectedItem, mc));

The Customize method takes as input a function that provides an initial ObjectBuilder as input, and returns a new, customized ObjectBuilder as output. This function is registered with the type, so that each time an anonymous instance of the type is requested, the customized ObjectBuilder will be used to create the instance.

In the example, I customize the supplied ObjectBuilder (ob) in exactly the same way as before, but instead of invoking CreateAnonymous, I simply return the customized ObjectBuilder to the Fixture instance. It then saves this customized ObjectBuilder for later use.

With this customization, what before failed now succeeds:

var mvm = fixture.CreateAnonymous<MyViewModel>();

The Customize method is the core method for customizing AutoFixture. Most other customization methods (like Register) are simply convenience methods that wraps Customize. It is a very powerful method that can be used to define some very specific Builder algorithms for particular types.


Comments

Scott Peterson #

I posted this to CodePlex without properly thinking it through, but am now posting here which should be closer to where it belongs.

I have the following class that I am trying to test:

public class License
    {
        public virtual DateTime DatePurchased { get; set; }
        public virtual int LicenseDuration { get; set; }
        public virtual EnumDatePeriod PeriodType { get; set; }
        public virtual bool InUse { get; set; }

        public DateTime ExpirationDate()
        {
            ILicenseCalculator calculator = CreateLicenseDurationBuilder(PeriodType);

            return calculator.CalculateLicenseDuration(DatePurchased, LicenseDuration);
        }

        public ILicenseCalculator CreateLicenseDurationBuilder(EnumDatePeriod datePeriod)
        {
            Dictionary<EnumDatePeriod, ILicenseCalculator> calculators = new Dictionary<EnumDatePeriod, ILicenseCalculator>();
            calculators.Add(EnumDatePeriod.Year, new YearLicenseCalculator());
            calculators.Add(EnumDatePeriod.Month, new MonthLicenseCalculator());
            calculators.Add(EnumDatePeriod.Week, new WeekLicenseCalculator());
            calculators.Add(EnumDatePeriod.Day, new DayLicenseCalculator());

            return calculators[datePeriod];
        }
    }

Specifically, I want to see if I have a license that was purchased more than X time periods ago, the expiration date calculates properly. For example, I have a test that is set up to use a 6 month license, with a purchase date from seven months ago. I am trying to force a certain date, so I got into customizing, and set up my test as follows:

[Fact]
        public void CanCalculateExpirationDateOnExpiredMonthlyLicense()
        {
            Fixture fixture = new Fixture();
            fixture.Customize<License>(x => x
                .With(b => b.DatePurchased == DateTime.Now.AddMonths(-7)));
            var sut = fixture.Create<License>();
        }

I realize that this isn't a complete test, but I ran it just to see what feedback I'd get, to make certain I was customizing properly. Looks like I'm not, because I get an error:

Result Message:    
System.ArgumentException : The expression's Body is not a MemberExpression. Most likely this is because it does not represent access to a property or field. 
Parameter name: propertyPicker 

Where have I gone wrong?

Thanks for your help.

2015-02-26 21:39 UTC

Scott, thank you for writing. In your expression b.DatePurchased == DateTime.Now.AddMonths(-7), what would you say the == does?

2015-02-27 7:35 UTC
Scott Peterson #

Mark, I really must apologize; my post above was not meant to be published. I worked on this a long time ago and I must have committed it to my local repository. I am very aware of the difference between = and ==. This must have been a question I had when I first started looking at AutoFixture (and working with Git). Again, my apologies.

Scott

2015-03-01 19:41 UTC

AutoFixture .8.6 Released

Monday, 21 September 2009 17:37:36 UTC

Yesterday I released version .8.6 of AutoFixture. It is a minor release that simply adds some new features.

There are some minor breaking changes (documented on the release page), but they only affect supporting classes and don't touch on any of the code examples I have so far published. In other words, if you are using AutoFixture's fluent interface, your code should still compile.

Please go ahead and download it and use it. As always, comments and questions are welcome, either here or in the forum.


Self-updating AJAX links with ASP.NET MVC

Monday, 07 September 2009 18:14:39 UTC

How can you make an AJAX link that updates itself in ASP.NET MVC? My colleague Mikkel and I recently had that problem and we couldn't find any guidance on this topic, so now that we have a solution, I thought I'd share it.

The problem is simple: We needed a link that invoked some server side code and updated the text of the link itself based on the result of the operation. Here is a simplified example:

image

Each time you click the link, it should invoke a Controller Action and return a new number that should appear as the link text.

This is pretty simple to implement once you know how. The first thing to realize is that the link and all the AJAX stuff must be placed in a user control. The only thing that needs to go into the containing page is the containing element itself:

<h2>Self-updating AJAX link</h2>
Click the link to update the number:
<span id="thespan">
    <% this.Html.RenderPartial("NumberAjaxUserControl"); %>
</span>

Notice the id of the span element - this same id will be referenced from the user control.

To bootstrap this view, the Controller Action for the page contains code that assigns an initial value to the number (in this case 1):

public ActionResult Index()
{
    this.ViewData["number"] = 1.ToString();
    return this.View();
}

To keep the example simple, I simply add the number to the ViewData dictionary, but in any production implementation, I would opt to use a strongly typed ViewModel instead.

The NumberAjaxUserControl itself only contains the definition of the AJAX link:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%@ Import Namespace="System.Web.Mvc.Ajax" %>
<%= this.Ajax.ActionLink((string)this.ViewData["number"],
    "GetNext",
    new { number = this.ViewData["number"] }, 
    new AjaxOptions { UpdateTargetId = "thespan" })%>

The first parameter to the ActionLink method is simply the current number to render as the link text. Since I'm using the untyped ViewData dictionary for this example, I need to cast it to a string.

The next parameter ("GetNext") indicates the Controller Action to invoke when the link is clicked - I will cover that shortly.

The third parameter is a Route Value that specifies that the parameter number with the correct value will be supplied to the GetNext Controller Action. It uses the number stored in ViewData.

The last parameter indicates the id of the element to update. Recall from before that this name was "thespan".

The only missing piece now is the GetNext Controller Action:

public PartialViewResult GetNext(int number)
{
    this.ViewData["number"] = (number + 1).ToString();
    return this.PartialView("NumberAjaxUserControl");
}

In this example I simply chose to increment the number by one, but I'm sure you can imagine that this method could just as well perform a database lookup or something similar.

Notice that the method returns a PartialViewResult that uses the same user control that I used to bootstrap the thespan element. This means that every time the link is clicked, the GetNext method is updated, and the exact same user control is used to render the content that dynamically replaces the original content of the element.


Comments

anonymous #
I kind of prefer the jQuery approach, it is much less intrusive: you render your link as usual and then you use the "live" function:

$("a#some_link").live('click', function(){ $('#thespan').load(this.href); });

This will automatically watch for DOM updates of the anchor tag and if it detects any it will automatically rebind the click function.
2009-09-08 07:00 UTC
Thank you for your comment

It looks pretty simple. The following questions are entirely based on my total (and very deplorable) lack of JQuery knowledge:

Will this allow me to query the server with particular parameter values (the number parameter in my example)?
Will it allow me to update the link with the result from the server?

From your snippet, I can't really see where it is specified which URL is requested, what are the query parameters, how the returned result is used to update the link text, etc.
2009-09-08 08:16 UTC

AutoFixture .8.5 Released

Wednesday, 02 September 2009 20:21:13 UTC

It gives me great pleasure to announce that I have just release version .8.5 of AutoFixture. It is a minor release (hence the numbering) that mainly contains a lot of convenience overloads to already existing methods. There is also a single bug fix.

There are two breaking changes (documented on the release page), but they are minor and I do not expect them to cause problems. Only one of these even remotely affects any part of the API I have already discussed here, and that relates to what kind of exception is being thrown when AutoFixture is unable to create an instance of the requested type.

Please go ahead and download it and use it heavily :) As always, comments and questions are welcome.


Do Redux

Tuesday, 25 August 2009 18:27:39 UTC

Soon after I posted my post on the AutoFixture Custom Builder's Do method, a much better example occurred to me, so let's revisit this feature in light of a more reasonable context.

When I write WPF code, I always use the MVVM pattern. When I need to create a Master/Detail View, I usually model it so that my View Model has a list of available items, and a property that returns the currently selected item. In this way, I can bind the current Detail View to the currently selected item purely through the View Model.

Such a View Model might look like this:

public class MyViewModel
{
    private readonly List<MyClass> availableItems;
    private MyClass selectedItem;
 
    public MyViewModel()
    {
        this.availableItems = new List<MyClass>();
    }
 
    public ICollection<MyClass> AvailableItems
    {
        get { return this.availableItems; }
    }
 
    public MyClass SelectedItem
    {
        get { return this.selectedItem; }
        set 
        {
            if (!this.availableItems.Contains(value))
            {
                throw new ArgumentException("...");
            }
            this.selectedItem = value;
        }
    }
}

The main point of interest is that if you attempt to set SelectedItem to an instance that's not contained in the list of available items, an exception will be thrown. That's reasonable behavior, since we want the user to select only from the available items.

By default, AutoFixture works by assigning an Anonymous Value to all writable properties. Since these values are auto-generated, the value AutoFixture is going to assign to SelectedItem will be a new instance of MyClass, and thus not one of the available items. In other words, this will throw an exception:

var mvm = fixture.CreateAnonymous<MyViewModel>();

There are several solutions to this situation, depending on the scenario. If you need an instance with SelectedItem correctly set to a non-null value, you can use the Do method like this:

var mc = fixture.CreateAnonymous<MyClass>();
var mvm = fixture.Build<MyViewModel>()
    .Do(x => x.AvailableItems.Add(mc))
    .With(x => x.SelectedItem, mc)
    .CreateAnonymous();

This first creates an anonymous instance of MyClass, adds it to AvailableItems as part of a customized Builder pipeline and subsequently assigns it to SelectedItem.

Another option is to skip assigning only the SelectedItem property. This is a good option if you don't need that value in a particular test. You can use the Without method to do that:

var mvm = fixture.Build<MyViewModel>()
    .Without(s => s.SelectedItem)
    .CreateAnonymous();

This will assign a value to all other writable properties of MyViewModel (if it had had any), except the SelectedItem property. In this case, the value of SelectedItem will be null, since it is being ignored.

Finally you can simply choose to omit all AutoProperties using the OmitAutoProperties method:

var mvm = fixture.Build<MyViewModel>()
    .OmitAutoProperties()
    .CreateAnonymous();

In this scenario, only MyViewModel's constructor is being executed, while all writable properties are being ignored.

As you can see, AutoFixture offers great flexibility in providing specialized custom Builders that fit almost any situation.


Comments

Murali #
Hi Mark,

Can you please help in creating the class which has an array of other types. With Autofixture , the array size is default to 2 null tems.

For eg:

Here is the my class definition:

class MyClassA
{

public MyClassB[] items;
public MyClassC c;
public MyClassD d;
}

class MyclassB
{
public int x;
public string y;

}
when i use Autofixture for creating MyClass c,d are created and b array with 2 items but with each item null instead of intantiated MyclassB objects. How do i get an Myclass with MyclassB array .
Thanks for your help in advance.

Murali
2009-12-04 22:00 UTC
Hi Murali

Thank you for your question! It prompted me to write a new blog post that provides possible solutions to your question: Building and assigning arrays with AutoFixture.

I hope it answers your question. If not then please write again.
2009-12-05 00:45 UTC
Simple #
Hi Mark,

which MVVM Frameworks do you prefer? Or if you dont use Framerworks - which one can you recommend?
2012-05-10 13:22 UTC
FWIW, I've found Knockout.js pretty decent so far, but that's probably not what you had in mind?

For WPF, I don't think an additional framework is warranted for MVVM; for Silverlight, I have no opinion.
2012-05-10 15:02 UTC
Simple #
Yes you are right - my question was about MVVM Framework for WPF.. )

2012-05-10 20:16 UTC
Simple #
Hello again Mark!

Do you use some kind of GUI-Tests? To simulate users cliks etc..

2012-05-14 07:09 UTC
2012-05-14 08:23 UTC

Omitting Only Certain Properties With AutoFixture

Monday, 17 August 2009 19:33:40 UTC

The default behavior of AutoFixture is to create an Anonymous Variable by assigning a value to all writable properties of the created instance. This is great in many scenarios, but not so much in others. You can disable this behavior by using the OmitAutoProperties method, but sometimes, you would like most of the writable properties set, except one or two.

Consider this simple Person class:

public class Person
{
    private Person spouse;
 
    public DateTime BirthDay { get; set; }
 
    public string Name { get; set; }
 
    public Person Spouse 
    {
        get { return this.spouse; }
        set
        {
            this.spouse = value;
            if (value != null)
            {
                value.spouse = this;
            }
        }
    }
}

The main trouble with this class, seen from AutoFixture's perspective, is the circular reference exposed by the Spouse property. When AutoFixture attempts to create an anonymous instance of Person, it will create anonymous values for all writable properties, and that includes the Spouse property, so it attempts to create a new instance of the Person class and assign values to all public properties, including the Spouse property, etc.

In other words, this line of code throws a StackOverflowException:

var person = fixture.CreateAnonymous<Person>();

If you would still like to have anonymous values assigned to Name and BirthDay, you can use the Without method:

var person = fixture.Build<Person>()
    .Without(p => p.Spouse)
    .CreateAnonymous();

This will give you an anonymous instance of the Person class, but with the Spouse property still with its default value of null.

Several calls to Without can be chained if you want to skip more than one property.


A Fluent Interface For Testing INotifyPropertyChanged

Thursday, 06 August 2009 17:58:36 UTC

If you are doing Rich UI, INotifyPropertyChanged is a pretty important interface. This is as true for WPF as it was for Windows Forms. Consisting solely of an event, it's not any harder to unit test than other events.

You can certainly write each test manually like the following.

[TestMethod]
public void ChangingMyPropertyWillRaiseNotifyEvent_Classic()
{
    // Fixture setup
    bool eventWasRaised = false;
    var sut = new MyClass();
    sut.PropertyChanged += (sender, e) =>
        {
            if (e.PropertyName == "MyProperty")
            {
                eventWasRaised = true;
            }
        };
    // Exercise system
    sut.MyProperty = "Some new value";
    // Verify outcome
    Assert.IsTrue(eventWasRaised, "Event was raised");
    // Teardown
}

Even for a one-off test, this one has a few problems. From an xUnit Test Patterns point of view, there's the issue that the test contains conditional logic, but that aside, the main problem is that if you have a lot of properties, writing all these very similar tests become old hat very soon.

To make testing INotifyPropertyChanged events easier, I created a simple fluent interface that allows me to write the same test like this:

[TestMethod]
public void ChangingMyPropertyWillRaiseNotifyEvent_Fluent()
{
    // Fixture setup
    var sut = new MyClass();
    // Exercise system and verify outcome
    sut.ShouldNotifyOn(s => s.MyProperty)
        .When(s => s.MyProperty = "Some new value");
    // Teardown
}

You simply state for which property you want to verify the event when a certain operation is invoked. This is certainly more concise and intention-revealing than the previous test.

If you have interdependent properties, you can specify than an event was raised when another property was modified.

[TestMethod]
public void ChangingMyPropertyWillRaiseNotifyForDerived()
{
    // Fixture setup
    var sut = new MyClass();
    // Exercise system and verify outcome
    sut.ShouldNotifyOn(s => s.MyDerivedProperty)
        .When(s => s.MyProperty = "Some new value");
    // Teardown
}

The When method takes any Action<T>, so you can also invoke methods, use Closures and what not.

There's also a ShouldNotNotifyOn method to verify that an event was not raised when a particular operation was invoked.

This fluent interface is implemented with an extension method on INotifyPropertyChanged, combined with a custom class that performs the verification. Here are the extension methods:

public static class NotifyPropertyChanged
{
    public static NotifyExpectation<T>
        ShouldNotifyOn<T, TProperty>(this T owner,
        Expression<Func<T, TProperty>> propertyPicker) 
        where T : INotifyPropertyChanged
    {
        return NotifyPropertyChanged.CreateExpectation(owner,
            propertyPicker, true);
    }
 
    public static NotifyExpectation<T> 
        ShouldNotNotifyOn<T, TProperty>(this T owner,
        Expression<Func<T, TProperty>> propertyPicker)
        where T : INotifyPropertyChanged
    {
        return NotifyPropertyChanged.CreateExpectation(owner,
            propertyPicker, false);
    }
 
    private static NotifyExpectation<T>
        CreateExpectation<T, TProperty>(T owner,
        Expression<Func<T, TProperty>> pickProperty,
        bool eventExpected) where T : INotifyPropertyChanged
    {
        string propertyName =
            ((MemberExpression)pickProperty.Body).Member.Name;
        return new NotifyExpectation<T>(owner,
            propertyName, eventExpected);
    }
}

And here's the NotifyExpectation class returned by both extension methods:

public class NotifyExpectation<T>
    where T : INotifyPropertyChanged
{
    private readonly T owner;
    private readonly string propertyName;
    private readonly bool eventExpected;
 
    public NotifyExpectation(T owner,
        string propertyName, bool eventExpected)
    {
        this.owner = owner;
        this.propertyName = propertyName;
        this.eventExpected = eventExpected;
    }
 
    public void When(Action<T> action)
    {
        bool eventWasRaised = false;
        this.owner.PropertyChanged += (sender, e) =>
        {
            if (e.PropertyName == this.propertyName)
            {
                eventWasRaised = true;
            }
        };
        action(this.owner);
 
        Assert.AreEqual<bool>(this.eventExpected,
            eventWasRaised,
            "PropertyChanged on {0}", this.propertyName);
    }
}

You can replace the Assertion with one that matches your test framework of choice (this one was written for MSTest).


Comments

PeteB #
I'm never played with modifying/creating a fluent interface; how can this be extended to check for multiple NotifyProperty events (and NOT events)?

e.g.
sut.ShouldNotifyOn(s => s.MyProperty).AndOn(s => s.MyDependentProperty).AndNotOn(s => s.MyIndependentProperty)
.When(s => s.MyProperty = "Some new value");
2012-08-06 11:39 UTC
Would that add more value than three individual tests?
2012-08-06 11:52 UTC

Disabling AutoProperties In AutoFixture

Thursday, 23 July 2009 14:54:45 UTC

Since AutoFixture is a Test Data Builder, one of its most important tasks is to build up graphs of fully populated, yet semantically correct, strongly typed objects. As such, its default behavior is to assign a value to every writable property in the object graph.

While this is sometimes the desired behavior, at other times it is not.

This is particularly the case when you want to test that a newly created object has a property of a particular value. When you want to test the default value of a writable property, AutoFixture's AutoProperty feature is very much in the way.

Let's consider as an example a piece of software that deals with vehicle registration. By default, a vehicle should have four wheels, since this is the most common occurrence. Although I always practice TDD, I'll start by showing you the Vehicle class to illustrate what I mean.

public class Vehicle
{
    public Vehicle()
    {
        this.Wheels = 4;
    }
 
    public int Wheels { get; set; }
}

Here's a test that ensures that the default number of wheels is 4 - or does it?

In fact the assertion fails because the actual value is 1, not 4.

[TestMethod]
public void AnonymousVehicleHasWheelsAssignedByFixture()
{
    // Fixture setup
    var fixture = new Fixture();
    var sut = fixture.CreateAnonymous<Vehicle>();
    // Exercise system
    var result = sut.Wheels;
    // Verify outcome
    Assert.AreEqual<int>(4, result, "Wheels");
    // Teardown
}

Why does the test fail when the value of Wheels is set to 4 in the constructor? It fails because AutoFixture is designed to create populated test data, so it assigns a value to every writable property. Wheels is a writable property, so AutoFixture assigns an integer value to it using its default algorithm for creating anonymous numbers. Since no other numbers are being created during this test, the number assigned to Wheels is 1. This is AutoFixture's AutoProperties feature in effect.

When you want to test constructor logic, or otherwise wish to disable the AutoProperties feature, you can use a customized Builder with the OmitAutoProperties method:

[TestMethod]
public void VehicleWithoutAutoPropertiesWillHaveFourWheels()
{
    // Fixture setup
    var fixture = new Fixture();
    var sut = fixture.Build<Vehicle>()
        .OmitAutoProperties()
        .CreateAnonymous();
    // Exercise system
    var result = sut.Wheels;
    // Verify outcome
    Assert.AreEqual<int>(4, result, "Wheels");
    // Teardown
}

The OmitAutoProperties method instructs AutoFixture to skip assigning automatic Anonymous Values to all writable properties in the object graph. Any properties specifically assigned by the With method will still be assigned.

The test using OmitAutoProperties succeeds.


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.


Page 69 of 73

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