Thursday, December 17, 2009

WPF: MultiBinding and IMultiValueConverter

I came across the MultiBinding markup extension and IMultiValueConveter today when looking for a solution to a problem. Not sure how I missed it previously. If you didn’t I probably don’t have a lot to add, but if you have not heard of them then read on.

The problem basically went like this, I have a TabControl that is hosting content with a Title property and an IsChanged property. I was binding the Header of the TabControl item to the Title of the content, but I wanted to add an ‘*’ to the end of the text if IsChanged was True.

I initially moved the binding to the class itself (instead of the Title property) and added an IValueConverter that could convert convert an instance of the class into the string I wanted (Title + (IsChanged ? “ *” : “”)) and while this worked when the binding was evaluated the first time, it obviously (if you understand WPF) broke when Title or IsChanged were updated.

Enter a MultiBinding and its partner in crime IMultiValueConverter. Now anyone who learnt WPF from a book or tutorial probably had a section all about this pair and how useful they are. Those of us who learn as we go however might have missed this one like I did.

A MultiBinding works just a regular Binding except it must have a Converter specified and can have multiple pieces of data bound to it, so when any of these change it fires a re-evaluation of the lot. There are two cases where this is helpful, and I will explain both.

The first is probably the intended use, which is where you want to combine two data elements into a single value and update that value when either changes.

For our example we are using a basic dataclass with two properties, a WPF form with a textbox to enter both of these values and a textblock to display the combination, and an implementation of IMultiValueConverter that does the combining. I have cut a few lines of code out for readability, but the whole lot is in the download linked at the bottom of this post.

   1: public class DataClass
   2: {
   3:     public string FirstName { get; set; }
   4:     public string Surname { get; set; }
   5: }
   6:  
   7: public class NameMultiValueConverter : IMultiValueConverter
   8: {
   9:     public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
  10:         return String.Format("{0} {1}", values[0], values[1]);
  11:     }
  12: }

The XAML looks basically like this, again I have cut out non-essential code so grab the download if you need it.

   1: <Window xmlns:local="clr-namespace:BlogIMultiValueConverter">
   2:     <Window.Resources>
   3:         <local:NameMultiValueConverter x:Key="NameMultiValueConverter" />
   4:     </Window.Resources>
   5:     <Grid>
   6:         <TextBox Text="{Binding Path=FirstName,UpdateSourceTrigger=PropertyChanged}" />
   7:         <TextBox Text="{Binding Path=Surname,UpdateSourceTrigger=PropertyChanged}" />
   8:         <TextBlock>
   9:             <TextBlock.Text>
  10:                 <MultiBinding Converter="{StaticResource NameMultiValueConverter}">
  11:                     <Binding Path="FirstName" />
  12:                     <Binding Path="Surname" />
  13:                 </MultiBinding>
  14:             </TextBlock.Text>
  15:         </TextBlock>
  16:     </Grid>
  17: </Window>

Fire it up and enter some data and you get this

captured_Image.png[4]

Nice and simple, does just what you would expect. But what I found more useful was to include the object itself as the first Binding, and then use the extra bindings simply for their triggers.

What this lets you do is call methods on the object to aid in the production of your new value. This could save some duplicating of code if you already have a method that does the transformation (for example builds a name or address string from its components) while still having the update triggered when any component changes.

So our IMultiValueConverter becomes (I have it doing a pointless task simply to show the difference)

   1: public class DataClassMultiValueConverter : IMultiValueConverter
   2: {
   3:     public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
   4:         if (values[0] is DataClass) {
   5:             DataClass data = values[0] as DataClass;
   6:             return String.Format("{0} {1} {2}", data.FirstName, data.Surname, data.ExtraData());
   7:         } else { return ""; }
   8:     }
   9: }

And the XAML becomes

   1: <MultiBinding Converter="{StaticResource DataClassMultiValueConverter}">
   2:     <Binding />
   3:     <Binding Path="FirstName" />
   4:     <Binding Path="Surname" />
   5: </MultiBinding>

And the result of this useless conversion

captured_Image.png[6]

So there you have it. If you missed the MultiBinding / IMultiValueConverter and need to convert/combine data for display purposes while maintaining the regular Binding trigger mechanism, make sure you take a look.

Labels: , , ,

Repository vs Query

