quarta-feira, 20 de junho de 2012

Logging, Authorizing and Performance analysis on method calls

Intercepting method calls in order to:

  - 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();
        }
    }
}


Nenhum comentário:

Postar um comentário

Feel free to comment on the immoderately.