1: /// <summary>
2: /// Generates routevalues and controller and action strings from a strong typed lambda expression of a controllermethod.
3: /// </summary>
4: /// <typeparam name="T">Must be a Controller</typeparam>
5: /// <param name="routeValues">Can be null or empty, but you can supply extra routevalues these win if generated values overlap</param>
6: /// <param name="actionSelector">a lambda expression, must be a call to a ActionResult returning method</param>
7: /// <param name="controller">the name of the controller</param>
8: /// <param name="action">the name of the action</param>
9: /// <returns></returns>
10: public static RouteValueDictionary GetRouteValues<T>(
11: RouteValueDictionary routeValues,
12: Expression<Func<T, ActionResult>> actionSelector,
13: out string controller,
14: out string action)
15: {
16: Type controllerType = typeof(T);
17: if (routeValues == null)
18: {
19: routeValues = new RouteValueDictionary();
20: }
21:
22: //The body of the expression must be a call to a method
23: MethodCallExpression call = actionSelector.Body as MethodCallExpression;
24: if (call == null)
25: {
26: throw new ArgumentException("You must call a method of " + controllerType.Name, "actionSelector");
27: }
28:
29: //the object being called must be the controller specified in <T>
30: if (call.Object.Type != controllerType)
31: {
32: throw new ArgumentException("You must call a method of " + controllerType.Name, "actionSelector");
33: }
34:
35: //Remove the controller part of the name ProductController --> Product
36: if (controllerType.Name.EndsWith("Controller"))
37: {
38: controller = controllerType.Name.Substring(0, controllerType.Name.Length - "Controller".Length);
39: }
40: else
41: {
42: controller = controllerType.Name;
43: }
44: //The action is the name of the method being called
45: action = call.Method.Name;
46:
47: //get all arguments from the lambda expression
48: var args = call.Arguments;
49:
50: //Get all parameters from the Action Method
51: ParameterInfo[] parameters = call.Method.GetParameters();
52:
53: //pair the lambda arguments with the param names
54: var pairs = args.Select((a, i) => new
55: {
56: Argument = a,
57: ParamName = parameters[i].Name
58: });
59:
60:
61: foreach (var argumentParameterPair in pairs)
62: {
63: string name = argumentParameterPair.ParamName;
64: if (!routeValues.ContainsKey(name))
65: {
66: //the argument could be a constant or a variable or a function and must be evaluated
67: object value;
68: //If it is a constant we can get the value immediately
69: if (argumentParameterPair.Argument.NodeType == ExpressionType.Constant)
70: {
71: var constant = argumentParameterPair.Argument as ConstantExpression;
72: value = constant.Value;
73: }
74: else //if not we have to evaluate the value
75: {
76:
77: value = Expression.Lambda(argumentParameterPair.Argument).Compile().DynamicInvoke(null);
78: }
79: if (value != null)
80: {
81: //add routevalues with the name = method parameter name (productSlug) and value = the evaluated lambda value
82: routeValues.Add(name, value);
83: }
84: }
85: }
86:
87: return routeValues;
88: }