Archive for July, 2009

MVC Model Binding to an interface

No Comments »

Have you ever tried using ASP.NET MVC’s data binding capabilities against an interface? If so, you may have experienced some unexpected behaviour.

Let’s say we’ve got a form with two fields that we want to post to a Create action. In the Create action we’ll usually databind the fields to properties of a business object and persist the object to the database. For this example, we’ll just perform the data binding and display the bound values.

Our Order class is very simple:

public class Order : IOrder
{
    public int Id { get; set; }
    public string Text { get; set; }
}

Our form for submitting an order is equally simple:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
    Home Page
</asp:Content>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%= Html.Encode(ViewData["Message"]) %></h2>

     <% using (Html.BeginForm("Create", "Home")){ %>
        <fieldset>
        <legend>Order:</legend>
            Id:<br />
            <%= Html.TextBox("order.Id") %> <br />
            Text:<br />
            <%= Html.TextBox("order.Text") %><br />
        </fieldset>
    <%} %>
</asp:Content>

We’ve got a Create action like this

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection form)
{
    Order order = new Order();
    UpdateModel(order, "order", form.ToValueProvider());

    ViewData["Id"] = order.Id;
    ViewData["Text"] = order.Text;

    return View();
}

and a corresponding view which displays the values:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Create</h2>
    <p>Data used for create:</p>
    <p>
        Id: <%= ViewData["Id"] %> <br />
        Text: <%= ViewData["Text"] %>
    </p>


</asp:Content>

When we enter a pair of values like so

forminput

we will see this upon submitting

result1

However, what happens if we try to databind to a reference of type IOrder? The IOrder interface looks like this

public interface IEntity
{
    int Id { get; set; }
}

public interface IOrder : IEntity
{
    string Text { get; set; }
}

If we change the Create action to use an IOrder reference like so

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection form)
{
    IOrder order = new Order(); //This line has been changed
    UpdateModel(order, "order", form.ToValueProvider());

    ViewData["Id"] = order.Id;
    ViewData["Text"] = order.Text;

    return View();
}

we will se a somewhat surprising result:

result2 

What happens is that the posted value is not bound to the Id property of IOrder! The reason for this turns out to be that the Id property is declared in the IEntity interface. If you move the Id property from IEntity to IOrder, things will again be working as expected.

Tihs is something to keep in mind when you’re considering what to use for databinding in your application. If all your business objects are encapsulated in interfaces once they get to the web tier, you may have to provide special types for use in databinding, even though this to some extent defeats the purpose of databinding..

I have previously written a blog post about why this behaviour occurs: Hey, where are my interface’s properties?


Hey, where are my interface’s properties?

2 Comments »

This post is about the somewhat unexpected behaviour of the Type.GetProperties() method when it is called on an interface.

Last week I began writing an ASP.NET MVC application to act as a dashboard for an application which has previously had a very cumbersome UI (involving pgAdmin – certainly not best practice :-). I wanted it to have a very light feel, hence decided to use as much AJAX as I could get away with. This has worked out very well. I’ve now got 1(!) view and a bunch of controller actions all returning JsonResults.

My business objects all reference each other, even in a circular fashion: an Order has a List<OrderLine> OrderLines property and each OrderLine has an Order property. I would like to pass orders and orderlines to the browser using JSON, but using an Order as data for a JsonResult will cause the serializer to barf because of the circularity. Thus, we’ll need to pass a simpler object to the JsonResult (that’s a good idea anyway, since you will usually not need/want all the object’s properties to be passed to the browser).

My business objects looked something like

namespace X.BO
{
    public class Entity
    {
        public virtual int Id { get;set; }
    }

    public class OrderLine : Entity, IOrderLine
    {
        public virtual string Text { get; set; }
        public virtual int UnitPrice { get; set; }
        public virtual string Quantity { get; set; }
        public virtual string ProductNumber { get; set; }
        public virtual Order Order {get;set;}
    }
}

and I decided that I would want to pass objects like

namespace X.JSON
{
    public class OrderLine
    {
        public int Id { get; set; }
        public string Text { get; set; }
        public int UnitPrice { get; set; }
        public string Quantity { get; set; }
        public string ProductNumber { get; set; }
        public int OrderId {get;set;}
    }
}

to the JsonResult. I furthermore anticipated that I would be passing all kinds of objects to the browser, hence didn’t want to write all the boilerplate code for mapping from my business objects to the JSON objects over and over. What I needed was a generic mapper. Among the features I wanted was the ability to automatically have the mapper map references to business objects in the source object to an identifier in the target JSON object (for an orderline this would mean automatically mapping the BO.OrderLine.Order property of type  BO.Order to the JSON.OrderLine.OrderId property of type Int32 by copying the value of BO.Order.Id (all my business objects have an identifier named Id of type Int32).

I considered using AutoMapper, but, not having used it before, I decided that for my limited needs it would be faster to just roll my own mapper (of course, as is most often the case, my needs changed over time and I am now thinking about investing the time to get acquainted with AutoMapper – I guess hindsight is always 20/20 :-).

So, I got to work on the mapper, initially named Business2JSONMapper. Everything was working out fine, I was writing unit tests, they were all passing and I was feeling good about myself. At last I fired up the application and, lo and behold, the Business2JSONMapper blew up, complaining that the target object X.JSON.OrderLine had a property named ‘Id’ of type Int32, but that the source object had no such property! This had me baffled! The source object certainly had a property named ‘Id’ of type Int32!

I started furiously banging out regression tests to try and reproduce the behaviour in my unit tests. I had been using pretty simple objects previously, so I started adding virtual properties, inherited properties etc.

In the end, it turned that the problem lay with the IOrderLine interface. In my application, all my references are interfaces, but I hadn’t been using interfaces in the tests. The IOrderLine interface looks something like

namespace X.BO
{
    public class IEntity
    {
        public virtual int Id { get;set; }
    }

    public class IOrderLine : IEntity
    {
        string Text { get; set; }
        int UnitPrice { get; set; }
        string Quantity { get; set; }
        string ProductNumber { get; set; }
        Order Order {get;set;}
    }
}

In the Business2JSONMapper code I used the Type.GetProperties() method to determine the set of properties on the source object which might act as sources for each of the properties of the target object. This worked great when acting on classes like OrderLine, but when called on the IOrderLine type, the Id property wasn’t among the properties being returned!

Some investigation revealed the reason for this: when an interface inherits from a parent interface, it does not inherit the properties of the parent interface, it only inherits the requirement to implement these properties!

This conforms with section 8.10 of the CLI specification:

Only object types can inherit implementations, hence only object types can inherit members (see §8.9.8). While interface types can be derived from other interface types, they only “inherit” the requirement to implement method contracts, never fields or method implementations.

Thus, in order to get a full list of the properties required by an interface, we will have to traverse the inheritance hierarchy:

public List<PropertyInfo> GetTypesProperties(Type type)
{
    List<PropertyInfo> typesProperties = type.GetProperties().ToList();

    if (!type.IsInterface)
        return typesProperties;

    foreach (Type intface in type.GetInterfaces())
        typesProperties.AddRange(GetTypesProperties(intface));

    return typesProperties;
}

For mapping purposes this might lead to some problems, since we may find properties of the same name and type in different interfaces. Fortunately, I know that I don’t have to worry about this in my particular case, but if you’re writing a mapper yourself, it may be a problem you’ll have to consider.