views:

379

answers:

2

I was asked to implement castle dynamic proxy in my asp.net web application and i was going through couple of articles which i got from Castle Project and Code Project about castle dynamic proxy in asp.net web application....

Both articles delt with creating interceptors but i can't get the idea why interceptors are used with classes.... Why should i intercept my class which is behaving properly?

+2  A: 

The reason you would use Castle-DynamicProxy is for what's called Aspect Orientated Programming. It lets you interject code into the standard operation flow of your code without the need to become dependent on the code itself.

A simple example is as always, logging. That you would create a DynamicProxy around a class that you have errors from that it logs the data going into the method and catches any exceptions and then logs the exception.

Using the intercepter your current code has no idea it exists (assuming you have your software built in a decoupled way with interfaces correctly) and you can change the registration of your classes with an inversion of control container to use the proxied class instead without having to change a single line else where in code. Then when you solve the bug you can turn off the proxying.

More advanced usage of proxying can be seen with NHibernate where all of the lazy loading is handled through proxies.

Chris Marisic
+7  A: 

Let's say that your class needs to do 3 things for a certain operation:

  1. Perform a security check;
  2. Log the method call;
  3. Cache the result.

Let's further assume that your class doesn't know anything about the specific way you've configured your security, logging, or caching. You need to depend on abstractions of these things.

There are a few ways to go about it. One way would be to set up a bunch of interfaces and use constructor injection:

public class OrderService : IOrderService
{
    private readonly IAuthorizationService auth;
    private readonly ILogger logger;
    private readonly ICache cache;

    public OrderService(IAuthorizationService auth, ILogger logger,
        ICache cache)
    {
        if (auth == null)
            throw new ArgumentNullException("auth");
        if (logger == null)
            throw new ArgumentNullException("logger");
        if (cache == null)
            throw new ArgumentNullException("cache");
        this.auth = auth;
        this.logger = logger;
        this.cache = cache;
    }

    public Order GetOrder(int orderID)
    {
        auth.AssertPermission("GetOrder");
        logger.LogInfo("GetOrder:{0}", orderID);
        string cacheKey = string.Format("GetOrder-{0}", orderID);
        if (cache.Contains(cacheKey))
            return (Order)cache[cacheKey];
        Order order = LookupOrderInDatabase(orderID);
        cache[cacheKey] = order;
        return order;
    }
}

This isn't horrible code, but think of the problems we're introducing:

  • The OrderService class can't function without all three dependencies. If we want to make it so it can, we need to start peppering the code with null checks everywhere.

  • We're writing a ton of extra code to perform a relatively simple operation (looking up an order).

  • All this boilerplate code has to be repeated in every method, making for a very large, ugly, bug-prone implementation.

Here's a class which is much easier to maintain:

public class OrderService : IOrderService
{
    [Authorize]
    [Log]
    [Cache("GetOrder-{0}")]
    public virtual Order GetOrder(int orderID)
    {
        return LookupOrderInDatabase(orderID);
    }
}

In Aspect Oriented Programming, these attributes are called Join Points, the complete set of which is called a Point Cut.

Instead of actually writing dependency code, over and over again, we leave "hints" that some additional operations are supposed to be performed for this method.

Of course, these attributes have to get turned into code sometime, but you can defer that all the way up to your main application code, by creating a proxy for the OrderService (note that the GetOrder method has been made virtual because it needs to be overridden for the service), and intercepting the GetOrder method.

Writing the interceptor might be as simple as this:

public class LoggingInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        if (Attribute.IsDefined(invocation.Method, typeof(LogAttribute))
        {
            Console.Writeline("Method called: "+ invocation.Method.Name);
        }
        invocation.Proceed();
    }
}

And creating the proxy would be:

var generator = new ProxyGenerator();
var orderService = (IOrderService)generator.CreateClassProxy(typeof(OrderService),
    new LoggingInterceptor());

This is not only a lot less repetitive code, but it completely removes the actual dependency, because look what we've done - we don't even have an authorization or caching system yet, but the system still runs. We can just insert the authorization and caching logic later by registering another interceptor and checking for AuthorizeAttribute or CacheAttribute.

Hopefully this explains the "why."

Sidebar: As Krzysztof Koźmic comments, it's not a DP "best practice" to use a dynamic interceptor like this. In production code, you don't want to have the interceptor running for unnecessary methods, so use an IInterceptorSelector instead.

Aaronaught
you pretty much got it. On a technical note, I would move the checking "are we in correct method" into interceptor selector (an `IInterceptorSelector` implementation)
Krzysztof Koźmic
@Krzysztof Koźmic: It was your blog that got me started on DP so I'm glad you approve! And I'm inclined to agree on the `IInterceptorSelector` preference, I mainly excluded it here in order to make this very basic example more palatable to those unfamiliar with DP.
Aaronaught
Random question for the caching of the attribute usage reading what exactly is considered best practice for capturing enough that guarantees uniqueness?
Chris Marisic
@Chris: When you say "caching of the attribute usage reading", do you mean how exactly is the caching system/interceptor implemented? That's actually a rather long story that originated here: http://stackoverflow.com/questions/2330275/thread-safe-cache-libraries-for-net. The end result was an entire library of some 20-odd classes. The way I'm using it, the `CacheAttribute` either takes a format string (which is applied to the parameters) or a method name (for more complex key generation). It's up to the class itself to define sufficiently unique keys for each cached method.
Aaronaught
Oh, forgot to mention, the caching interceptor uses the fully-qualified type name as part of the key, so keys only need to be unique within the scope of each class. That's probably a good "best practice", it's similar to how ASP.NET handles script registration.
Aaronaught