- Analyze the implementation performance
- Authorize using
- Log access
With use cases implemented by business class methods, it is a interesting way intercept the calls of these methods and apply these strategies.
How to intercept methods:
The instance of business should be created through a DynamicProxy.
The interceptable methods must be virtual, so that the proxy can override it.
Installs Castle.Core the project, obtained via NuGet, which provides a great API to intercept methods.
This recipe is for properties as well.
Below there is a simple application which implements the idea.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace InterceptingApp
{
using Castle.DynamicProxy;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var user = new User { Login = "It's me" };
var allowedMethods = new List<MemberInfo>
{
typeof(MyBusiness).GetMethod("GetProducts")
};
var performanceInterceptor = new PerformanceInterceptor();
var authorizeInterceptor = new AuthorizeInterceptor(allowedMethods);
var logInterceptor = new LogInterceptor(user);
var generator = new ProxyGenerator(new PersistentProxyBuilder());
var business = generator.CreateClassProxy<MyBusiness>(performanceInterceptor, authorizeInterceptor, logInterceptor);
try
{
// This call was allowed, so it should works just fine
Console.WriteLine("Products:");
foreach (var product in business.GetProducts())
{
Console.WriteLine("Product name: {0} price: {1:c}", product.Name, product.Price);
}
// This call was not allowed, so it should throw an exception
Console.WriteLine("BestSellers:");
foreach (var product in business.GetBestSellers())
{
Console.WriteLine("Product name: {0} price: {1:c}", product.Name, product.Price);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public class MyBusiness
{
public virtual IEnumerable<Product> GetProducts()
{
System.Threading.Thread.Sleep(100);
return new List<Product>
{
new Product { Name = "Beer", Price = 1.80M },
new Product { Name = "Soda", Price = 1.50M },
new Product { Name = "Juice", Price = 2.15M }
};
}
public virtual IEnumerable<Product> GetBestSellers()
{
System.Threading.Thread.Sleep(100);
return new List<Product>
{
new Product { Name = "Juice", Price = 2.15M }
};
}
}
public class User
{
public string Login { get; set; }
}
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
}
class PerformanceInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var start = DateTime.Now;
try
{
invocation.Proceed();
}
catch
{
throw;
}
finally
{
var end = DateTime.Now;
Console.WriteLine("[Performance]: Method {0}.{1} takes {2}",
invocation.Method.DeclaringType.Name,
invocation.Method.Name,
end - start);
}
}
}
class AuthorizeInterceptor : IInterceptor
{
IEnumerable<MemberInfo> _allowedMethods;
public AuthorizeInterceptor(IEnumerable<MemberInfo> allowedMethods) { _allowedMethods = allowedMethods; }
public void Intercept(IInvocation invocation)
{
if (_allowedMethods.Contains(invocation.Method))
{
Console.WriteLine("[Authorize]: Granted! You are allowed to access this method");
invocation.Proceed();
}
else
{
throw new Exception("[Authorize]: Denied! You are not allowed to access this method.");
}
}
}
class LogInterceptor : IInterceptor
{
User _user;
public LogInterceptor(User user) { _user = user; }
public void Intercept(IInvocation invocation)
{
Console.WriteLine("[Log]: Method {0}.{1} was called by '{2}' at {3}",
invocation.Method.DeclaringType.Name,
invocation.Method.Name,
_user.Login,
DateTime.Now);
invocation.Proceed();
}
}
}