Castle Windsor sample application now supports interface. If you have read my post on how to implement INotifyPropertyChanged interface using Castle DynamicProxy, here same technique is used in parallel with Fluent Validation framework for Silverlight. The magic behind this approach is that your models are clear as you want them to be. Let’s see in more detail how this can be done.

A typical implementation of interface is like the following, where you need to specify two things when object state has errors: A. Using the indexer you specify if a property value on the object has any error B. Error property that returns a general error message when object has any errors.

Let’s see how this looks on our simple Customer object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
namespace Castle.Samples.WindsorSilverlight.Model
{
using System;

public class Customer :
{
public virtual int Age { get; set; }

public virtual DateTime JoinedAt { get; private set; }

public virtual string Firstname { get; set; }

public virtual string Lastname { get; set; }

public virtual string this[string columnName]
{
get
{
switch (columnName)
{
case "Age":
return Age < 18 || Age > 60 ? "Age is not valid" : string.Empty;
case "Firstname":
return string.IsNullOrEmpty(Firstname) ? "Firstname is mandatory" : string.Empty;
case "Lastname":
return string.IsNullOrEmpty(Lastname) ? "Lastname is mandatory" : string.Empty;
default:
return string.Empty;
}
}
}

private bool HasAnyError()
{
return Age < 18 || Age > 60 ||
string.IsNullOrEmpty(Firstname) ||
string.IsNullOrEmpty(Lastname);
}

public virtual string Error
{
get { return HasAnyError() ? "Customer is not valid" : string.Empty; }
}
}
}

As you can see, our once clean object, is cluttered. One reason is that the validation logic is inside the same class (SoC anyone?), but even if we remove that, we’d have the interface implementation that delegate the dirty work to a validator, but again the noise is still there.

The solution is to use DataErrorInfoBehavior. Using this approach you don’t even need to implement the interface on your model class and it will be done for you dynamically. All you need to do is to register and resolve your objects from the container, and let it do all the heavy lifting for you.

To make the models resolved from the container implement interface for you, first you need to specify the additional interface that you require, and then add an interceptor to implement that interface dynamically. The following snippet will register your Customer class along with necessary interface and interceptor:

1
2
3
4
5
6
7
8
9
10
11
public class ModelInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
//Add interceptors and behaviors to the object
container.Register(Component.For<Customer>()
.LifeStyle.Transient
.Proxy.AdditionalInterfaces(typeof())
.Interceptors(typeof(DataErrorInfoBehavior)));
}
}

All the magic is in the DataErrorInfoBehavior class. Here we’ll validate the object based on what method of the is being called and set the return value of that method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void Intercept(IInvocation invocation)
{
if (invocation.Method.DeclaringType.Equals(typeof()))
{
var validator = GetValidator(typeof (Customer));
var result = validator.Validate(invocation.Proxy);

if(result.IsValid) //object is valid
{
invocation.ReturnValue = string.Empty;
return;
}

if (invocation.Method.Name == "get_Item") //Indexer is called, get the error for the property
{
var propertyName = (string) invocation.Arguments[0]; //property name to validate
var errors = result.Errors.Where(x => x.PropertyName.Contains(propertyName));

invocation.ReturnValue = string.Join(Environment.NewLine, errors);
}
else if (invocation.Method.Name == "get_Error") //Error property is called
{
invocation.ReturnValue = "Customer is not valid"
}
}
else
{
//Other methods not belonging to ,
//so just invoke the original method.
invocation.Proceed();
}
}

If you resolve an instance of your object from the container and bind it to a view, you’ll see that this is working pretty sweet.

Data Validation

If you are interested, you can check out the complete implementation along with other goodies in Castle Windsor Example Application over at GitHub.