Today I will solve a problem concerning single responsibility principle and lazy loading properties using Castle DynamicProxy. My example application is a simple bookstore, that can display books from an XML.
public interface IStoreRepository
{
IList<Book> GetAll();
IList<Author> GetAuthorsForBook(string isbn);
}

Because the Author object would require a JOIN, we would like to lazy load the values - meaning, when we access the property it will be loaded with values from the datasource.
Castle.DynamicProxy2
Download the dynamic proxy and reference it in your project.

Now create a ProxyBuilder that will be responsible for creating proxies instances for the Book class. It is also possible to create proxies from classes but that is something you may discover by yourself.
public interface IProxyBuilder
{
T ProxyFromClass<T>() where T : class;
}
public class ProxyBuilder : IProxyBuilder
{
private readonly IInterceptor[] interceptors;
private readonly ProxyGenerator proxyGenerator;
public ProxyBuilder(IInterceptor[] interceptors)
: this(interceptors, new ProxyGenerator())
{
}
public ProxyBuilder(IInterceptor[] interceptors, ProxyGenerator proxyGenerator)
{
this.interceptors = interceptors;
this.proxyGenerator = proxyGenerator;
}
public virtual T ProxyFromClass<T>() where T : class
{
return proxyGenerator.CreateClassProxy<T>(interceptors);
}
}
If this where a larger application I would use a DI framework and register different instances of IProxyGenerator, for example.
container.Register<IProxyBuilder>("LazyAuthors", new[] { new LazyLoadAuthorsInterceptor() });
Our implementation of the interceptor that will be triggered on every virtual member of the class where it's put.
public class LazyLoadAuthorsInterceptor : IInterceptor
{
private readonly IStoreRepository repository;
private const string MethodName = "get_Authors";
public LazyLoadAuthorsInterceptor(IStoreRepository repository)
{
this.repository = repository;
}
public void Intercept(IInvocation invocation)
{
if (invocation.Method.Name == MethodName)
{
var isbn = ((Book) invocation.InvocationTarget).Isbn;
invocation.ReturnValue = repository.GetAuthorsForBook(isbn);
}
}
}
Now we can create a proxy class of book, and when we call the Authors property, the authors will be loaded and returned from IStoreRepository.
var proxyBuilder = new ProxyBuilder(new [] { new LazyLoadAuthorsInterceptor(new StoreRepository()) };
var book = proxyBuilder.ProxyFromClass<Book>();
// Will call IStoreRepository.GetAuthorsForBook
var authors = book.Authors;
You may get the code for this here, or you may download it as a zip package.

1 Comment
Interception with LinFu « Mint said
[...] have previously showed you how you can do interception with both Castle DynamicProxy and with Unity. Now it is time to do the same with LinFu, which is suprisingly easy if you have [...]