New tests.
[mono.git] / mcs / class / System.Web.Mvc2 / System.Web.Mvc / ActionMethodDispatcher.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. All rights reserved.\r
4  *\r
5  * This software is subject to the Microsoft Public License (Ms-PL). \r
6  * A copy of the license can be found in the license.htm file included \r
7  * in this distribution.\r
8  *\r
9  * You must not remove this notice, or any other, from this software.\r
10  *\r
11  * ***************************************************************************/\r
12 \r
13 namespace System.Web.Mvc {\r
14     using System;\r
15     using System.Collections.Generic;\r
16     using System.Linq.Expressions;\r
17     using System.Reflection;\r
18 \r
19     // The methods in this class don't perform error checking; that is the responsibility of the\r
20     // caller.\r
21     internal sealed class ActionMethodDispatcher {\r
22 \r
23         private delegate object ActionExecutor(ControllerBase controller, object[] parameters);\r
24         private delegate void VoidActionExecutor(ControllerBase controller, object[] parameters);\r
25 \r
26         private ActionExecutor _executor;\r
27 \r
28         public ActionMethodDispatcher(MethodInfo methodInfo) {\r
29             _executor = GetExecutor(methodInfo);\r
30             MethodInfo = methodInfo;\r
31         }\r
32 \r
33         public MethodInfo MethodInfo {\r
34             get;\r
35             private set;\r
36         }\r
37 \r
38         public object Execute(ControllerBase controller, object[] parameters) {\r
39             return _executor(controller, parameters);\r
40         }\r
41 \r
42         private static ActionExecutor GetExecutor(MethodInfo methodInfo) {\r
43             // Parameters to executor\r
44             ParameterExpression controllerParameter = Expression.Parameter(typeof(ControllerBase), "controller");\r
45             ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");\r
46 \r
47             // Build parameter list\r
48             List<Expression> parameters = new List<Expression>();\r
49             ParameterInfo[] paramInfos = methodInfo.GetParameters();\r
50             for (int i = 0; i < paramInfos.Length; i++) {\r
51                 ParameterInfo paramInfo = paramInfos[i];\r
52                 BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));\r
53                 UnaryExpression valueCast = Expression.Convert(valueObj, paramInfo.ParameterType);\r
54 \r
55                 // valueCast is "(Ti) parameters[i]"\r
56                 parameters.Add(valueCast);\r
57             }\r
58 \r
59             // Call method\r
60             UnaryExpression instanceCast = (!methodInfo.IsStatic) ? Expression.Convert(controllerParameter, methodInfo.ReflectedType) : null;\r
61             MethodCallExpression methodCall = methodCall = Expression.Call(instanceCast, methodInfo, parameters);\r
62 \r
63             // methodCall is "((TController) controller) method((T0) parameters[0], (T1) parameters[1], ...)"\r
64             // Create function\r
65             if (methodCall.Type == typeof(void)) {\r
66                 Expression<VoidActionExecutor> lambda = Expression.Lambda<VoidActionExecutor>(methodCall, controllerParameter, parametersParameter);\r
67                 VoidActionExecutor voidExecutor = lambda.Compile();\r
68                 return WrapVoidAction(voidExecutor);\r
69             }\r
70             else {\r
71                 // must coerce methodCall to match ActionExecutor signature\r
72                 UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));\r
73                 Expression<ActionExecutor> lambda = Expression.Lambda<ActionExecutor>(castMethodCall, controllerParameter, parametersParameter);\r
74                 return lambda.Compile();\r
75             }\r
76         }\r
77 \r
78         private static ActionExecutor WrapVoidAction(VoidActionExecutor executor) {\r
79             return delegate(ControllerBase controller, object[] parameters) {\r
80                 executor(controller, parameters);\r
81                 return null;\r
82             };\r
83         }\r
84 \r
85     }\r
86 }\r