The Grand Unified Framework Theory

Tuesday, May 4, 2010 by K. Scott Allen
0 comments

Tom Janssens left a comment:

What still bugs me is that we do not have a unified pattern for all .net dev (using modelbinders and icommand for example...)

But, Tom – we are pretty close. At least as close as we should be, I think. With .NET there are plenty of low level patterns we can reuse regardless of the application platform or architecture. Stuff like:

  • Asynchronous programming with events or the TPL.
  • Object queries with LINQ.
  • Resource management with IDispose.

 

At a higher level, XAML {Binding} and friends are taking over client-side development. WPF runs on the desktop, while Silverlight runs in the browser, on phones, and on the desktop, too. The only formality left for total unification is the merge of Silverlight and WPF into a single product.

On the server side things are different, but maybe not as different as they first seem. Take, for example, the following method:

public int Create(Employee newEmployee)
{
    // ....
    return newEmployee.Id;
}

This method might belong to an ASP.NET MVC controller, or it might belong to a WFC web service. We can’t really tell without more context. If the method belongs to a controller, than a model binder will go out and search the HTTP payload for information it can use to put together an Employee. If the method belongs to a service than a serializer will use information gathered from the payload to form an Employee. Underneath the covers one recognizes the soap:mustUnderstand attribute and one doesn’t, but there isn’t a significant difference in the programming model.

And I think this is about as far as we should go. The “one size fits all” framework never fits anyone well. 

 

onesizefitsall

What’s Wrong With This Code (#25)

Monday, May 3, 2010 by K. Scott Allen
3 comments

The goal: create an extension method that will make it easy to create FormCollection objects. The method is a helper for unit testing ASP.NET MVC code.

public static FormCollection ToFormCollection(this object data)
{
    var namesAndValues =
        data.GetType()
            .GetProperties()
            .WhereValueIsNotDefaultValue(data)
            .ToNameValueCollection(data);
    
    return new FormCollection(namesAndValues);
}

The extension method itself relies on a couple private extension methods:

static IEnumerable<PropertyInfo> WhereValueIsNotDefaultValue(
    this IEnumerable<PropertyInfo> properties, object source)
{
    foreach(var p in properties)
    {
        var value = p.GetValue(source, null);
        if(value != (p.PropertyType.IsValueType ? 
                     Activator.CreateInstance(p.PropertyType)
                     : null))
        {
            yield return p;
        }
    }
}

static NameValueCollection ToNameValueCollection(
    this IEnumerable<PropertyInfo> properties, object source)
{
    return properties.Aggregate(
            new NameValueCollection(),
            (nvc,pi) =>
                {
                    var value = pi.GetValue(source, null);
                    nvc.Add(pi.Name, value.ToString());
                    return nvc;
                });
}

The code mostly works. This test passes:

public void should_copy_property_values()
{
    var expectedName = "Scott";
    var expectedHireDate = new DateTime(2010, 1, 1);

    var data = new Employee
    {
        Name = expectedName,
        HireDate = expectedHireDate
    }.ToFormCollection();

    Assert.IsTrue(data["Name"] == expectedName);
    Assert.IsTrue(data["HireDate"] == expectedHireDate.ToString());
}

However, the helper should not put entries in the FormCollection for properties holding a default value, and this test fails:

public void should_not_copy_default_values()
{
    var data = new Employee
    {
        Name = "",
        HireDate = DateTime.Now
    }.ToFormCollection();

    Assert.IsNull(data["Tags"]);
    Assert.IsNull(data["Id"]);
}

Employee is defined as:

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime HireDate { get; set; }
    public string Tags { get; set; }
}

Hint: the first assert passes – it’s the assert on data[“Id”] that fails.

by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!