Castle Dynamic Proxy
March 30, 2008This blog has been silent for a while, and for good reason. Besides experiencing symptoms of writer's block, I've also been playing around with a lot of new stuff (at least new to me), and no, it's not LINQ or any other stuff from Redmond this time.
One of the things I've been playing with is Dynamic Proxy and it's successor Dynamic Proxy 2 from the magnificent Castle stack.
Now, what are the problems that this library tries to solve? It tries to overcome the CLR's heavyweight proxy capabilities (extending MarshalByRefObject or ContextBoundObject) by providing lightweight proxies that can be generated on the fly for interfaces and classes (virtual properties and methods only). If this last sentence blows you away, don't worry. It's not that hard to understand.
I'm a big proponent of Persistence Ignorant (PI) domain models. Practically, this means that the assembly that contains my domain entities (also called POCO's) does not have any reference to other assemblies, except for the System assembly of the .NET Framework. The domain layer is the core of your application and it should be treated as such. You can compare it with the kernel of an operating system. It is the beating heart of ..., you get the picture.
This of course is easier said than done. You have to take some actions in order to accomplish PI domain models. Castle Dynamic Proxy can be used to simplify some of these actions and overcome some of the issues you come across while trying to achieve Persistence Ignorance. It's time for an example.
Let's say you have an entity in your domain model called Artist. An Artist can have a number of Records in his Repertoire.
public class Artist
{
private String _name;
private Repertoire _repertoire;
public String Name
{
get { return _name; }
set { _name = value; }
}
public Repertoire Repertoire
{
get { return _repertoire; }
set { _repertoire = value; }
}
}
public class Repertoire
{
private readonly Artist _artist;
private readonly List<Record> _records
= new List<Record>();
public Repertoire(Artist artist)
{
_artist = artist;
}
public Artist Artist
{
get { return _artist; }
}
public virtual IEnumerable<Record> Records
{
get { return _records; }
}
}
public class Record
{
private readonly String _title;
public Record(String title)
{
_title = title;
}
public String Title
{
get { return _title; }
}
}
This is the simplest domain I could come up with. In some scenarios, I want to use Artist information without retrieving the records from it's Repertoire. Other scenario's require that the records of the Repertoire are available.
One solution would be to change the Records property of the Repertoire class to directly retrieve the records from a database gateway when this property is accessed. This violates the PI principle explained earlier by polluting the domain with infrastructure concerns.
Let's see how Castle Dynamic Proxy can help us out here. First we implement an interceptor (implements the IInterceptor interface from the Castle.Core.Interceptor namespace).
public class LazyLoadInterceptor : IInterceptor
{
private List<Record> _loadedRecords;
public void Intercept(IInvocation invocation)
{
Repertoire repertoire =
(Repertoire)invocation.Proxy;
if(null == _loadedRecords)
{
// Some data access
_loadedRecords = new List<Record>();
_loadedRecords.Add(new Record("Die Sonne"));
_loadedRecords.Add(new Record("Mutter"));
_loadedRecords.Add(new Record("Mein Teil"));
Console.WriteLine("Repertoire of {0}",
repertoire.Artist.Name);
}
invocation.ReturnValue = _loadedRecords;
}
}
We need to make sure that the Records property of the Repertoire class is marked as virtual. Calls to the Records property are intercepted. If the records are not yet loaded, then they are retrieved from the database. This interceptor lives in the infrastructure or data access part of your application.
Next, we use this interceptor to intercept calls to the Records property.
public class ArtistRepository : IArtistRepository
{
public Artist FindBy(String name)
{
// Some data access
Artist artist = new Artist();
artist.Name = name;
ProxyGenerator proxyGenerator = new ProxyGenerator();
LazyLoadInterceptor lazyLoadInterceptor =
new LazyLoadInterceptor();
IInterceptor[] interceptors =
new IInterceptor[] { lazyLoadInterceptor };
Repertoire repertoire = (Repertoire)proxyGenerator
.CreateClassProxy(typeof(Repertoire),
interceptors,
artist);
artist.Repertoire = repertoire;
return artist;
}
}
Notice that the Repertoire class doesn't need to have a default constructor. It is possible to specify constructor arguments. You typically want to move this proxy setup code to some kind of a mapper class, but for the simplicity of this example this will do.
The following code results in the records to be retrieved only once, although the collection is accessed twice:
Artist artist = artistRepository.FindBy("Rammstein");
Console.WriteLine("Name: {0}", artist.Name);
foreach(Record record in artist.Repertoire.Records)
{
Console.WriteLine("Record: {0}", record.Title);
}
foreach(Record record in artist.Repertoire.Records)
{
Console.WriteLine("Record: {0}", record.Title);
}
Lazy loading is just one example where using proxies can be helpful. When you have a decent ORM at your disposal, you don't need to write this kind of code for lazy loading. In fact, NHibernate makes extensive use of Castle Dynamic Proxy to support lazy loading for you.
Other scenarios include cross-cutting concerns like dirty tracking, logging, tracing, etc. Interceptors also integrate nicely with Castle Windsor (what would you expect :-) ). This nicely written blog post explains how easy this is.
This example makes use of Dynamic Proxy 2. The first version of Castle Dynamic Proxy also supports mixins, which is not yet available for Dynamic Proxy 2 included with the Castle RC3 release. According to Hamilton Verissimo, Dynamic Proxy 2 is significantly more performant than it's first version.
If you, my dear reader want to know more about the use of dynamic proxies in your applications, than these articles and blog posts will provide you with some more information:
- Mats Helander has written a must read article about Aspects of Domain Model Management. Highly recommended.
- Castle's DynamicProxy for .NET (covers Dynamic Proxy V1, but it's still a useful article.)
- Explicit Strongly Typed Selective Proxies
- Explicit Strongly Typed Selective Proxies - Part 2
Till next time.
If you and your team want to learn more about how to write maintainable unit tests and get the most out of TDD practices, make sure to have look at our trainings and workshops or check out the books section. Feel free to reach out at info. @ principal-it .be
Jan Van Ryswyck
Thank you for visiting my blog. I’m a professional software developer since Y2K. A blogger since Y2K+5. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.
Comments
Writing Maintainable
Unit Tests
Watch The Videos
Latest articles
-
Contract Tests - Parameterised Test Cases
June 28, 2023
-
Contract Tests - Abstract Test Cases
April 12, 2023
-
Contract Tests
February 1, 2023
-
The Testing Quadrant
June 15, 2022
-
Tales Of TDD: The Big Refactoring
February 2, 2022
Tags
- .NET
- ALT.NET
- ASP.NET
- Agile
- Announcement
- Architecture
- Behavior-Driven Development
- C++
- CQRS
- Clojure
- CoffeeScript
- Community
- Concurrent Programming
- Conferences
- Continuous Integration
- Core Skills
- CouchDB
- Database
- Design Patterns
- Domain-Driven Design
- Event Sourcing
- F#
- Fluent Interfaces
- Functional Programming
- Hacking
- Humor
- Java
- JavaScript
- Linux
- Microsoft
- NHibernate
- NoSQL
- Node.js
- Object-Relational Mapping
- Open Source
- Reading
- Ruby
- Software Design
- SourceControl
- Test-Driven Development
- Testing
- Tools
- Visual Studio
- Web
- Windows
Disclaimer
The opinions expressed on this blog are my own personal opinions. These do NOT represent anyone else’s view on the world in any way whatsoever.
About
Thank you for visiting my website. I’m a professional software developer since Y2K. A blogger since Y2K+5. Author of Writing Maintainable Unit Tests. Provider of training and coaching in XP practices. Curator of the Awesome Talks list. Thinking and learning about all kinds of technologies since forever.
Latest articles
Contract Tests - Parameterised Test Cases
Contract Tests - Abstract Test Cases
Contract Tests
The Testing Quadrant
Contact information
(+32) 496 38 00 82
info @ principal-it .be