IT:AD:Unity:HowTo:Interception
Summary
Process
See: http://msdn.microsoft.com/en-us/library/ff650639.aspx
The basics are expressed here (several concepts at once…you'll have to trawl through the different approachs I was exploring):
using System;
using System.Linq;
using Microsoft.Practices.Unity;
namespace XAct.Spikes.UnityInterception
{
using System.Reflection;
using System.Security.Principal;
using Microsoft.Practices.Unity.InterceptionExtension;
using XAct.Environment;
using XAct.Services;
class Program
{
static void Main(string[] args)
{
XAct.Services.IoC.UnityBootstrapper.Initialize();
Microsoft.Practices.Unity.UnityContainer c;
Microsoft.Practices.Unity.IUnityContainer unityContainer =
XAct.Library.Initialization.Status.BindingResults.DependencyInjectionContainer
as Microsoft.Practices.Unity.IUnityContainer;
unityContainer.AddNewExtension<Interception>();
unityContainer.Configure<Interception>()
.AddPolicy("TheNameYouLike")
.AddMatchingRule(new MyRule())
.AddCallHandler(new BetterAuthenticationHandler());
unityContainer.Configure<Interception>().SetInterceptorFor<ISomeService>(new InterfaceInterceptor());
var someService = XAct.Shortcuts.ServiceLocate<ISomeService>();
someService.DoSomething();
//These two are decorated with a naive implementation of roles
//Wouldn't do it this way:
someService.DoSomethingTricky1();
someService.DoSomethingTricky2();
//These are decorated with a much better solution:
someService.DoSomethingTricky3();
someService.DoSomethingTricky4();
}
}
public interface ISomeService
{
void DoSomething();
void DoSomethingTricky1();
void DoSomethingTricky2();
void DoSomethingTricky3();
void DoSomethingTricky4();
}
[DefaultBindingImplementation(typeof(ISomeService))]
public class SomeService:ISomeService
{
[MyNonPollutingUpAttribute]
public virtual void DoSomething()
{
Console.WriteLine("DoSomething...");
}
[LogExceptions]
[AuthenticationByAOP(Roles = "BABA")]
public virtual void DoSomethingTricky1()
{
Console.WriteLine("DoSomethingTricky...");
}
[AuthenticationByAOP(Roles="ABC")]
public virtual void DoSomethingTricky2()
{
Console.WriteLine("DoSomethingTricky...");
}
//OLD WAY OF DOING IT, BUT IT POLUTES THE STACK WITH A UNITY REFRENCE:[BetterAuthenticationByAOP]
public virtual void DoSomethingTricky3()
{
Console.WriteLine("DoSomethingTricky...");
}
//OLD WAY OF DOING IT, BUT IT POLUTES THE STACK WITH A UNITY REFRENCE:[BetterAuthenticationByAOP]
public virtual void DoSomethingTricky4()
{
Console.WriteLine("DoSomethingTricky...");
}
}
public interface IAuthorisationByMethodService
{
bool AuthenticatePrincipalByMethod(string fullMethodName);
bool AuthenticatePrincipalByMethod(MethodInfo methodInfo);
}
[DefaultBindingImplementation(typeof(IAuthorisationByMethodService))]
public class AuthorisationByMethodService : IAuthorisationByMethodService
{
private readonly IEnvironmentService environmentService;
public AuthorisationByMethodService(IEnvironmentService environmentService)
{
this.environmentService = environmentService;
}
public bool AuthenticatePrincipalByMethod(MethodInfo methodInfo)
{
string className = methodInfo.ReflectedType.FullName;
string methodName = methodInfo.Name;
String fullMethodName = "{0}.{1}".FormatStringInvariantCulture(className, methodName);
return this.AuthenticatePrincipalByMethod(fullMethodName);
}
public bool AuthenticatePrincipalByMethod(string fullMethodName)
{
Console.WriteLine("Looking in db or cache or for intersection between MethodName and current Principal Roles");
Console.WriteLine("...for {0}", fullMethodName);
return true;
}
}
//define what it is you want to do with your custom interceptor
public class LogExceptionsHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{ //Put any logic here you would like to invoke BEFORE the method is invoked.
Console.WriteLine("Before method Invocation happened");
//This invokes the next item in the Injection pipeline, or eventually
//calls your method
var methodReturn = getNext().Invoke(input, getNext);
// AFTER the target method execution check to see if it excepted
if (methodReturn.Exception != null)
{
Console.WriteLine("Add some real logging here");
}
//if you would like to re-throw, do it here, otherwise just return
//your methodReturn
else
{
Console.WriteLine
("To Rethrow, or not to rethrow, that is the question.");
}
return methodReturn;
}
}
public class AuthenticationHandler : ICallHandler
{
public AuthenticationHandler()
{
}
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
//This will return the Attributes applied to the INterface (not the Instance)
AuthenticationByAOPAttribute entryAttrib = input.MethodBase.GetAttribute<AuthenticationByAOPAttribute>(false);
//To Get to attributes applied to the actual Instance method would require even more expensive Reflection.
if (entryAttrib != null)
{
IPrincipal principal = System.Threading.Thread.CurrentPrincipal;
string roleNames = entryAttrib.Roles;
if (!roleNames.IsNullOrEmpty())
{
if (roleNames.Split().First(principal.IsInRole).IsNullOrEmpty())
{
//Not good...
Console.WriteLine("Not in role...");
}
}
}
////service.Trace.AppendLine(entryAttrib.Message);
//Put any logic here you would like to invoke BEFORE the method is invoked.
Console.WriteLine("Before method Invocation happened");
//This invokes the next item in the Injection pipeline, or eventually
//calls your method
var methodReturn = getNext().Invoke(input, getNext);
return methodReturn;
}
}
public class BetterAuthenticationHandler : ICallHandler
{
public BetterAuthenticationHandler()
{
}
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
IAuthorisationByMethodService authorisationByMethodService=
XAct.Services.ServiceLocatorService.Current.GetInstance<IAuthorisationByMethodService>();
MethodInfo methodInfo = (MethodInfo) input.MethodBase;
bool result = authorisationByMethodService.AuthenticatePrincipalByMethod(methodInfo);
Console.Write("Checking in db...Answer: sure!");
////service.Trace.AppendLine(entryAttrib.Message);
//Put any logic here you would like to invoke BEFORE the method is invoked.
Console.WriteLine("Before method Invocation happened");
//This invokes the next item in the Injection pipeline, or eventually
//calls your method
var methodReturn = getNext().Invoke(input, getNext);
return methodReturn;
}
}
//create an attribute so you can apply it to your methods
public class LogExceptionsAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)
{
return new LogExceptionsHandler();
}
}
public class AuthenticationByAOPAttribute : HandlerAttribute
{
public string Roles { get; set; }
public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)
{
return new AuthenticationHandler();
}
}
public class BetterAuthenticationByAOPAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)
{
return new BetterAuthenticationHandler();
}
}
public class MyRule : IMatchingRule
{
public bool Matches(MethodBase member)
{
if (member.GetCustomAttribute<MyNonPollutingUpAttribute>() != null)
{
return true;
}
return member.Name.StartsWith("DoSomethingTricky");
}
}
public class MyNonPollutingUpAttribute :Attribute
{
//Prefer to use an app specific (or atleast corp specific) Attribute
//throughout your Application Facade, rather than use one that
//mentions Unity.
}
}
Raising Exceptions
Resources
- Alternate way of attaching:


