Action invocation changes:

Changed 404s to throw
Propagate reflected exception
Add resources for specific errors
This commit is contained in:
Yishai Galatzer 2014-04-01 09:48:24 -07:00
parent 1b4754454b
commit 9756f74565
4 changed files with 125 additions and 74 deletions

View File

@ -1,6 +1,6 @@
using System; using System;
using System.Reflection;
using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.DependencyInjection;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
@ -22,23 +22,18 @@ namespace Microsoft.AspNet.Mvc
var actionDescriptor = actionContext.ActionDescriptor as ReflectedActionDescriptor; var actionDescriptor = actionContext.ActionDescriptor as ReflectedActionDescriptor;
if (actionDescriptor == null) if (actionDescriptor == null)
{ {
return null; throw new ArgumentException(
Resources.FormatDefaultControllerFactory_ActionDescriptorMustBeReflected(
typeof(ReflectedActionDescriptor)),
"actionContext");
} }
try var controller = _activator.CreateInstance(_serviceProvider, actionDescriptor.ControllerDescriptor.ControllerTypeInfo.AsType());
{
var controller = _activator.CreateInstance(_serviceProvider, actionDescriptor.ControllerDescriptor.ControllerTypeInfo.AsType());
// TODO: How do we feed the controller with context (need DI improvements) // TODO: How do we feed the controller with context (need DI improvements)
InitializeController(controller, actionContext); InitializeController(controller, actionContext);
return controller; return controller;
} // TODO: Should we not catch it here?
catch (ReflectionTypeLoadException)
{
}
return null;
} }
public void ReleaseController(object controller) public void ReleaseController(object controller)

View File

