private static ControllerDescriptor GetDescriptor(Type controllerType)
        {
            ControllerDescriptor descriptor;
            if (_controllerDescriptors.TryGetValue(controllerType, out descriptor)) {
                return descriptor;
            }

            descriptor = new ControllerDescriptor();

            Type actionResultType = typeof(ActionResult);
            Type taskActionResultType = typeof(Task<ActionResult>);
            BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance |
                                        BindingFlags.FlattenHierarchy;

            MethodInfo[] methods = controllerType.GetMethods(bindingFlags);
            foreach (MethodInfo method in methods) {
                ActionDescriptor action = null;
                if (method.ReturnType.IsAssignableFrom(taskActionResultType)) {
                    action = new ActionDescriptor(method, /* async */ true);
                }
                else if (method.ReturnType.IsAssignableFrom(actionResultType)) {
                    action = new ActionDescriptor(method, /* async */ false);
                }
                else {
                    continue;
                }

                string actionName = method.Name;
                if (descriptor._actions.ContainsKey(actionName)) {
                    throw new InvalidOperationException(controllerType.Name + " has a duplicate action named " + actionName);
                }
                descriptor._actions[actionName] = action;
            }

            _controllerDescriptors[controllerType] = descriptor;
            return descriptor;
        }