# IT:AD:Unity:HowTo:Interception # * [[../|(UP)]] {{indexmenu>.#2|nsort tsort}} * See also: [[IT/AD/Cujo.JS/]] Why? * [[IT/AD/Design/patterns_security_is_an_application_concern/]] ![](https://dl.dropboxusercontent.com/u/11851202/Posted/IT/About/Unity/Interjection.png) ![](https://dl.dropboxusercontent.com/u/11851202/Posted/IT/About/Unity/Interjection2.png) ![](https://dl.dropboxusercontent.com/u/11851202/Posted/IT/About/Unity/Interjection3.png) ## 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(); unityContainer.Configure() .AddPolicy("TheNameYouLike") .AddMatchingRule(new MyRule()) .AddCallHandler(new BetterAuthenticationHandler()); unityContainer.Configure().SetInterceptorFor(new InterfaceInterceptor()); var someService = XAct.Shortcuts.ServiceLocate(); 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(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(); 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() != 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 ### See: [[IT/AD/Unity/HowTo/Interception/Raising Exceptions]] ## Resources ## * See: http://msdn.microsoft.com/en-us/library/ff647107.aspx * http://msdn.microsoft.com/en-us/magazine/gg535676.aspx * http://www.codeproject.com/Articles/565108/Unity-Interceptor-for-Performance-Instrumentation * Nuget: https://nuget.org/packages/Unity.Interception/2.1.505.2 * Alternate way of attaching: * http://www.orbifold.net/default/the-bare-bones-of-unity-interceptions/ * http://weblogs.asp.net/ricardoperes/archive/2013/04/28/unity-part-3-aspect-oriented-programming.aspx