@ -201,7 +201,7 @@ namespace Microsoft.AspNet.Mvc.Core
{ {
return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_InvalidReturnValue"), p0, p1, p2); return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_InvalidReturnValue"), p0, p1, p2);
} }
/// <summary> /// <summary>
/// Replacing the action context is not supported. /// Replacing the action context is not supported.
/// </summary> /// </summary>
@ -234,6 +234,54 @@ namespace Microsoft.AspNet.Mvc.Core
return string.Format(CultureInfo.CurrentCulture, GetString("ActionInvokerFactory_CouldNotCreateInvoker"), p0); return string.Format(CultureInfo.CurrentCulture, GetString("ActionInvokerFactory_CouldNotCreateInvoker"), p0);
} }
/// <summary>
/// The action descriptor must be of type '{0}'.
/// </summary>
internal static string DefaultControllerFactory_ActionDescriptorMustBeReflected
{
get { return GetString("DefaultControllerFactory_ActionDescriptorMustBeReflected"); }
}
/// <summary>
/// The action descriptor must be of type '{0}'.
/// </summary>
internal static string FormatDefaultControllerFactory_ActionDescriptorMustBeReflected(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("DefaultControllerFactory_ActionDescriptorMustBeReflected"), p0);
}
/// <summary>
/// The '{0}' property of '{1}' must not be null.
/// </summary>
internal static string PropertyOfTypeCannotBeNull
{
get { return GetString("PropertyOfTypeCannotBeNull"); }
}
/// <summary>
/// The '{0}' property of '{1}' must not be null.
/// </summary>
internal static string FormatPropertyOfTypeCannotBeNull(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("PropertyOfTypeCannotBeNull"), p0, p1);
}
/// <summary>
/// The '{0}' must return a non null '{1}'.
/// </summary>
internal static string MethodMustReturnNotNullValue
{
get { return GetString("MethodMustReturnNotNullValue"); }
}
/// <summary>
/// The '{0}' must return a non null '{1}'.
/// </summary>
internal static string FormatMethodMustReturnNotNullValue(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("MethodMustReturnNotNullValue"), p0, p1);
}
private static string GetString(string name, params string[] formatterNames) private static string GetString(string name, params string[] formatterNames)
{ {
var value = _resourceManager.GetString(name); var value = _resourceManager.GetString(name);

View File

@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.DependencyInjection;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -21,12 +23,12 @@ namespace Microsoft.AspNet.Mvc
private readonly List<IActionFilter> _actionFilters = new List<IActionFilter>(); private readonly List<IActionFilter> _actionFilters = new List<IActionFilter>();
private readonly List<IActionResultFilter> _actionResultFilters = new List<IActionResultFilter>(); private readonly List<IActionResultFilter> _actionResultFilters = new List<IActionResultFilter>();
public ReflectedActionInvoker(ActionContext actionContext, public ReflectedActionInvoker([NotNull] ActionContext actionContext,
ReflectedActionDescriptor descriptor, [NotNull] ReflectedActionDescriptor descriptor,
IActionResultFactory actionResultFactory, [NotNull] IActionResultFactory actionResultFactory,
IControllerFactory controllerFactory, [NotNull] IControllerFactory controllerFactory,
IActionBindingContextProvider bindingContextProvider, [NotNull] IActionBindingContextProvider bindingContextProvider,
INestedProviderManager<FilterProviderContext> filterProvider) [NotNull] INestedProviderManager<FilterProviderContext> filterProvider)
{ {
_actionContext = actionContext; _actionContext = actionContext;
_descriptor = descriptor; _descriptor = descriptor;
@ -34,6 +36,14 @@ namespace Microsoft.AspNet.Mvc
_controllerFactory = controllerFactory; _controllerFactory = controllerFactory;
_bindingProvider = bindingContextProvider; _bindingProvider = bindingContextProvider;
_filterProvider = filterProvider; _filterProvider = filterProvider;
if (descriptor.MethodInfo == null)
{
throw new ArgumentException(
Resources.FormatPropertyOfTypeCannotBeNull(typeof(ReflectedActionDescriptor),
"MethodInfo"),
"descriptor");
}
} }
public async Task InvokeActionAsync() public async Task InvokeActionAsync()
@ -54,67 +64,56 @@ namespace Microsoft.AspNet.Mvc
if (controller == null) if (controller == null)
{ {
// TODO: See if these return 404s should turn into 500s throw new InvalidOperationException(
actionResult = new HttpStatusCodeResult(404); Resources.FormatMethodMustReturnNotNullValue(typeof(IControllerFactory),
"controller"));
} }
else
{
var method = _descriptor.MethodInfo;
if (method == null) if (_authorizationFilters.Count > 0)
{
var authZEndPoint = new AuthorizationFilterEndPoint();
_authorizationFilters.Add(authZEndPoint);
var authZContext = new AuthorizationFilterContext(_actionContext, filterMetaItems);
var authZPipeline = new FilterPipelineBuilder<AuthorizationFilterContext>(_authorizationFilters, authZContext);
await authZPipeline.InvokeAsync();
if (authZContext.ActionResult == null &&
!authZContext.HasFailed &&
authZEndPoint.EndPointCalled)
{ {
// TODO: See if these return 404s should turn into 500s actionResult = null;
actionResult = new HttpStatusCodeResult(404);
} }
else else
{ {
if (_authorizationFilters.Count > 0) // User cleaned out the result but we failed or short circuited the end point.
{ actionResult = authZContext.ActionResult ?? new HttpStatusCodeResult(401);
var authZEndPoint = new AuthorizationFilterEndPoint();
_authorizationFilters.Add(authZEndPoint);
var authZContext = new AuthorizationFilterContext(_actionContext, filterMetaItems);
var authZPipeline = new FilterPipelineBuilder<AuthorizationFilterContext>(_authorizationFilters, authZContext);
await authZPipeline.InvokeAsync();
if (authZContext.ActionResult == null &&
!authZContext.HasFailed &&
authZEndPoint.EndPointCalled)
{
actionResult = null;
}
else
{
// User cleaned out the result but we failed or short circuited the end point.
actionResult = authZContext.ActionResult ?? new HttpStatusCodeResult(401);
}
}
else
{
actionResult = null;
}
if (actionResult == null)
{
var parameterValues = await GetParameterValues(_actionContext.ModelState);
var actionFilterContext = new ActionFilterContext(_actionContext,
filterMetaItems,
parameterValues);
var actionEndPoint = new ReflectedActionFilterEndPoint(_actionResultFactory, controller);
_actionFilters.Add(actionEndPoint);
var actionFilterPipeline = new FilterPipelineBuilder<ActionFilterContext>(_actionFilters,
actionFilterContext);
await actionFilterPipeline.InvokeAsync();
actionResult = actionFilterContext.ActionResult;
}
} }
} }
else
{
actionResult = null;
}
if (actionResult == null)
{
var parameterValues = await GetParameterValues(_actionContext.ModelState);
var actionFilterContext = new ActionFilterContext(_actionContext,
filterMetaItems,
parameterValues);
var actionEndPoint = new ReflectedActionFilterEndPoint(_actionResultFactory, controller);
_actionFilters.Add(actionEndPoint);
var actionFilterPipeline = new FilterPipelineBuilder<ActionFilterContext>(_actionFilters,
actionFilterContext);
await actionFilterPipeline.InvokeAsync();
actionResult = actionFilterContext.ActionResult;
}
var actionResultFilterContext = new ActionResultFilterContext(_actionContext, filterMetaItems, actionResult); var actionResultFilterContext = new ActionResultFilterContext(_actionContext, filterMetaItems, actionResult);
var actionResultFilterEndPoint = new ActionResultFilterEndPoint(); var actionResultFilterEndPoint = new ActionResultFilterEndPoint();

View File

@ -159,4 +159,13 @@
<data name="ActionInvokerFactory_CouldNotCreateInvoker" xml:space="preserve"> <data name="ActionInvokerFactory_CouldNotCreateInvoker" xml:space="preserve">
<value>An action invoker could not be created for action '{0}'.</value> <value>An action invoker could not be created for action '{0}'.</value>
</data> </data>
<data name="DefaultControllerFactory_ActionDescriptorMustBeReflected" xml:space="preserve">
<value>The action descriptor must be of type '{0}'.</value>
</data>
<data name="PropertyOfTypeCannotBeNull" xml:space="preserve">
<value>The '{0}' property of '{1}' must not be null.</value>
</data>
<data name="MethodMustReturnNotNullValue" xml:space="preserve">
<value>The '{0}' must return a non null '{1}'.</value>
</data>
</root> </root>