I’ve read a lot of blog posts about the Repository pattern. Whenever I have looked at implementing it, I always come away underwhelmed. It’s one of those things that displays nicely in a small example but in practice you end up with a huge number of methods that each query the data in a similar but slightly different manner, and for me it’s fault is with querying.
GetCustomersByFirstName();
GetCustomersByFirstAndLastName(); GetCustomersByFirstAndLastAndThreeOfTheirFourChildrensNames();

Now granted I made that last one up, but I have seen Repository examples that are nearly as silly.

The story is even worse when you are trying to bring back data in a form that does not exactly match your data structure. The pattern feels very restrictive to me with each repository matching an entity in the database.

LINQ is a tempting way of getting around the querying problems by exposing a LINQ provider for your datasource to the other areas of the application. Which in certain cases I am all for, but in a large enough application this really isn’t that different from just letting the business layer execute it’s own SQL. Sure you might get some strong typing, but a basic structure change in the database can still see you hunting all over for references that need fixing.

Then one day I saw in passing someone comment they preferred to use Query objects now over Repositories. A quick internet search didn’t turn up anything I considered a pattern so I set about thinking what might be meant by a Query object, and quickly convinced myself this is what I was really after.

The basic requirements I had were a data layer that worked with POCO objects, able to be created as an interface to allow a secondary implementation and a focus on usable querying for both straight entities from the database and ad-hoc queries as needed.

The objects I ended up with were fluent wrappers for basically a set of query options. These options are then used to construct a query using whatever method of database connection the app is using. Here is an example of a query to give you an idea of how it works.

IList<Customer> = db.CustomerQuery()
    .FirstName_Contains("Fred")
    .LastName_Is("Blog")
    .Age_Between(18, 35)
    .FirstName_Sort(SortOrder.Ascending)
    .List();

And here is an example of how to implement FirstName_Contains() in an implementation of the query layer that uses NHibernate.Linq as it’s data provider.

public ICustomerQuery FirstName_Contains(string name) {
    if (!String.IsNullOrEmpty(name))
        Query = Query.Where(d => d.FirstName.Contains(name));
    return this;
}

Obviously that implementation code depends heavily on how you talk to your database. Before I started to utilise NHibernate.Linq it looked more like this

Criteria.Add(Expression.Like("FirstName", name)

So I now use a single database object that can load and save an entity from any table in the database, and it can also set up a query object for me to fill out with the appropriate options for that query and execute it.

I find this a nice middle ground between needing every query to have it’s own method and the open slate that comes from exposing a LINQ provider or SQL statements.

I won’t pull apart one of the projects that uses this to offer a full example of every method, but it is simple to add features like Top(), Take()/Skip(), even Count().

Labels: ,

Thursday, November 05, 2009

WPF + Strong Typing

I have been working with WPF recently, and one of the things that annoys me most is the usage of strings to reference object properties. This mainly affects Bindings, but also pops up in other places such as the IDataErrorInfo interface.

Here is an example that anyone who has touched WPF should understand.

<TextBox Name="textBox1" Text="{Binding DataItem}" />

This particularly bothers me when writing a project from scratch where the data model is still evolving and there is refactoring going on. While some tools like ReSharper are pretty good at picking these up and changing them when you rename a property, you are still relying on the correct usage of a tool rather than the compiler to keep everything in sync.

Now perhaps I am just bad at bing-ing (not quite as catchy as Google’s verbs is it) but this issue seems to be really difficult to find any good coverage on. There are a number of posts around with people complaining, and there are a number of cranky comments on those blogs from people who just say deal with it, but there is very little in the way of a solution. And from what I have seen there is no attempt to improve the situation in the next release of VS/WPF/C#.

Now I don’t have a perfect solution to offer either, but I do have  a little class that makes my life easier. It is similar code to what you will find inside some LINQ providers if you dig into them and involves breaking a Lambda Expression down into a useful form (in this case a string).

First things first, this involves moving your bindings from the XAML and into the code-behind file (or some other place that has access to the controls). Personally I prefer this, I like to put as little into XAML as possible. I see the XAML as a visual layer, therefore beyond visual styling and control names I try to keep my XAML files empty. I personally do both data binding and event binding in the code behind, always have.
If this is unacceptable to you for whatever reason, then I can do nothing to help your assumed string based data binding woes.

On to the code.

   1: using System;
   2: using System.Linq.Expressions;
   3:  
   4: namespace MagicStringBlog
   5: {
   6:     public static class MagicString
   7:     {
   8:         public static string Get<T>(Expression<Func<T, object>> ex) {
   9:             string name;
  10:             switch (ex.Body.NodeType) {
  11:                 case ExpressionType.MemberAccess:
  12:                     name = ex.Body.ToString();
  13:                     break;
  14:                 case ExpressionType.Convert:
  15:                     name = ((UnaryExpression)ex.Body).Operand.ToString();
  16:                     break;
  17:                 default:
  18:                     throw new Exception(String.Format("Expression type {0} unknown", ex.Body.NodeType));
  19:             }
  20:             name = name.Substring(name.IndexOf('.') + 1);    // remove the lambda name from expression (d=>d.Test to Test)
  21:             return name;
  22:         }
  23:     }
  24: }

I stole the name MagicString from a blog post I read a while ago about configuring NHibernate and how all the strings were “magic” because you just had to assume you have typed them correctly and that they will work. (On a side note for NHibernate users, if you are using the Fluent interface you are likely to find some code very similar to the above in it somewhere)

The first thing to note is that the Func<T, object> which describes a delegate that takes a parameter of type T and returns something (of type object, so anything) is wrapped in a System.Linq.Expressions.Expression. I’ve never looked at how this precisely works, but the end result is that instead of getting a reference to a delegate that can be .Invoke()’d you get an expression tree that can be analysed, modified, compiled and then executed. Note that here I only perform step one of that sequence, there is no attempt at execution made.
These expressions are at the core of how a LINQ provider such as LINQ-to-SQL can take your .Where(d=>d.PK==1) and turn it into a SQL statement rather than returning all the objects from the database and running that piece of code over them as CLR objects.

The contents of the method are not as important as the signature, but basically it analyses the expression, pulls out the name of the property being referenced and returns it. The only complication comes from types that are wrapped to be returned as an object, for example bool, then you need to dig inside the casting operator.

And here is how we call it in the case of a data binding.

textBox2.SetBinding(TextBox.TextProperty, MagicString.Get<DataClass>(x => x.DataItem));

For the record here is the data class that is being used. Complicated!

   1: namespace MagicStringBlog
   2: {
   3:     public class DataClass
   4:     {
   5:         public int DataItem { get; set; }
   6:     }
   7: }

It’s worth noting that I find the binding expression above too long as well, and have created an Extension Method on controls that has the following signature.

public static void Bind<T>(this FrameworkElement el, DependencyProperty dp, Expression<Func<T, object>> ex)

Which cuts down the call time binding code to

textBox2.Bind<DataClass>(TextBox.TextProperty, d=>d.DataItem);

With this in place, even the Visual Studio rename tools will find the property and tidy up its name if your objects change, and it will be checked at compile time.

Now I said earlier that this solution is not perfect, and I meant that. One problem is that all we are doing is turning a string literal into a runtime generated string. There is nothing that is going to check that the DataContext of the TextBox is actually of the type you are binding to, and you are going to suffer some performance hit (I haven’t run the numbers to see how much of one), but the safety this does bring I find useful. I didn’t move to C# only to need to search my code for string literals every time I want to rename a property.

Here is a project that includes the code and shows both regular binding and “MagicString” binding.

Labels: , ,

Tuesday, February 03, 2009

Moq: Mocking GetEnumerator()

In my last post I made mention that it was easier not to use the Enumerators on HTTP context objects when you want to unit test with mocking. This is due to some annoyances with casting (as they predate generics) that can be avoided with simple for() loops instead of foreach().

Today however, I am going to look at mocking GetEnumerator() in a more general sense should you ever need it. Also for the first time I am going to pop the code onto SkyDrive and include line numbers in my code snippets.

We start with a simple "business object" that iterates over a set of products returning a list of their names. Nice useless test code as always.

   1: public class BizProducts
   2: {
   3:     private IProductsRepository db;
   4:  
   5:     public BizProducts(IProductsRepository repository) {
   6:         db = repository;
   7:     }
   8:  
   9:     public string List() {
  10:         StringBuilder sb = new StringBuilder();
  11:         foreach (Product p in db) {
  12:             sb.AppendLine(p.ProductName);
  13:         }
  14:         return sb.ToString();
  15:     }
  16: }

The business object expects to be passed its data store rather than creating the instance itself. This has two benefits, it becomes far easier to unit test as we can pass in a mocked set of data rather than the concrete class used in the real code, and we can also plug it into a dependency injection framework easily.

The product repository interface and the underlying product class look like this. Note that the IProductsRepository implements the IEnumerable<Product> interface, which exposes a strongly typed GetEnumerator() method rather than the older object one. This comes from System.Collections.Generic

   1: public interface IProductsRepository : IEnumerable<Product>
   2: {
   3: }
   4:  
   5: public class Product
   6: {
   7:     public int ProductID { get; set; }
   8:     public string ProductName { get; set; }
   9: }

Now a concrete implementation of the IProductsRepository is likely to connect to SQL Server for its data, but this can be a pain with unit testing as it requires every developer who is sharing tests to have consistent data that can be coded into the unit tests. It also means a test for the business object needs to rely on a bug free data layer to succeed. It is better to test one thing at a time, leave testing the data layer to the data layer tests. This means we need to mock the data layer in business object tests, which means we need to sort out mocking the implicit GetEnumerator() called by the foreach() loop.

Here is a unit test you can use that will mock the IProductsRepository interface using Moq

   1: [TestClass]
   2: public class BizProductsTests
   3: {
   4:     [TestMethod]
   5:     public void TestList() {
   6:         Mock<IProductsRepository> repository = new Mock<IProductsRepository>();
   7:         repository.Expect(d => d.GetEnumerator()).Returns(ProductList());
   8:         BizProducts biz = new BizProducts(repository.Object);
   9:  
  10:         string s = biz.List();
  11:         Assert.AreEqual("First Product\r\nSecond Product\r\n", s);
  12:     }
  13:  
  14:     public IEnumerator<Product> ProductList() {
  15:         yield return new Product() { ProductID = 1, ProductName = "First Product" };
  16:         yield return new Product() { ProductID = 2, ProductName = "Second Product" };
  17:     }
  18: }

Line 7 sets up the expectation that the GetEnumerator() method should return the IEnumerator<Product> returned by the ProductList() method. It turns out one of the easiest ways to get your hands on an enumerator is with the lovely yield statement. Better yet since it comes out of a method, you could set this list of products up once and use it through all appropriate unit tests.
Another option not shown here is by using a generic collection such as List<Product> to store your products, and then return its GetEnumerator(), make sure you use a collection from System.Collections.Generic though, older collections will not implement the generic IEnumerable<> interface.
I prefer the yield method as it is simpler to set up and keeps the actual unit test code shorter, but if you need to inspect the underlying objects afterwards or prefer to keep the code all in one place than the List<> option would be the way to go.

Here is the link to the hopefully working solution file on SkyDrive.

Labels: , , ,

Thursday, January 29, 2009

ASP.NET MVC: Unit Test File Upload with Moq

Microsoft released the ASP.NET MVC Release Candidate yesterday (Link). One thing that pricked my ears in the release notes was a change to the ControllerContext that would apparently make it easier to use a mocking tool to unit test actions that needed to interact with the standard HTTP objects.

I gave up on mocking back at Preview 3 of the MVC framework, and instead I was slowly building up a library of classes using the Http...Base (eg HttpRequestBase) classes that implemented each feature as needed. It was a little bit of work, but at least it did work.

With ScottGu's example in hand and a copy of Moq installed and referenced in my test project I set about replacing my own classes with the appropriate mocks in each test of a project I am working on at the moment. The results were surprisingly good, I am now able to mock every part of the web context I am currently using with ease.

One scenario I was pretty impressed with that I will share with you is mocking the Request.Files collection to test uploading files to a site. I will start with a simple Upload method and build a few iterations of the unit test to show what is going on. This isn't a lesson on mocking or unit tests, I have assumed you have some knowledge of both. I am simply showing off a particular mock I was impressed with.

First we need a new ASP.MVC project, we will add an Upload action to the Home controller like so.

public ActionResult Upload() {
    string s = "Uploaded " + Request.Files.Count.ToString() + " files.<br/>\n";
    for (int i = 0; i < Request.Files.Count; i++) {
        using (StreamReader reader = new StreamReader(Request.Files[i].InputStream)) {
            s += String.Format("File {0}: {1}<br/>\n", Request.Files[i].FileName, reader.ReadToEnd());
        }
    }
    return Content(s);
}

Obviously not a method you would use, but suits our purposes for demonstration. It simply loops through the files collection and writes out the name and contents of each file in the response. Note: It is easier to test this code with the for() loop instead of a foreach() as you do not need to mock GetEnumerator() which can be clumsy and in this case was struggling with casting.

If we put together a simple unit test for this, you will soon see the problem.

[TestMethod]
public void TestUpload() {
    HomeController c = new HomeController();
    ActionResult r = c.Upload();
    Assert.IsInstanceOfType(r, typeof(ContentResult));
    Assert.AreNotEqual("", ((ContentResult)r).Content);                        
}

This test throws a null exception on the first line of the Upload method because it can not access Request. On top of this problem it is not immediately obvious in your unit test how you even "upload" a file to the action. Because your unit test is not a web request, all the architecture of a usual web call (I am calling it the context through this post) is not created. The whole point of using mocking here is to recreate the part of the context the test needs to be able to succeed. Lets fix one step at a time though.

Since we are currently failing on Request.Files.Count, this will be the first mock we add. It looks like this.

[TestMethod]
public void TestUpload() {
    HomeController c = new HomeController();
    Mock<ControllerContext> cc = new Mock<ControllerContext>();
    cc.Expect(d => d.HttpContext.Request.Files.Count).Returns(2);
    c.ControllerContext = cc.Object;
    
    ActionResult r = c.Upload();
    Assert.IsInstanceOfType(r, typeof(ContentResult));
    Assert.AreNotEqual("", ((ContentResult)r).Content);                        
}

The object we want to mock is the ControllerContext, it can be attached to the Controller and contains all the HTTP classes we need to manipulate to fake a web request.
The syntax of Moq is very concise and provided you know how to read a lambda you will note that I am telling the mock that I expect HttpContext.Request.Files.Count to return 2.
The other key part of the Moq syntax is that to get the actual instance of the mocked object you access the .Object property. So we assign this to the controller as the context it should use.
If we run this test it still fails, but now it is failing on the first usage of the file inside the for loop. The code now thinks there are two files uploaded, it just couldn't find them when it went looking. If you have never played with mocking before, this simple concept of "I expect xxx to return yyy" will get you a long way improving your unit tests against an MVC website. It is fairly straight forward to mock any part of web context (Request, Response, Server, etc) just like this. But back to file uploads.

So what we need to do now, is to add two new expectations to the mocked ControllerContext to state that HttpContext.Request.Files[0] should return our first file and that .Files[1] should return our second file. This however begs the question, what exactly do they return. Our code is expecting objects of type HttpPostedFile to be returned from the Files collection, helpfully ASP.NET MVC has included an HttpPostedFileBase class that can be mocked to represent the objects of the Request.Files collection. So we simply need to create two of these, mocking the FileName and InputStream properties we have used in our code to return the relevant details from our test files. Then tell the mocked ControllerContext to return them. Putting this all together looks like this. Note that I am returning .Object again, it is important to understand the difference between the mocking configuration object and the actual instance you should use in your code.

[TestMethod]
public void TestUpload() {
    HomeController c = new HomeController();
    Mock<ControllerContext> cc = new Mock<ControllerContext>();
    UTF8Encoding enc = new UTF8Encoding();

    Mock<HttpPostedFileBase> file1 = new Mock<HttpPostedFileBase>();
    file1.Expect(d => d.FileName).Returns("test1.txt");
    file1.Expect(d => d.InputStream).Returns(new MemoryStream(enc.GetBytes(Resources.UploadTestFiles.test1)));

    Mock<HttpPostedFileBase> file2 = new Mock<HttpPostedFileBase>();
    file2.Expect(d => d.FileName).Returns("test2.txt");
    file2.Expect(d => d.InputStream).Returns(new MemoryStream(enc.GetBytes(Resources.UploadTestFiles.test2)));
                
    cc.Expect(d => d.HttpContext.Request.Files.Count).Returns(2);
    cc.Expect(d => d.HttpContext.Request.Files[0]).Returns(file1.Object);
    cc.Expect(d => d.HttpContext.Request.Files[1]).Returns(file2.Object);
    c.ControllerContext = cc.Object;

    ActionResult r = c.Upload();
    Assert.IsInstanceOfType(r, typeof(ContentResult));
    Assert.AreNotEqual("Uploaded 2 files.<br/>\nFile test1.txt: Contents of test file 1<br/>\nFile test2.txt: Contents of test file 2<br/>", ((ContentResult)r).Content);
This test now passes and we can be confident that our action for handling the upload of files is working correctly.

 Note: To host the actual test files I am uploading I have created a Resource file called UploadTestFiles and added two .txt files to it that are stored under the Resources sub-directory of the unit test project. I have found this to be a useful way to keep control of my test files. Using binary files is even easier than text files as you get direct access as a Stream, this saves you the encoding code you see above to turn the string into the Stream needed by the HttpPostedFile class.

So there you have it! Mocking of ASP.NET MVC has come a long way since I last looked at it. Exactly which release each piece of the puzzle dropped in, I can't say, but where we are at now with the Release Candidate is working quite well for me so far.

If you have had troubles with mocking the web context in ASP.NET MVC previously or simply avoided unit tests for actions that needed it. Now is a good time to take another look.

Labels: , , , , ,

Wednesday, May 07, 2008

The 'yield' Keyword

I have recently been brushing up on my Computer Science training, implementing various data structures and algorithms, O(log n) searching, that sort of thing. While traversing a binary tree returning it's contents in sorted order, I really wanted to put the yield keyword to use.

The yield keyword was introduced in .NET 2.0 and is used when added iteration features to a class. Typically this means when implementing the IEnumerable or IEnumerable<T> interfaces.

One of the most striking examples I have seen that demonstrates how it works is a simple method that returns an iterator over the numbers 1 to 10.

public IEnumerator<int> GetEnumerator() {
    yield return 1;
    yield return 2;
    yield return 3;
    yield return 4;
    yield return 5;
    yield return 6;
    yield return 7;
    yield return 8;
    yield return 9;
    yield return 10;
}

I think this simple-as-they-come example really represents what is going on here. The compiler uses this method to put together an iterator. When the first MoveNext() is called, the method executes until the first yield is reached. The value is returned and the state is saved, when the next MoveNext() is called, the code keeps running from where it was until the next yield is reached.
The iterator reaches its end when the function has no more statements to execute, or a yield break; is called.

I've long liked this concept, but rarely had any use for it that wasn't nearly as trivial as the example above. The big reason is that most of our data structures are already written for us these days. Need a list? Grab it from System.Collections. Therefore I rarely need to iterate in anything but a linear fashion.

So it wasn't until my recent adventures into re-learning some Computer Science theory that I was presented with a good chance to put this to work.
As I was saying, I was using a binary tree to store and sort a set of int's and then needed to pull them back out again in order. For any given node of the tree, this means returning the Left branch followed by the node's own value followed by the Right branch. By implementing the IEnumerable<int> interface on my Node class I was exposing the capability to use foreach(int i in Node) {} to return the values. All I needed was the code for the iterator.

public IEnumerator<int> GetEnumerator() {
    if (Left != null) {
        foreach (int i in Left) {
            yield return i;
        }
    }
    yield return Value;
    if (Right != null) {
        foreach (int i in Right) {
            yield return i;
        }
    }
}

Now I am not going to declare this is a perfect implementation to traverse a Binary Tree. I am not certain exactly what code this compiles down to, but assuming it becomes recursive makes it less than ideal.
Putting that aside for the moment however, I was really impressed with how succinctly this let me express how I wanted the code to behave.

All you could ask for on top of this at a language level is something like a
yield iterate Left;
Now that would really cut the code down.

Labels: ,

Tuesday, April 15, 2008

LINQ-to-SQL: Generic Primary Key function

An issue I have seen blogged about a number of times with LINQ-to-SQL is that by strong typing queries, you lose the ability to create generic functions for processes such as fetching records by their Primary Key. A recent example is Rick Strahl who offers a number of good options for getting around this, while not being particularly happy with any of them. In the comments of Rick's post Richard Deeming offers a solution very similar to my own, which is to use the Meta-data provided by LINQ-to-SQL and the functionality of System.Linq.Expressions to create a simple and robust solution.

Here is an extension method you can pop onto your DataContext object to facilitate the pulling of records from the database by their Primary Key.

public static class DataContextHelpers
{
    public static T GetByPk<T>(this DataContext context, object pk) where T : class {
        var table = context.GetTable<T>();
        var mapping = context.Mapping.GetTable(typeof(T));
        var pkfield = mapping.RowType.DataMembers.SingleOrDefault(d => d.IsPrimaryKey);
        if (pkfield == null)
            throw new Exception(String.Format("Table {0} does not contain a Primary Key field", mapping.TableName));
        var param = Expression.Parameter(typeof(T), "e");
        var predicate = Expression.Lambda<Func<T, bool>>(Expression.Equal(Expression.Property(param, pkfield.Name), Expression.Constant(pk)), param);
        return table.SingleOrDefault(predicate);
    }
}

You can then run this code by doing the following

MyDataContext db = new MyDataContext();
Product p = db.GetByPk<Product>(1);

Note: Excuse the excessive use of "var". However it can be useful in the context of a code-snippet as it removes the need for you to work out all the using statements needed to make the code work.

So what does this code do, first we get a reference to the LINQ-to-SQL meta data store for the table we are querying, then pull out the Primary Key field for the table. It then builds a lambda expression tree that compares the Primary Key field of the parameter (that will be passed to the expression later) against the constant id passed to the function. This expression is then passed into LINQ-to-SQL where it can be decomposed and turned into SQL code. This is effectively the same as writing the lambda  "e=>e.PK == id", except that we work out the name for PK at run-time.

I have attached this as an extension method on the DataContext, but if you are using a base class for your entities, or writing a generic business object, you should be able to manipulate this fairly easily to do as you wish.
I have only scratched the surface of what may be possible with this technique of building code through Expression Tress, there is bound to be some interesting work done in this area as people get more and more accustomed to the concept.

Labels: , ,

Friday, March 28, 2008

ASP.NET MVC Application Layout

I am slowly evolving my general layout for ASP.NET MVC applications as I come more and more to grips with the framework and they ways I am most comfortable using it.

This post is going to be a bit of an overview of how I am laying out my project at the moment in case it is of use to anyone.

Controllers

I have reduced the work-load of my controllers substantially since my early attempts. My average controller action now performs three simple steps. Create a Model, Pass the relevant state data from the URL to the Model, Choose and render a View.
When combined with the new ActionFilters to handle things like Authentication and SSL, I can really see my controllers being replaced by some form of Inversion-of-Control class that is configured up and simply runs the same piece of code for every action using the configuration as a guide.

Models

As my controllers have become simpler, my models have become more complicated. I am still using LINQ-to-SQL to connect to the database, but there is a bit more to models than just this.
My models have two sets of properties, those that are get/set which provide an interface for the controller to tell the model what state the user has requested (ie ProductID = 1) and those that are only get. The later provide the interface the View should use to present it's data. Often I don't load each piece of this data unless it is requested.

Views

I have killed off code behind files. I still think strong typing views is a good idea though.
Rather than having a code behind file on every page just to set up this strong typing, I am using a single Views.cs file for each directory of Views, it contains empty definitions for each page eg
public partial class Home : ViewPage<HomeModel> { }
The main benefit here is that it removes clutter, both in terms of files in the project and cuts down the @Page declaration in the .aspx files
For the project at hand this is very useful as I will need to deal with designers who will be making lots of pages based around a small number of models. So I will have a basic set of page models and you simply point that page at the one that provides the appropriate data set.

Testing

Testing of Controllers and Models is a fairly straight forward task now as they both have well defined roles. Testing a controller involves checking the correct View has been chosen and the a model has been correctly chosen and sent to the View. Testing a model involves setting different state configurations and then checking to see the data public data to be used by the view is correctly set.
Views are still causing head-aches for testing though. Getting a view to render down to a string from the context of a Unit Test is proving difficult. I should get my hands on a spare box to set up as a Continuous Integration and Test box soon though and if nothing else I will be able to use one of the UAT web tools to test Views along with the whole process flow and performance of the app.
I am also finding that using subclasses of the new Http*Base classes is an easier proposition than Mocking these classes. I have completely removed Mocking from my tests for the moment, though I learnt a lot from the excursion and will definitely find a use for the technique in the future.

Drawbacks

The only real concern I have at the moment is exposing LINQ-to-SQL classes through the model for the view to consume. This is effectively tightly coupling my views to the LINQ-to-SQL back-end. I believe to be a "truer" MVC application the data source should be easier to replace. If I wanted to switch to a disconnected web service based data source (for an extreme example) I would currently need to create a set of data classes that matched the LINQ-to-SQL classes, a massive task. It's near impossible to resist the lure of LINQ-to-SQL though, it is just so nice to work with.
I am hoping that the forth coming LINQ-to-Entities will reduce my concerns by at least offering a path to a different database on the back-end even if I can still not move to a totally different type of data source.

Conclusion

The more I use the framework, the more I like it. The recent release of the source code for the framework is a nice bonus, it has made debugging a few things easier and will make extending the framework much easier.

Labels: , ,