While I’ve understood Dynamic Proxies, Interception, and AOP conceptually and used them in personal projects, my first production-level encounter was last year. We utilized Unity’s interception features for seemingly minor tasks. Despite achieving the desired outcome, some aspects remained unclear, partly due to time constraints that rushed my reading of Unity’s documentation.
Dino Esposito’s insightful series [[1, 2 and 3] prompted me to revisit and clarify this experience.
It’s crucial to differentiate between AOP and Dependency Injection. However, most modern IoC containers, including Spring.Net, Castle Windsor, and Unity, offer rudimentary AOP support, primarily for intercepting method calls to add aspects like logging, validation, or security.
This runtime method interception is achieved through Proxy Objects, which either reference the intercepted instance (composition) or inherit from the intercepted class. Although this concept is shared among Spring, Castle, and Unity, some aspects of Unity can be confusing:
- Unity 2.0 operates independently from Enterprise Library, connected only by their shared developer: Patterns and Practices. Using Unity’s lightweight AOP only requires adding these assemblies:
- Microsoft.Practices.ServiceLocation
- Microsoft.Practices.Unity
- Microsoft.Practices.UnityInterception
- Unity prefers “Interceptor” over “Proxy.” While it lacks a “ProxyGenerator” class like Castle, the “Intercept” class fulfills the proxy creation role.
- Unity implements interception through a chain of IInterceptionBehavior objects, each encapsulating injected logic. This is analogous to Castle’s IInterceptor.
Unity provides two Composition-based proxy types (Instance Interceptor) for wrapping existing object instances: InterfaceInterceptor and TransparentProxyInterceptor. Additionally, it offers one Inheritance-based proxy type (Type Interceptor): VirtualMethodInterceptor.
Creating and using proxies without an IoC container is possible, but for decoupled and extensible production applications, container-based creation is recommended.
Let’s illustrate with examples inspired by last year’s project. Imagine needing to mock a Data Source. The goal is to serialize Data Entities from real DAOs and subsequently use those serialized versions instead of querying the real DAOs or Data Source.
Injecting a serialization behavior into the real DAOs can be achieved by wrapping them in a Proxy. This Proxy would first delegate to the real DAO to retrieve entities (e.g., from a database) and then serialize them before returning to the unaware caller.
We can manually create this Proxy (using an InterfaceInterceptor, a Composition-based approach):
| |
For decoupling, we’d employ an IoC container, register the DAO type, and resolve it to get the proxied instance:
| |
A more intriguing challenge arose when we needed a MockDao to deserialize previously saved entities. Creating dedicated MockDao classes seemed redundant since the desired behavior (finding, deserializing, and returning entities from disk) could be entirely handled by the interception logic (IInterceptionBehavior). We wanted Unity to dynamically generate a Proxy implementing the required I___Dao interface and incorporating the deserialization behavior. However, Intercept.ThroughProxy necessitates an instance of the intercepted class, implying the need for a MockDao class. Inheritance-based proxies posed the same issue, inheriting from the nonexistent MockDao.
This limitation was surprising, as I had previously achieved the intended behavior with Castle Proxies using CreateInterfaceProxyWithoutTarget:
Proxy without target. This one is tricky. You don’t supply target implementation for the interface. Dynamic Proxy generates it for you at runtime, using interceptors to provide behavior for its methods.
Under project constraints, I didn’t delve into a Unity equivalent and resorted to Castle. However, this unresolved question lingered until recently.
Upon researching, I found two similar queries about the Unity equivalent of Castle’s CreateInterfaceProxyWithoutTarget: [1] and [2]. A (flawed) response to the second question pointed me in the right direction: utilize NewInstaceWithAdditionalInterfaces and casting:
| |
container.AddNewExtension(); container.RegisterType(new InjectionFactory(c => { return Intercept.NewInstanceWithAdditionalInterfaces%lt;Object>( new VirtualMethodInterceptor(), new List() { new RetrieveSavedResultBehavior() }, new List() { typeof(IUserDao) } ); }));
IUserDao userDao = container.Resolve();
| |