Inheritance: BaseMetaDescriptor
		/// <summary>
		/// Gets an action descriptor with information about an action.
		/// </summary>
		/// <param name="actionMethod">The action method.</param>
		/// <returns></returns>
		public ActionMetaDescriptor GetAction(MethodInfo actionMethod)
		{
			ActionMetaDescriptor desc;

			if (!actionMetaDescriptors.TryGetValue(actionMethod, out desc))
			{
				desc = new ActionMetaDescriptor();
				actionMetaDescriptors[actionMethod] = desc;
			}

			return desc;
		}
		/// <summary>
		/// Selects the action to execute based on the url information
		/// </summary>
		/// <param name="controllerName">The controller name</param>
		/// <param name="actionName">The action name</param>
		/// <param name="actionArgs">The action arguments.</param>
		/// <returns></returns>
		public bool SelectAction(string actionName, string controllerName, IDictionary actionArgs)
		{
			try
			{
				// Look for the target method
				actionMethod = controller.SelectMethod(actionName, metaDescriptor.Actions, context.Request, actionArgs);

				// If we couldn't find a method for this action, look for a dynamic action
				dynAction = null;

				if (actionMethod == null)
				{
					if (controller.DynamicActions.ContainsKey(actionName))
					{
						dynAction = controller.DynamicActions[actionName];
					}

					if (dynAction == null)
					{
						actionMethod = FindOutDefaultMethod(actionArgs);

						if (actionMethod == null)
						{
							throw new ControllerException(
								String.Format("Unable to locate action [{0}] on controller [{1}].", actionName, controllerName));
						}
					}
				}
				else
				{
					actionDesc = metaDescriptor.GetAction(actionMethod);

					// Overrides the current layout, if the action specifies one
					if (actionDesc.Layout != null)
					{
						controller.LayoutName = actionDesc.Layout.LayoutName;
					}

					if (actionDesc.AccessibleThrough != null)
					{
						string verbName = actionDesc.AccessibleThrough.Verb.ToString();
						string requestType = context.RequestType;

						if (String.Compare(verbName, requestType, true) != 0)
						{
							exceptionToThrow = new ControllerException(string.Format("Access to the action [{0}] " +
							                                            "on controller [{1}] is not allowed by the http verb [{2}].",
							                                            actionName, controllerName, requestType));

							hasError = true;

							return false;
						}
					}
				}

				// Record the action
				controller.SetEvaluatedAction(actionName);

				// Record the default view for this area/controller/action
				controller.RenderView(actionName);
				
				// Compute the filters that should be skipped for this action/method
				filtersToSkip = new HybridDictionary();
				skipFilters = ShouldSkip(actionMethod);

				return true;
			}
			catch(Exception ex)
			{
				// There was an exception selecting the method

				hasError = true;

				exceptionToThrow = ex;

				return false;
			}
		}
		/// <summary>
		/// Collects the cache configures.
		/// </summary>
		/// <param name="descriptor">The descriptor.</param>
		/// <param name="memberInfo">The member info.</param>
		private void CollectCacheConfigures(ActionMetaDescriptor descriptor, MemberInfo memberInfo)
		{
			object[] configurers = memberInfo.GetCustomAttributes(typeof(ICachePolicyConfigurer), true);

			if (configurers.Length != 0)
			{
				foreach(ICachePolicyConfigurer cacheConfigurer in configurers)
				{
					descriptor.CacheConfigurers.Add(cacheConfigurer);
				}
			}
		}
		/// <summary>
		/// Collects the transform filter.
		/// </summary>
		/// <param name="actionDescriptor">The action descriptor.</param>
		/// <param name="method">The method.</param>
		private void CollectTransformFilter(ActionMetaDescriptor actionDescriptor, MethodInfo method)
		{
			actionDescriptor.TransformFilters = transformFilterDescriptorProvider.CollectFilters((method));
			Array.Sort(actionDescriptor.TransformFilters, TransformFilterDescriptorComparer.Instance);
		}
		/// <summary>
		/// Collects the skip filter.
		/// </summary>
		/// <param name="actionDescriptor">The action descriptor.</param>
		/// <param name="method">The method.</param>
		private void CollectSkipFilter(ActionMetaDescriptor actionDescriptor, MethodInfo method)
		{
			object[] attributes = method.GetCustomAttributes(typeof(SkipFilterAttribute), true);
			
			foreach(SkipFilterAttribute attr in attributes)
			{
				actionDescriptor.SkipFilters.Add(attr);
			}
		}
		/// <summary>
		/// Collects the accessible through.
		/// </summary>
		/// <param name="actionDescriptor">The action descriptor.</param>
		/// <param name="method">The method.</param>
		private void CollectAccessibleThrough(ActionMetaDescriptor actionDescriptor, MethodInfo method)
		{
			object[] attributes = method.GetCustomAttributes(typeof(AccessibleThroughAttribute), true);
			
			if (attributes.Length != 0)
			{
				actionDescriptor.AccessibleThrough = (AccessibleThroughAttribute) attributes[0];
			}
		}
		/// <summary>
		/// Collects the skip rescue.
		/// </summary>
		/// <param name="actionDescriptor">The action descriptor.</param>
		/// <param name="method">The method.</param>
		private void CollectSkipRescue(ActionMetaDescriptor actionDescriptor, MethodInfo method)
		{
			object[] attributes = method.GetCustomAttributes(typeof(SkipRescueAttribute), true);
			
			if (attributes.Length != 0)
			{
				actionDescriptor.SkipRescue = (SkipRescueAttribute) attributes[0];
			}
		}