Advertisement
Guest User

AnalyticsRouteTable

a guest
May 5th, 2011
402
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.54 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Reflection;
  7. using System.Web;
  8. using System.Web.Mvc;
  9. using System.Web.Routing;
  10.  
  11. namespace Funda.Web.FundaMobiel.Helpers
  12. {
  13.     public class AnalyticsRouteTable
  14.     {
  15.         public AnalyticsRouteTable()
  16.         {
  17.             Routes = new Dictionary<Func<RouteData, bool>, string>();
  18.         }
  19.  
  20.         public Dictionary<Func<RouteData, bool>, string> Routes { get; set; }
  21.  
  22.         public void Add<T>(Expression<Action<T>> expectation, string tag)
  23.         {
  24.             Routes.Add(AnalyticsHelper.CompileRule<T>(expectation), tag);
  25.         }
  26.     }
  27.  
  28.     public static class AnalyticsHelper
  29.     {
  30.         private static object _lock = new object();
  31.         public static void Initialize(AnalyticsRouteTable routeTable)
  32.         {
  33.             lock(_lock)
  34.             {
  35.                 _routes = routeTable.Routes;
  36.             }
  37.         }
  38.  
  39.         private static Dictionary<Func<RouteData, bool>, string> _routes = new Dictionary<Func<RouteData, bool>, string>();
  40.  
  41.         /// <summary>
  42.         /// Compiles a given rule into a delegate
  43.         /// </summary>
  44.         /// <typeparam name="TController">Controller-type</typeparam>
  45.         /// <param name="expectation">Action on the controller</param>
  46.         /// <returns></returns>
  47.         internal static Func<RouteData, bool> CompileRule<TController>(Expression<Action<TController>> expectation)
  48.         {
  49.             // bijhouden van een lijst met expectation
  50.             Dictionary<string, object> expects = new Dictionary<string, object>();
  51.             // lijst met de calls naar 'MatchesRouteData'
  52.             List<MethodCallExpression> methodCalls = new List<MethodCallExpression>();
  53.  
  54.             // eerste argument van de delegate die we maken
  55.             ParameterExpression parameterExpression = Expression.Parameter(typeof(RouteData), "rd");
  56.  
  57.             // controller & action uitlezen vanuit de expectation
  58.             expects.Add("Controller", expectation.Parameters[0].Type.Name.Replace("Controller", ""));
  59.  
  60.             expects.Add("Action", ((MethodCallExpression)expectation.Body).Method.Name);
  61.  
  62.             // alle parameters die zijn meegegeven aan de actie aflopen
  63.             var parameters = ((MethodCallExpression)expectation.Body).Method.GetParameters();
  64.             for (var ix = 0; ix < parameters.Length; ix++)
  65.             {
  66.                 // parameterinfo voor het type & de ingevoerde waarde
  67.                 var methodParam = parameters[ix];
  68.                 var expression = ((MethodCallExpression) expectation.Body).Arguments[ix];
  69.  
  70.                 object value;
  71.  
  72.                 // een MemberExpression moeten we even de waarde ophalen die deze referenced
  73.                 if(expression is MemberExpression)
  74.                 {
  75.                     value = Expression.Lambda(expression).Compile().DynamicInvoke();
  76.                 }
  77.                 // Constant is lekker simpel:
  78.                 else if (expression is ConstantExpression)
  79.                 {
  80.                     value = ((ConstantExpression) expression).Value;
  81.                 }
  82.                 // Aan andere waardes doen we voorlopig niet
  83.                 else
  84.                 {
  85.                     continue;
  86.                 }
  87.  
  88.                 // null? dan negeren we deze
  89.                 if (!methodParam.ParameterType.IsValueType && value == null)
  90.                 {
  91.                     continue;
  92.                 }
  93.                 // ben je geen reference type?
  94.                 else if (methodParam.ParameterType.IsValueType
  95.                          && !methodParam.ParameterType.IsEnum)
  96.                 {
  97.                     // generic en geen reference? dan ben je Nullable<>
  98.                     if (methodParam.ParameterType.IsGenericType)
  99.                     {
  100.                         // als value == null, dan negeren
  101.                         if (Activator.CreateInstance(methodParam.ParameterType) == value)
  102.                             continue;
  103.                     }
  104.                     // anders: als waarde de default waarde van het type is, negeren (voor long is dit dus 0)
  105.                     else if (Activator.CreateInstance(methodParam.ParameterType).Equals(value))
  106.                     {
  107.                         continue;
  108.                     }
  109.                 }
  110.  
  111.                 // voeg toe aan de lijst met expectations
  112.                 expects.Add(methodParam.Name, value);
  113.             }
  114.  
  115.             // omzetten van expectation -> method call naar MatchesRouteData
  116.             foreach (var expect in expects)
  117.             {
  118.                 methodCalls.Add(Expression.Call(typeof(AnalyticsHelper).GetMethod("MatchesRouteData", BindingFlags.Static | BindingFlags.NonPublic),
  119.                                                 parameterExpression,
  120.                                                 Expression.Constant(expect.Key),
  121.                                                 // we moeten expliciet omzetten naar object; normaal gaat dit impliciet, maar niet in een expression tree
  122.                                                 Expression.Convert(Expression.Constant(expect.Value), typeof(object)),
  123.                                                 Expression.Constant(expect.Value.GetType())));
  124.             }
  125.  
  126.             // voeg alles samen
  127.             BinaryExpression wholeExpression = null;
  128.             foreach (var call in methodCalls)
  129.             {
  130.                 if (wholeExpression == null)
  131.                 {
  132.                     wholeExpression = Expression.MakeBinary(ExpressionType.AndAlso, Expression.Constant(true), call);
  133.                     continue;
  134.                 }
  135.  
  136.                 // we gebruiken AndAlso
  137.                 wholeExpression = Expression.MakeBinary(ExpressionType.AndAlso, wholeExpression, call);
  138.             }
  139.  
  140.             // de delegate wordt nu:
  141.             // routeData => MatchesRouteData(...) && MatchesRouteData(...) && MatchesRouteData(...)
  142.             // hetzelfde als je zelf een lambda hiervoor zou schrijven
  143.             var del = (Func<RouteData, bool>)Expression.Lambda(wholeExpression, parameterExpression).Compile();
  144.  
  145.             return del;
  146.         }
  147.  
  148.         public static string GetTag(RouteData routeData)
  149.         {
  150.             var val = _routes.Where(d => d.Key.Invoke(routeData));
  151.  
  152.             if (!val.Any()) return "unknown";
  153.  
  154.             return "/" + val.First().Value;
  155.         }
  156.  
  157.         /// <summary>
  158.         /// Validates whether the given key in routeData is equal to the given value
  159.         /// </summary>
  160.         /// <param name="routeData">Full set of routedata</param>
  161.         /// <param name="key">Parameter name</param>
  162.         /// <param name="value">Expected value</param>
  163.         /// <param name="type">The full type, for modelbinder</param>
  164.         /// <returns></returns>
  165.         private static bool MatchesRouteData(RouteData routeData, string key, object value, Type type)
  166.         {
  167.             object outValue;
  168.             if (routeData.Values.TryGetValue(key, out outValue))
  169.             {
  170.                 // langs smartbinder halen
  171.                 if (ModelBinders.Binders.DefaultBinder != null)
  172.                 {
  173.                     outValue = ModelBinders.Binders.DefaultBinder.BindModel(GetControllerContext(), GetModelBindingContext(key, outValue, type));
  174.                 }
  175.  
  176.                 if (outValue != null && outValue.Equals(value))
  177.                 {
  178.                     return true;
  179.                 }
  180.  
  181.                 if(outValue != null && outValue.ToString().Equals(value.ToString(), StringComparison.OrdinalIgnoreCase))
  182.                 {
  183.                     return true;
  184.                 }
  185.             }
  186.  
  187.             return false;
  188.         }
  189.  
  190.         private static ControllerContext GetControllerContext()
  191.         {
  192.             return new ControllerContext();
  193.         }
  194.  
  195.         private static ModelBindingContext GetModelBindingContext(string id, object value, Type type)
  196.         {
  197.             ValueProviderResult valueProviderResult = new ValueProviderResult(value, value.ToString(), new CultureInfo("nl-NL"));
  198.  
  199.             ValueProviderDictionary dictionary = new ValueProviderDictionary(null)
  200.                 {
  201.                     { id, valueProviderResult }
  202.                 };
  203.  
  204.             return new ModelBindingContext
  205.                 {
  206.                     ModelName = id,
  207.                     ValueProvider = dictionary,
  208.                     ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, type)
  209.                 };
  210.         }
  211.     }
  212. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement