Changing when controllers are created
This change moves controller creation to the stage immediately before model binding. The controller will be disposed/released before Resource Filters run their 'OnResourceExecuted' method. Previously the controller's lifetime surrounded all filter invocation. Additionally, the Controller property is now gone from ActionContext, and is moved to the 4 filter contexts that should have access to it Action*Context and Result*Context.
This commit is contained in:
parent
e1069dbf65
commit
0c5a702245
|
|
@ -14,7 +14,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
: this(actionContext.HttpContext, actionContext.RouteData, actionContext.ActionDescriptor)
|
: this(actionContext.HttpContext, actionContext.RouteData, actionContext.ActionDescriptor)
|
||||||
{
|
{
|
||||||
ModelState = actionContext.ModelState;
|
ModelState = actionContext.ModelState;
|
||||||
Controller = actionContext.Controller;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionContext([NotNull] RouteContext routeContext, [NotNull] ActionDescriptor actionDescriptor)
|
public ActionContext([NotNull] RouteContext routeContext, [NotNull] ActionDescriptor actionDescriptor)
|
||||||
|
|
@ -39,10 +38,5 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public ModelStateDictionary ModelState { get; private set; }
|
public ModelStateDictionary ModelState { get; private set; }
|
||||||
|
|
||||||
public ActionDescriptor ActionDescriptor { get; private set; }
|
public ActionDescriptor ActionDescriptor { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The controller is available only after the controller factory runs.
|
|
||||||
/// </summary>
|
|
||||||
public object Controller { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,21 +50,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async override Task InvokeAsync()
|
protected override object CreateInstance()
|
||||||
{
|
{
|
||||||
// The binding context is used in activation
|
// The binding context is used in activation
|
||||||
Debug.Assert(ActionBindingContext != null);
|
Debug.Assert(ActionBindingContext != null);
|
||||||
var controller = _controllerFactory.CreateController(ActionContext);
|
return _controllerFactory.CreateController(ActionContext);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
protected override void ReleaseInstance(object instance)
|
||||||
{
|
{
|
||||||
ActionContext.Controller = controller;
|
_controllerFactory.ReleaseController(instance);
|
||||||
await base.InvokeAsync();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_controllerFactory.ReleaseController(ActionContext.Controller);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<IActionResult> InvokeActionAsync(ActionExecutingContext actionExecutingContext)
|
protected override async Task<IActionResult> InvokeActionAsync(ActionExecutingContext actionExecutingContext)
|
||||||
|
|
@ -72,7 +67,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var actionMethodInfo = _descriptor.MethodInfo;
|
var actionMethodInfo = _descriptor.MethodInfo;
|
||||||
var actionReturnValue = await ControllerActionExecutor.ExecuteAsync(
|
var actionReturnValue = await ControllerActionExecutor.ExecuteAsync(
|
||||||
actionMethodInfo,
|
actionMethodInfo,
|
||||||
ActionContext.Controller,
|
actionExecutingContext.Controller,
|
||||||
actionExecutingContext.ActionArguments);
|
actionExecutingContext.ActionArguments);
|
||||||
|
|
||||||
var actionResult = CreateActionResult(
|
var actionResult = CreateActionResult(
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
_serviceProvider,
|
_serviceProvider,
|
||||||
actionDescriptor.ControllerTypeInfo.AsType());
|
actionDescriptor.ControllerTypeInfo.AsType());
|
||||||
|
|
||||||
actionContext.Controller = controller;
|
|
||||||
_controllerActivator.Activate(controller, actionContext);
|
_controllerActivator.Activate(controller, actionContext);
|
||||||
|
|
||||||
return controller;
|
return controller;
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
_modelValidatorProviderProvider = modelValidatorProviderProvider;
|
_modelValidatorProviderProvider = modelValidatorProviderProvider;
|
||||||
_valueProviderFactoryProvider = valueProviderFactoryProvider;
|
_valueProviderFactoryProvider = valueProviderFactoryProvider;
|
||||||
_actionBindingContextAccessor = actionBindingContextAccessor;
|
_actionBindingContextAccessor = actionBindingContextAccessor;
|
||||||
|
|
||||||
ActionBindingContext = new ActionBindingContext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ActionContext ActionContext { get; private set; }
|
protected ActionContext ActionContext { get; private set; }
|
||||||
|
|
@ -73,6 +71,21 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected object Instance { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called to create an instance of an object which will act as the reciever of the action invocation.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The constructed instance or <c>null</c>.</returns>
|
||||||
|
protected abstract object CreateInstance();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called to create an instance of an object which will act as the reciever of the action invocation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instance">The instance to release.</param>
|
||||||
|
/// <remarks>This method will not be called if <see cref="CreateInstance"/> returns <c>null</c>.</remarks>
|
||||||
|
protected abstract void ReleaseInstance(object instance);
|
||||||
|
|
||||||
protected abstract Task<IActionResult> InvokeActionAsync(ActionExecutingContext actionExecutingContext);
|
protected abstract Task<IActionResult> InvokeActionAsync(ActionExecutingContext actionExecutingContext);
|
||||||
|
|
||||||
protected abstract Task<IDictionary<string, object>> GetActionArgumentsAsync(
|
protected abstract Task<IDictionary<string, object>> GetActionArgumentsAsync(
|
||||||
|
|
@ -95,7 +108,20 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await InvokeAllResourceFiltersAsync();
|
try
|
||||||
|
{
|
||||||
|
await InvokeAllResourceFiltersAsync();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Release the instance after all filters have run. We don't need to surround
|
||||||
|
// Authorizations filters because the instance will be created much later than
|
||||||
|
// that.
|
||||||
|
if (Instance != null)
|
||||||
|
{
|
||||||
|
ReleaseInstance(Instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We've reached the end of resource filters. If there's an unhandled exception on the context then
|
// We've reached the end of resource filters. If there's an unhandled exception on the context then
|
||||||
// it should be thrown and middleware has a chance to handle it.
|
// it should be thrown and middleware has a chance to handle it.
|
||||||
|
|
@ -207,7 +233,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
if (item.FilterAsync != null)
|
if (item.FilterAsync != null)
|
||||||
{
|
{
|
||||||
await item.FilterAsync.OnResourceExecutionAsync(
|
await item.FilterAsync.OnResourceExecutionAsync(
|
||||||
_resourceExecutingContext,
|
_resourceExecutingContext,
|
||||||
InvokeResourceFilterAsync);
|
InvokeResourceFilterAsync);
|
||||||
|
|
||||||
if (_resourceExecutedContext == null)
|
if (_resourceExecutedContext == null)
|
||||||
|
|
@ -384,23 +410,30 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
Debug.Assert(_resourceExecutingContext != null);
|
Debug.Assert(_resourceExecutingContext != null);
|
||||||
|
|
||||||
Debug.Assert(ActionBindingContext != null);
|
ActionBindingContext = new ActionBindingContext();
|
||||||
ActionBindingContext.InputFormatters = _resourceExecutingContext.InputFormatters;
|
ActionBindingContext.InputFormatters = _resourceExecutingContext.InputFormatters;
|
||||||
ActionBindingContext.ModelBinder = new CompositeModelBinder(_resourceExecutingContext.ModelBinders);
|
ActionBindingContext.ModelBinder = new CompositeModelBinder(_resourceExecutingContext.ModelBinders);
|
||||||
ActionBindingContext.ValidatorProvider = new CompositeModelValidatorProvider(
|
ActionBindingContext.ValidatorProvider = new CompositeModelValidatorProvider(
|
||||||
_resourceExecutingContext.ValidatorProviders);
|
_resourceExecutingContext.ValidatorProviders);
|
||||||
|
|
||||||
var valueProviderFactoryContext = new ValueProviderFactoryContext(
|
var valueProviderFactoryContext = new ValueProviderFactoryContext(
|
||||||
ActionContext.HttpContext,
|
ActionContext.HttpContext,
|
||||||
ActionContext.RouteData.Values);
|
ActionContext.RouteData.Values);
|
||||||
|
|
||||||
ActionBindingContext.ValueProvider = CompositeValueProvider.Create(
|
ActionBindingContext.ValueProvider = CompositeValueProvider.Create(
|
||||||
_resourceExecutingContext.ValueProviderFactories,
|
_resourceExecutingContext.ValueProviderFactories,
|
||||||
valueProviderFactoryContext);
|
valueProviderFactoryContext);
|
||||||
|
|
||||||
|
Instance = CreateInstance();
|
||||||
|
|
||||||
var arguments = await GetActionArgumentsAsync(ActionContext, ActionBindingContext);
|
var arguments = await GetActionArgumentsAsync(ActionContext, ActionBindingContext);
|
||||||
|
|
||||||
_actionExecutingContext = new ActionExecutingContext(ActionContext, _filters, arguments);
|
_actionExecutingContext = new ActionExecutingContext(
|
||||||
|
ActionContext,
|
||||||
|
_filters,
|
||||||
|
arguments,
|
||||||
|
Instance);
|
||||||
|
|
||||||
await InvokeActionFilterAsync();
|
await InvokeActionFilterAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -429,7 +462,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
if (_actionExecutedContext == null)
|
if (_actionExecutedContext == null)
|
||||||
{
|
{
|
||||||
// If we get here then the filter didn't call 'next' indicating a short circuit
|
// If we get here then the filter didn't call 'next' indicating a short circuit
|
||||||
_actionExecutedContext = new ActionExecutedContext(_actionExecutingContext, _filters)
|
_actionExecutedContext = new ActionExecutedContext(
|
||||||
|
_actionExecutingContext,
|
||||||
|
_filters,
|
||||||
|
Instance)
|
||||||
{
|
{
|
||||||
Canceled = true,
|
Canceled = true,
|
||||||
Result = _actionExecutingContext.Result,
|
Result = _actionExecutingContext.Result,
|
||||||
|
|
@ -443,7 +479,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
if (_actionExecutingContext.Result != null)
|
if (_actionExecutingContext.Result != null)
|
||||||
{
|
{
|
||||||
// Short-circuited by setting a result.
|
// Short-circuited by setting a result.
|
||||||
_actionExecutedContext = new ActionExecutedContext(_actionExecutingContext, _filters)
|
_actionExecutedContext = new ActionExecutedContext(
|
||||||
|
_actionExecutingContext,
|
||||||
|
_filters,
|
||||||
|
Instance)
|
||||||
{
|
{
|
||||||
Canceled = true,
|
Canceled = true,
|
||||||
Result = _actionExecutingContext.Result,
|
Result = _actionExecutingContext.Result,
|
||||||
|
|
@ -457,7 +496,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// All action filters have run, execute the action method.
|
// All action filters have run, execute the action method.
|
||||||
_actionExecutedContext = new ActionExecutedContext(_actionExecutingContext, _filters)
|
_actionExecutedContext = new ActionExecutedContext(
|
||||||
|
_actionExecutingContext,
|
||||||
|
_filters,
|
||||||
|
Instance)
|
||||||
{
|
{
|
||||||
Result = await InvokeActionAsync(_actionExecutingContext),
|
Result = await InvokeActionAsync(_actionExecutingContext),
|
||||||
};
|
};
|
||||||
|
|
@ -466,7 +508,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
// Exceptions thrown by the action method OR filters bubble back up through ActionExcecutedContext.
|
// Exceptions thrown by the action method OR filters bubble back up through ActionExcecutedContext.
|
||||||
_actionExecutedContext = new ActionExecutedContext(_actionExecutingContext, _filters)
|
_actionExecutedContext = new ActionExecutedContext(
|
||||||
|
_actionExecutingContext,
|
||||||
|
_filters,
|
||||||
|
Instance)
|
||||||
{
|
{
|
||||||
ExceptionDispatchInfo = ExceptionDispatchInfo.Capture(exception)
|
ExceptionDispatchInfo = ExceptionDispatchInfo.Capture(exception)
|
||||||
};
|
};
|
||||||
|
|
@ -478,7 +523,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
_cursor.SetStage(FilterStage.ResultFilters);
|
_cursor.SetStage(FilterStage.ResultFilters);
|
||||||
|
|
||||||
_resultExecutingContext = new ResultExecutingContext(ActionContext, _filters, result);
|
_resultExecutingContext = new ResultExecutingContext(ActionContext, _filters, result, Instance);
|
||||||
await InvokeResultFilterAsync();
|
await InvokeResultFilterAsync();
|
||||||
|
|
||||||
Debug.Assert(_resultExecutingContext != null);
|
Debug.Assert(_resultExecutingContext != null);
|
||||||
|
|
@ -525,7 +570,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
_resultExecutedContext = new ResultExecutedContext(
|
_resultExecutedContext = new ResultExecutedContext(
|
||||||
_resultExecutingContext,
|
_resultExecutingContext,
|
||||||
_filters,
|
_filters,
|
||||||
_resultExecutingContext.Result)
|
_resultExecutingContext.Result,
|
||||||
|
Instance)
|
||||||
{
|
{
|
||||||
Canceled = true,
|
Canceled = true,
|
||||||
};
|
};
|
||||||
|
|
@ -536,7 +582,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
_resultExecutedContext = new ResultExecutedContext(
|
_resultExecutedContext = new ResultExecutedContext(
|
||||||
_resultExecutingContext,
|
_resultExecutingContext,
|
||||||
_filters,
|
_filters,
|
||||||
_resultExecutingContext.Result)
|
_resultExecutingContext.Result,
|
||||||
|
Instance)
|
||||||
{
|
{
|
||||||
Canceled = true,
|
Canceled = true,
|
||||||
};
|
};
|
||||||
|
|
@ -552,7 +599,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
_resultExecutedContext = new ResultExecutedContext(
|
_resultExecutedContext = new ResultExecutedContext(
|
||||||
_resultExecutingContext,
|
_resultExecutingContext,
|
||||||
_filters,
|
_filters,
|
||||||
_resultExecutingContext.Result)
|
_resultExecutingContext.Result,
|
||||||
|
Instance)
|
||||||
{
|
{
|
||||||
Canceled = true,
|
Canceled = true,
|
||||||
};
|
};
|
||||||
|
|
@ -570,7 +618,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
_resultExecutedContext = new ResultExecutedContext(
|
_resultExecutedContext = new ResultExecutedContext(
|
||||||
_resultExecutingContext,
|
_resultExecutingContext,
|
||||||
_filters,
|
_filters,
|
||||||
_resultExecutingContext.Result);
|
_resultExecutingContext.Result,
|
||||||
|
Instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
|
|
@ -578,7 +627,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
_resultExecutedContext = new ResultExecutedContext(
|
_resultExecutedContext = new ResultExecutedContext(
|
||||||
_resultExecutingContext,
|
_resultExecutingContext,
|
||||||
_filters,
|
_filters,
|
||||||
_resultExecutingContext.Result)
|
_resultExecutingContext.Result,
|
||||||
|
Instance)
|
||||||
{
|
{
|
||||||
ExceptionDispatchInfo = ExceptionDispatchInfo.Capture(exception)
|
ExceptionDispatchInfo = ExceptionDispatchInfo.Capture(exception)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,17 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public ActionExecutedContext(
|
public ActionExecutedContext(
|
||||||
[NotNull] ActionContext actionContext,
|
[NotNull] ActionContext actionContext,
|
||||||
[NotNull] IList<IFilter> filters)
|
[NotNull] IList<IFilter> filters,
|
||||||
|
object controller)
|
||||||
: base(actionContext, filters)
|
: base(actionContext, filters)
|
||||||
{
|
{
|
||||||
|
Controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool Canceled { get; set; }
|
public virtual bool Canceled { get; set; }
|
||||||
|
|
||||||
|
public virtual object Controller { get; }
|
||||||
|
|
||||||
public virtual Exception Exception
|
public virtual Exception Exception
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,18 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public ActionExecutingContext(
|
public ActionExecutingContext(
|
||||||
[NotNull] ActionContext actionContext,
|
[NotNull] ActionContext actionContext,
|
||||||
[NotNull] IList<IFilter> filters,
|
[NotNull] IList<IFilter> filters,
|
||||||
[NotNull] IDictionary<string, object> actionArguments)
|
[NotNull] IDictionary<string, object> actionArguments,
|
||||||
|
object controller)
|
||||||
: base(actionContext, filters)
|
: base(actionContext, filters)
|
||||||
{
|
{
|
||||||
ActionArguments = actionArguments;
|
ActionArguments = actionArguments;
|
||||||
|
Controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual IActionResult Result { get; set; }
|
public virtual IActionResult Result { get; set; }
|
||||||
|
|
||||||
public virtual IDictionary<string, object> ActionArguments { get; private set; }
|
public virtual IDictionary<string, object> ActionArguments { get; }
|
||||||
|
|
||||||
|
public virtual object Controller { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,18 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public ResultExecutedContext(
|
public ResultExecutedContext(
|
||||||
[NotNull] ActionContext actionContext,
|
[NotNull] ActionContext actionContext,
|
||||||
[NotNull] IList<IFilter> filters,
|
[NotNull] IList<IFilter> filters,
|
||||||
[NotNull] IActionResult result)
|
[NotNull] IActionResult result,
|
||||||
|
object controller)
|
||||||
: base(actionContext, filters)
|
: base(actionContext, filters)
|
||||||
{
|
{
|
||||||
Result = result;
|
Result = result;
|
||||||
|
Controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool Canceled { get; set; }
|
public virtual bool Canceled { get; set; }
|
||||||
|
|
||||||
|
public virtual object Controller { get; }
|
||||||
|
|
||||||
public virtual Exception Exception
|
public virtual Exception Exception
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public ResultExecutingContext(
|
public ResultExecutingContext(
|
||||||
[NotNull] ActionContext actionContext,
|
[NotNull] ActionContext actionContext,
|
||||||
[NotNull] IList<IFilter> filters,
|
[NotNull] IList<IFilter> filters,
|
||||||
[NotNull] IActionResult result)
|
[NotNull] IActionResult result,
|
||||||
|
object controller)
|
||||||
: base(actionContext, filters)
|
: base(actionContext, filters)
|
||||||
{
|
{
|
||||||
Result = result;
|
Result = result;
|
||||||
|
Controller = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual object Controller { get; }
|
||||||
|
|
||||||
public virtual IActionResult Result { get; set; }
|
public virtual IActionResult Result { get; set; }
|
||||||
|
|
||||||
public virtual bool Cancel { get; set; }
|
public virtual bool Cancel { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -296,6 +296,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
filter1.Verify(f => f.OnAuthorization(It.IsAny<AuthorizationContext>()), Times.Once());
|
filter1.Verify(f => f.OnAuthorization(It.IsAny<AuthorizationContext>()), Times.Once());
|
||||||
|
Assert.False(invoker.ControllerFactory.CreateCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -325,6 +326,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
filter1.Verify(
|
filter1.Verify(
|
||||||
f => f.OnAuthorizationAsync(It.IsAny<AuthorizationContext>()),
|
f => f.OnAuthorizationAsync(It.IsAny<AuthorizationContext>()),
|
||||||
Times.Once());
|
Times.Once());
|
||||||
|
|
||||||
|
Assert.False(invoker.ControllerFactory.CreateCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -1735,6 +1738,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(expected.Object, context.Result);
|
Assert.Same(expected.Object, context.Result);
|
||||||
Assert.True(context.Canceled);
|
Assert.True(context.Canceled);
|
||||||
|
Assert.False(invoker.ControllerFactory.CreateCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -1786,6 +1790,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(expected.Object, context.Result);
|
Assert.Same(expected.Object, context.Result);
|
||||||
Assert.True(context.Canceled);
|
Assert.True(context.Canceled);
|
||||||
|
Assert.False(invoker.ControllerFactory.CreateCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -1847,6 +1852,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
resourceFilter.Verify(
|
resourceFilter.Verify(
|
||||||
f => f.OnResourceExecutionAsync(It.IsAny<ResourceExecutingContext>(), It.IsAny<ResourceExecutionDelegate>()),
|
f => f.OnResourceExecutionAsync(It.IsAny<ResourceExecutingContext>(), It.IsAny<ResourceExecutionDelegate>()),
|
||||||
Times.Never());
|
Times.Never());
|
||||||
|
|
||||||
|
Assert.False(invoker.ControllerFactory.CreateCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -1969,10 +1976,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
routeData: new RouteData(),
|
routeData: new RouteData(),
|
||||||
actionDescriptor: actionDescriptor);
|
actionDescriptor: actionDescriptor);
|
||||||
|
|
||||||
var controllerFactory = new Mock<IControllerFactory>();
|
|
||||||
controllerFactory.Setup(c => c.CreateController(It.IsAny<ActionContext>())).Returns(this);
|
|
||||||
controllerFactory.Setup(m => m.ReleaseController(this)).Verifiable();
|
|
||||||
|
|
||||||
var filterProvider = new Mock<INestedProviderManager<FilterProviderContext>>(MockBehavior.Strict);
|
var filterProvider = new Mock<INestedProviderManager<FilterProviderContext>>(MockBehavior.Strict);
|
||||||
filterProvider
|
filterProvider
|
||||||
.Setup(fp => fp.Invoke(It.IsAny<FilterProviderContext>()))
|
.Setup(fp => fp.Invoke(It.IsAny<FilterProviderContext>()))
|
||||||
|
|
@ -1985,7 +1988,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var invoker = new TestControllerActionInvoker(
|
var invoker = new TestControllerActionInvoker(
|
||||||
actionContext,
|
actionContext,
|
||||||
filterProvider.Object,
|
filterProvider.Object,
|
||||||
controllerFactory,
|
new MockControllerFactory(this),
|
||||||
actionDescriptor,
|
actionDescriptor,
|
||||||
inputFormattersProvider.Object,
|
inputFormattersProvider.Object,
|
||||||
Mock.Of<IControllerActionArgumentBinder>(),
|
Mock.Of<IControllerActionArgumentBinder>(),
|
||||||
|
|
@ -1997,8 +2000,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return invoker;
|
return invoker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Invoke_UsesDefaultValuesIfNotBound()
|
public async Task Invoke_UsesDefaultValuesIfNotBound()
|
||||||
{
|
{
|
||||||
|
|
@ -2097,14 +2098,47 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestControllerActionInvoker : ControllerActionInvoker
|
private class MockControllerFactory : IControllerFactory
|
||||||
{
|
{
|
||||||
private Mock<IControllerFactory> _factoryMock;
|
private object _controller;
|
||||||
|
|
||||||
|
public MockControllerFactory(object controller)
|
||||||
|
{
|
||||||
|
_controller = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CreateCalled { get; private set; }
|
||||||
|
|
||||||
|
public bool ReleaseCalled { get; private set; }
|
||||||
|
|
||||||
|
public object CreateController(ActionContext actionContext)
|
||||||
|
{
|
||||||
|
CreateCalled = true;
|
||||||
|
return _controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReleaseController(object controller)
|
||||||
|
{
|
||||||
|
Assert.NotNull(controller);
|
||||||
|
Assert.Same(_controller, controller);
|
||||||
|
ReleaseCalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Verify()
|
||||||
|
{
|
||||||
|
if (CreateCalled && !ReleaseCalled)
|
||||||
|
{
|
||||||
|
Assert.False(true, "ReleaseController should have been called.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestControllerActionInvoker : ControllerActionInvoker
|
||||||
|
{
|
||||||
public TestControllerActionInvoker(
|
public TestControllerActionInvoker(
|
||||||
ActionContext actionContext,
|
ActionContext actionContext,
|
||||||
INestedProviderManager<FilterProviderContext> filterProvider,
|
INestedProviderManager<FilterProviderContext> filterProvider,
|
||||||
Mock<IControllerFactory> controllerFactoryMock,
|
MockControllerFactory controllerFactory,
|
||||||
ControllerActionDescriptor descriptor,
|
ControllerActionDescriptor descriptor,
|
||||||
IInputFormattersProvider inputFormattersProvider,
|
IInputFormattersProvider inputFormattersProvider,
|
||||||
IControllerActionArgumentBinder controllerActionArgumentBinder,
|
IControllerActionArgumentBinder controllerActionArgumentBinder,
|
||||||
|
|
@ -2115,7 +2149,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
: base(
|
: base(
|
||||||
actionContext,
|
actionContext,
|
||||||
filterProvider,
|
filterProvider,
|
||||||
controllerFactoryMock.Object,
|
controllerFactory,
|
||||||
descriptor,
|
descriptor,
|
||||||
inputFormattersProvider,
|
inputFormattersProvider,
|
||||||
controllerActionArgumentBinder,
|
controllerActionArgumentBinder,
|
||||||
|
|
@ -2124,14 +2158,17 @@ namespace Microsoft.AspNet.Mvc
|
||||||
valueProviderFactoryProvider,
|
valueProviderFactoryProvider,
|
||||||
actionBindingContext)
|
actionBindingContext)
|
||||||
{
|
{
|
||||||
_factoryMock = controllerFactoryMock;
|
ControllerFactory = controllerFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MockControllerFactory ControllerFactory { get; }
|
||||||
|
|
||||||
public async override Task InvokeAsync()
|
public async override Task InvokeAsync()
|
||||||
{
|
{
|
||||||
await base.InvokeAsync();
|
await base.InvokeAsync();
|
||||||
|
|
||||||
_factoryMock.Verify();
|
// Make sure that the controller was disposed in every test that creates ones.
|
||||||
|
ControllerFactory.Verify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
.Returns(services);
|
.Returns(services);
|
||||||
var routeContext = new RouteContext(httpContext.Object);
|
var routeContext = new RouteContext(httpContext.Object);
|
||||||
var controller = new TestController();
|
var controller = new TestController();
|
||||||
var context = new ActionContext(routeContext, new ActionDescriptor())
|
var context = new ActionContext(routeContext, new ActionDescriptor());
|
||||||
{
|
|
||||||
Controller = controller
|
|
||||||
};
|
|
||||||
var activator = new DefaultControllerActivator();
|
var activator = new DefaultControllerActivator();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -55,10 +52,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
.Returns(services);
|
.Returns(services);
|
||||||
var routeContext = new RouteContext(httpContext.Object);
|
var routeContext = new RouteContext(httpContext.Object);
|
||||||
var controller = new TestController();
|
var controller = new TestController();
|
||||||
var context = new ActionContext(routeContext, new ActionDescriptor())
|
var context = new ActionContext(routeContext, new ActionDescriptor());
|
||||||
{
|
|
||||||
Controller = controller
|
|
||||||
};
|
|
||||||
var activator = new DefaultControllerActivator();
|
var activator = new DefaultControllerActivator();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -83,10 +77,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
var routeContext = new RouteContext(httpContext.Object);
|
var routeContext = new RouteContext(httpContext.Object);
|
||||||
|
|
||||||
var controller = new TestController();
|
var controller = new TestController();
|
||||||
var context = new ActionContext(routeContext, new ActionDescriptor())
|
var context = new ActionContext(routeContext, new ActionDescriptor());
|
||||||
{
|
|
||||||
Controller = controller
|
|
||||||
};
|
|
||||||
|
|
||||||
var activator = new DefaultControllerActivator();
|
var activator = new DefaultControllerActivator();
|
||||||
|
|
||||||
|
|
@ -109,10 +100,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
.Returns(services);
|
.Returns(services);
|
||||||
var routeContext = new RouteContext(httpContext.Object);
|
var routeContext = new RouteContext(httpContext.Object);
|
||||||
var controller = new TestController();
|
var controller = new TestController();
|
||||||
var context = new ActionContext(routeContext, new ActionDescriptor())
|
var context = new ActionContext(routeContext, new ActionDescriptor());
|
||||||
{
|
|
||||||
Controller = controller
|
|
||||||
};
|
|
||||||
var activator = new DefaultControllerActivator();
|
var activator = new DefaultControllerActivator();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -135,10 +123,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
.Returns(services);
|
.Returns(services);
|
||||||
var routeContext = new RouteContext(httpContext.Object);
|
var routeContext = new RouteContext(httpContext.Object);
|
||||||
var controller = new TestController();
|
var controller = new TestController();
|
||||||
var context = new ActionContext(routeContext, new ActionDescriptor())
|
var context = new ActionContext(routeContext, new ActionDescriptor());
|
||||||
{
|
|
||||||
Controller = controller
|
|
||||||
};
|
|
||||||
var activator = new DefaultControllerActivator();
|
var activator = new DefaultControllerActivator();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
|
||||||
|
|
@ -227,12 +227,13 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
return new ActionExecutingContext(
|
return new ActionExecutingContext(
|
||||||
CreateActionContext(),
|
CreateActionContext(),
|
||||||
new IFilter[] { filter, },
|
new IFilter[] { filter, },
|
||||||
new Dictionary<string, object>());
|
new Dictionary<string, object>(),
|
||||||
|
controller: new object());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionExecutedContext CreateActionExecutedContext(ActionExecutingContext context)
|
private static ActionExecutedContext CreateActionExecutedContext(ActionExecutingContext context)
|
||||||
{
|
{
|
||||||
return new ActionExecutedContext(context, context.Filters)
|
return new ActionExecutedContext(context, context.Filters, context.Controller)
|
||||||
{
|
{
|
||||||
Result = context.Result,
|
Result = context.Result,
|
||||||
};
|
};
|
||||||
|
|
@ -243,12 +244,13 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
return new ResultExecutingContext(
|
return new ResultExecutingContext(
|
||||||
CreateActionContext(),
|
CreateActionContext(),
|
||||||
new IFilter[] { filter, },
|
new IFilter[] { filter, },
|
||||||
new NoOpResult());
|
new NoOpResult(),
|
||||||
|
controller: new object());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ResultExecutedContext CreateResultExecutedContext(ResultExecutingContext context)
|
private static ResultExecutedContext CreateResultExecutedContext(ResultExecutingContext context)
|
||||||
{
|
{
|
||||||
return new ResultExecutedContext(context, context.Filters, context.Result);
|
return new ResultExecutedContext(context, context.Filters, context.Result, context.Controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionContext CreateActionContext()
|
private static ActionContext CreateActionContext()
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
|
|
||||||
private static ResultExecutedContext CreateResultExecutedContext(ResultExecutingContext context)
|
private static ResultExecutedContext CreateResultExecutedContext(ResultExecutingContext context)
|
||||||
{
|
{
|
||||||
return new ResultExecutedContext(context, context.Filters, context.Result);
|
return new ResultExecutedContext(context, context.Filters, context.Result, context.Controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ResultExecutingContext CreateResultExecutingContext(IFilter filter)
|
private static ResultExecutingContext CreateResultExecutingContext(IFilter filter)
|
||||||
|
|
@ -70,7 +70,8 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
return new ResultExecutingContext(
|
return new ResultExecutingContext(
|
||||||
CreateActionContext(),
|
CreateActionContext(),
|
||||||
new IFilter[] { filter, },
|
new IFilter[] { filter, },
|
||||||
new ObjectResult("Some Value"));
|
new ObjectResult("Some Value"),
|
||||||
|
controller: new object());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionContext CreateActionContext()
|
private static ActionContext CreateActionContext()
|
||||||
|
|
|
||||||
|
|
@ -190,12 +190,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
})
|
})
|
||||||
.Returns(Task.FromResult(result: false));
|
.Returns(Task.FromResult(result: false));
|
||||||
|
|
||||||
var actionContext = new ActionContext(
|
var actionContext = new ActionContext(new RouteContext(Mock.Of<HttpContext>()), actionDescriptor);
|
||||||
new RouteContext(Mock.Of<HttpContext>()),
|
|
||||||
actionDescriptor)
|
|
||||||
{
|
|
||||||
Controller = Mock.Of<object>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
var actionBindingContext = new ActionBindingContext()
|
var actionBindingContext = new ActionBindingContext()
|
||||||
{
|
{
|
||||||
|
|
@ -243,12 +238,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
})
|
})
|
||||||
.Returns(Task.FromResult(result: true));
|
.Returns(Task.FromResult(result: true));
|
||||||
|
|
||||||
var actionContext = new ActionContext(
|
var actionContext = new ActionContext(new RouteContext(Mock.Of<HttpContext>()), actionDescriptor);
|
||||||
new RouteContext(Mock.Of<HttpContext>()),
|
|
||||||
actionDescriptor)
|
|
||||||
{
|
|
||||||
Controller = Mock.Of<object>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
var actionBindingContext = new ActionBindingContext()
|
var actionBindingContext = new ActionBindingContext()
|
||||||
{
|
{
|
||||||
|
|
@ -303,12 +293,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
})
|
})
|
||||||
.Returns(Task.FromResult(result: true));
|
.Returns(Task.FromResult(result: true));
|
||||||
|
|
||||||
var actionContext = new ActionContext(
|
var actionContext = new ActionContext(new RouteContext(Mock.Of<HttpContext>()), actionDescriptor);
|
||||||
new RouteContext(Mock.Of<HttpContext>()),
|
|
||||||
actionDescriptor)
|
|
||||||
{
|
|
||||||
Controller = Mock.Of<object>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
var actionBindingContext = new ActionBindingContext()
|
var actionBindingContext = new ActionBindingContext()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return new ActionExecutingContext(
|
return new ActionExecutingContext(
|
||||||
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()),
|
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()),
|
||||||
filters ?? new List<IFilter>(),
|
filters ?? new List<IFilter>(),
|
||||||
new Dictionary<string, object>());
|
new Dictionary<string, object>(),
|
||||||
|
new object());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -34,12 +34,17 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var filter = new HttpResponseExceptionActionFilter();
|
var filter = new HttpResponseExceptionActionFilter();
|
||||||
var context = new ActionExecutingContext(new ActionContext(
|
|
||||||
new DefaultHttpContext(),
|
var actionContext = new ActionContext(
|
||||||
new RouteData(),
|
new DefaultHttpContext(),
|
||||||
actionDescriptor: Mock.Of<ActionDescriptor>()),
|
new RouteData(),
|
||||||
filters: Mock.Of<IList<IFilter>>(),
|
Mock.Of<ActionDescriptor>());
|
||||||
actionArguments: new Dictionary<string, object>());
|
|
||||||
|
var context = new ActionExecutingContext(
|
||||||
|
actionContext,
|
||||||
|
filters: new List<IFilter>(),
|
||||||
|
actionArguments: new Dictionary<string, object>(),
|
||||||
|
controller: new object());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
filter.OnActionExecuting(context);
|
filter.OnActionExecuting(context);
|
||||||
|
|
@ -56,12 +61,16 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
httpContext.Request.Method = "GET";
|
httpContext.Request.Method = "GET";
|
||||||
|
|
||||||
|
var actionContext = new ActionContext(
|
||||||
|
httpContext,
|
||||||
|
new RouteData(),
|
||||||
|
Mock.Of<ActionDescriptor>());
|
||||||
|
|
||||||
var context = new ActionExecutedContext(
|
var context = new ActionExecutedContext(
|
||||||
new ActionContext(
|
actionContext,
|
||||||
httpContext,
|
filters: new List<IFilter>(),
|
||||||
new RouteData(),
|
controller: new object());
|
||||||
actionDescriptor: Mock.Of<ActionDescriptor>()),
|
|
||||||
filters: null);
|
|
||||||
context.Exception = new HttpResponseException(HttpStatusCode.BadRequest);
|
context.Exception = new HttpResponseException(HttpStatusCode.BadRequest);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue