Replace ActionBindingContext with ControllerContext

This change introduces ControllerContext for inside of Controllers, and
controller-specific extensibility points. ControllerContext carries with
it the model binding infrastructure needed to do all of the things that
controllers need to do.
This commit is contained in:
Ryan Nowak 2015-11-11 09:36:03 -08:00
parent 62978229c4
commit 8682fe0cfd
72 changed files with 730 additions and 1034 deletions

View File

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14 # Visual Studio 14
VisualStudioVersion = 14.0.23107.0 VisualStudioVersion = 14.0.24711.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject EndProject

View File

@ -58,7 +58,7 @@ namespace MvcSample.Web
public bool IsDefaultNameSpace() public bool IsDefaultNameSpace()
{ {
var namespaceToken = ActionContext.RouteData.DataTokens["NameSpace"] as string; var namespaceToken = RouteData.DataTokens["NameSpace"] as string;
return namespaceToken == "default"; return namespaceToken == "default";
} }

View File

@ -19,7 +19,7 @@ namespace MvcSample.Web
public string GetOtherThing() public string GetOtherThing()
{ {
// Will be GetOtherThing // Will be GetOtherThing
return (string)ActionContext.RouteData.Values["action"]; return (string)RouteData.Values["action"];
} }
[HttpGet("Link")] [HttpGet("Link")]

View File

@ -29,11 +29,6 @@ namespace Microsoft.AspNet.Mvc.Filters
/// </summary> /// </summary>
public virtual FormatterCollection<IInputFormatter> InputFormatters { get; set; } public virtual FormatterCollection<IInputFormatter> InputFormatters { get; set; }
/// <summary>
/// Gets or sets the list of <see cref="IOutputFormatter"/> instances used to format the response.
/// </summary>
public virtual FormatterCollection<IOutputFormatter> OutputFormatters { get; set; }
/// <summary> /// <summary>
/// Gets or sets the list of <see cref="IModelBinder"/> instances used by model binding. /// Gets or sets the list of <see cref="IModelBinder"/> instances used by model binding.
/// </summary> /// </summary>

View File

@ -10,10 +10,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// <summary> /// <summary>
/// Gets a <see cref="IValueProvider"/> with values from the current request. /// Gets a <see cref="IValueProvider"/> with values from the current request.
/// </summary> /// </summary>
/// <param name="context">The <see cref="ValueProviderFactoryContext"/>.</param> /// <param name="context">The <see cref="ActionContext"/>.</param>
/// <returns> /// <returns>
/// A <see cref="Task"/> that when completed will yield a <see cref="IValueProvider"/> instance or <c>null</c>. /// A <see cref="Task"/> that when completed will yield a <see cref="IValueProvider"/> instance or <c>null</c>.
/// </returns> /// </returns>
Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context); Task<IValueProvider> GetValueProviderAsync(ActionContext context);
} }
} }

View File

@ -1,34 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class ValueProviderFactoryContext
{
public ValueProviderFactoryContext(
HttpContext httpContext,
IDictionary<string, object> routeValues)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (routeValues == null)
{
throw new ArgumentNullException(nameof(routeValues));
}
HttpContext = httpContext;
RouteValues = routeValues;
}
public HttpContext HttpContext { get; private set; }
public IDictionary<string, object> RouteValues { get; private set; }
}
}

View File

@ -1,23 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
namespace Microsoft.AspNet.Mvc
{
public class ActionBindingContext
{
public IModelBinder ModelBinder { get; set; }
public IValueProvider ValueProvider { get; set; }
public IList<IInputFormatter> InputFormatters { get; set; }
public IList<IOutputFormatter> OutputFormatters { get; set; }
public IModelValidatorProvider ValidatorProvider { get; set; }
}
}

View File

@ -0,0 +1,159 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc.Controllers;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// The context associated with the current request for a controller.
/// </summary>
public class ControllerContext : ActionContext
{
private FormatterCollection<IInputFormatter> _inputFormatters;
private IList<IModelBinder> _modelBinders;
private IList<IModelValidatorProvider> _validatorProviders;
private IList<IValueProvider> _valueProviders;
/// <summary>
/// Creates a new <see cref="ControllerContext"/>.
/// </summary>
/// <remarks>
/// The default constructor is provided for unit test purposes only.
/// </remarks>
public ControllerContext()
: base()
{
}
/// <summary>
/// Creates a new <see cref="ControllerContext"/>.
/// </summary>
/// <param name="context">The <see cref="ActionContext"/> associated with the current request.</param>
public ControllerContext(ActionContext context)
: base(context)
{
if (!(context.ActionDescriptor is ControllerActionDescriptor))
{
throw new ArgumentException(Resources.FormatActionDescriptorMustBeBasedOnControllerAction(
typeof(ControllerActionDescriptor)),
nameof(context));
}
}
/// <summary>
/// Gets or sets the <see cref="ControllerActionDescriptor"/> associated with the current request.
/// </summary>
public new ControllerActionDescriptor ActionDescriptor
{
get { return (ControllerActionDescriptor)base.ActionDescriptor; }
set { base.ActionDescriptor = value; }
}
/// <summary>
/// Gets or sets the list of <see cref="IInputFormatter"/> instances for the current request.
/// </summary>
public virtual FormatterCollection<IInputFormatter> InputFormatters
{
get
{
if (_inputFormatters == null)
{
_inputFormatters = new FormatterCollection<IInputFormatter>();
}
return _inputFormatters;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_inputFormatters = value;
}
}
/// <summary>
/// Gets or sets the list of <see cref="IModelBinder"/> instances for the current request.
/// </summary>
public virtual IList<IModelBinder> ModelBinders
{
get
{
if (_modelBinders == null)
{
_modelBinders = new List<IModelBinder>();
}
return _modelBinders;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_modelBinders = value;
}
}
/// <summary>
/// Gets or sets the list of <see cref="IModelValidatorProvider"/> instances for the current request.
/// </summary>
public virtual IList<IModelValidatorProvider> ValidatorProviders
{
get
{
if (_validatorProviders == null)
{
_validatorProviders = new List<IModelValidatorProvider>();
}
return _validatorProviders;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_validatorProviders = value;
}
}
/// <summary>
/// Gets or sets the list of <see cref="IValueProvider"/> instances for the current request.
/// </summary>
public virtual IList<IValueProvider> ValueProviders
{
get
{
if (_valueProviders == null)
{
_valueProviders = new List<IValueProvider>();
}
return _valueProviders;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_valueProviders = value;
}
}
}
}

View File

@ -7,11 +7,11 @@ namespace Microsoft.AspNet.Mvc
{ {
/// <summary> /// <summary>
/// Specifies that a controller property should be set with the current /// Specifies that a controller property should be set with the current
/// <see cref="ActionBindingContext"/> when creating the controller. The property must have a public /// <see cref="ControllerContext"/> when creating the controller. The property must have a public
/// set method. /// set method.
/// </summary> /// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class ActionBindingContextAttribute : Attribute public class ControllerContextAttribute : Attribute
{ {
} }
} }

View File

@ -9,7 +9,6 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Mvc.Formatters; using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Logging; using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.ModelBinding.Validation;
@ -30,12 +29,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
IControllerFactory controllerFactory, IControllerFactory controllerFactory,
ControllerActionDescriptor descriptor, ControllerActionDescriptor descriptor,
IReadOnlyList<IInputFormatter> inputFormatters, IReadOnlyList<IInputFormatter> inputFormatters,
IReadOnlyList<IOutputFormatter> outputFormatters,
IControllerActionArgumentBinder controllerActionArgumentBinder, IControllerActionArgumentBinder controllerActionArgumentBinder,
IReadOnlyList<IModelBinder> modelBinders, IReadOnlyList<IModelBinder> modelBinders,
IReadOnlyList<IModelValidatorProvider> modelValidatorProviders, IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
IReadOnlyList<IValueProviderFactory> valueProviderFactories, IReadOnlyList<IValueProviderFactory> valueProviderFactories,
IActionBindingContextAccessor actionBindingContextAccessor,
ILogger logger, ILogger logger,
DiagnosticSource diagnosticSource, DiagnosticSource diagnosticSource,
int maxModelValidationErrors) int maxModelValidationErrors)
@ -43,11 +40,9 @@ namespace Microsoft.AspNet.Mvc.Controllers
actionContext, actionContext,
filterProviders, filterProviders,
inputFormatters, inputFormatters,
outputFormatters,
modelBinders, modelBinders,
modelValidatorProviders, modelValidatorProviders,
valueProviderFactories, valueProviderFactories,
actionBindingContextAccessor,
logger, logger,
diagnosticSource, diagnosticSource,
maxModelValidationErrors) maxModelValidationErrors)
@ -77,11 +72,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(inputFormatters)); throw new ArgumentNullException(nameof(inputFormatters));
} }
if (outputFormatters == null)
{
throw new ArgumentNullException(nameof(outputFormatters));
}
if (controllerActionArgumentBinder == null) if (controllerActionArgumentBinder == null)
{ {
throw new ArgumentNullException(nameof(controllerActionArgumentBinder)); throw new ArgumentNullException(nameof(controllerActionArgumentBinder));
@ -102,11 +92,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(valueProviderFactories)); throw new ArgumentNullException(nameof(valueProviderFactories));
} }
if (actionBindingContextAccessor == null)
{
throw new ArgumentNullException(nameof(actionBindingContextAccessor));
}
if (logger == null) if (logger == null)
{ {
throw new ArgumentNullException(nameof(logger)); throw new ArgumentNullException(nameof(logger));
@ -132,9 +117,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
protected override object CreateInstance() protected override object CreateInstance()
{ {
// The binding context is used in activation return _controllerFactory.CreateController(Context);
Debug.Assert(ActionBindingContext != null);
return _controllerFactory.CreateController(ActionContext);
} }
protected override void ReleaseInstance(object instance) protected override void ReleaseInstance(object instance)
@ -165,21 +148,9 @@ namespace Microsoft.AspNet.Mvc.Controllers
return actionResult; return actionResult;
} }
protected override Task<IDictionary<string, object>> BindActionArgumentsAsync( protected override Task<IDictionary<string, object>> BindActionArgumentsAsync()
ActionContext context,
ActionBindingContext bindingContext)
{ {
if (context == null) return _argumentBinder.BindActionArgumentsAsync(Context, Instance);
{
throw new ArgumentNullException(nameof(context));
}
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
return _argumentBinder.BindActionArgumentsAsync(context, bindingContext, Instance);
} }
// Marking as internal for Unit Testing purposes. // Marking as internal for Unit Testing purposes.

View File

@ -8,7 +8,6 @@ using System.Linq;
using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Mvc.Formatters; using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -23,10 +22,8 @@ namespace Microsoft.AspNet.Mvc.Controllers
private readonly IFilterProvider[] _filterProviders; private readonly IFilterProvider[] _filterProviders;
private readonly IReadOnlyList<IInputFormatter> _inputFormatters; private readonly IReadOnlyList<IInputFormatter> _inputFormatters;
private readonly IReadOnlyList<IModelBinder> _modelBinders; private readonly IReadOnlyList<IModelBinder> _modelBinders;
private readonly IReadOnlyList<IOutputFormatter> _outputFormatters;
private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders; private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders;
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories; private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
private readonly IActionBindingContextAccessor _actionBindingContextAccessor;
private readonly int _maxModelValidationErrors; private readonly int _maxModelValidationErrors;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly DiagnosticSource _diagnosticSource; private readonly DiagnosticSource _diagnosticSource;
@ -36,7 +33,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
IEnumerable<IFilterProvider> filterProviders, IEnumerable<IFilterProvider> filterProviders,
IControllerActionArgumentBinder argumentBinder, IControllerActionArgumentBinder argumentBinder,
IOptions<MvcOptions> optionsAccessor, IOptions<MvcOptions> optionsAccessor,
IActionBindingContextAccessor actionBindingContextAccessor,
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
DiagnosticSource diagnosticSource) DiagnosticSource diagnosticSource)
{ {
@ -44,11 +40,9 @@ namespace Microsoft.AspNet.Mvc.Controllers
_filterProviders = filterProviders.OrderBy(item => item.Order).ToArray(); _filterProviders = filterProviders.OrderBy(item => item.Order).ToArray();
_argumentBinder = argumentBinder; _argumentBinder = argumentBinder;
_inputFormatters = optionsAccessor.Value.InputFormatters.ToArray(); _inputFormatters = optionsAccessor.Value.InputFormatters.ToArray();
_outputFormatters = optionsAccessor.Value.OutputFormatters.ToArray();
_modelBinders = optionsAccessor.Value.ModelBinders.ToArray(); _modelBinders = optionsAccessor.Value.ModelBinders.ToArray();
_modelValidatorProviders = optionsAccessor.Value.ModelValidatorProviders.ToArray(); _modelValidatorProviders = optionsAccessor.Value.ModelValidatorProviders.ToArray();
_valueProviderFactories = optionsAccessor.Value.ValueProviderFactories.ToArray(); _valueProviderFactories = optionsAccessor.Value.ValueProviderFactories.ToArray();
_actionBindingContextAccessor = actionBindingContextAccessor;
_maxModelValidationErrors = optionsAccessor.Value.MaxModelValidationErrors; _maxModelValidationErrors = optionsAccessor.Value.MaxModelValidationErrors;
_logger = loggerFactory.CreateLogger<ControllerActionInvoker>(); _logger = loggerFactory.CreateLogger<ControllerActionInvoker>();
_diagnosticSource = diagnosticSource; _diagnosticSource = diagnosticSource;
@ -77,12 +71,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
_controllerFactory, _controllerFactory,
actionDescriptor, actionDescriptor,
_inputFormatters, _inputFormatters,
_outputFormatters,
_argumentBinder, _argumentBinder,
_modelBinders, _modelBinders,
_modelValidatorProviders, _modelValidatorProviders,
_valueProviderFactories, _valueProviderFactories,
_actionBindingContextAccessor,
_logger, _logger,
_diagnosticSource, _diagnosticSource,
_maxModelValidationErrors); _maxModelValidationErrors);

View File

@ -36,18 +36,12 @@ namespace Microsoft.AspNet.Mvc.Controllers
} }
public Task<IDictionary<string, object>> BindActionArgumentsAsync( public Task<IDictionary<string, object>> BindActionArgumentsAsync(
ActionContext actionContext, ControllerContext context,
ActionBindingContext actionBindingContext,
object controller) object controller)
{ {
if (actionContext == null) if (context == null)
{ {
throw new ArgumentNullException(nameof(actionContext)); throw new ArgumentNullException(nameof(context));
}
if (actionBindingContext == null)
{
throw new ArgumentNullException(nameof(actionBindingContext));
} }
if (controller == null) if (controller == null)
@ -55,16 +49,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(controller)); throw new ArgumentNullException(nameof(controller));
} }
var actionDescriptor = actionContext.ActionDescriptor as ControllerActionDescriptor; if (context.ActionDescriptor == null)
if (actionDescriptor == null)
{ {
throw new ArgumentException( throw new ArgumentException(Resources.FormatPropertyOfTypeCannotBeNull(
Resources.FormatActionDescriptorMustBeBasedOnControllerAction( nameof(ControllerContext.ActionDescriptor),
typeof(ControllerActionDescriptor)), nameof(ControllerContext)));
nameof(actionContext));
} }
// Perf: Avoid allocating async state machines when we know there's nothing to bind. // Perf: Avoid allocating async state machines when we know there's nothing to bind.
var actionDescriptor = context.ActionDescriptor;
if (actionDescriptor.BoundProperties.Count == 0 && if (actionDescriptor.BoundProperties.Count == 0 &&
actionDescriptor.Parameters.Count == 0) actionDescriptor.Parameters.Count == 0)
{ {
@ -74,24 +67,22 @@ namespace Microsoft.AspNet.Mvc.Controllers
else else
{ {
return BindActionArgumentsCoreAsync( return BindActionArgumentsCoreAsync(
actionContext, context,
actionBindingContext,
controller, controller,
actionDescriptor); actionDescriptor);
} }
} }
private async Task<IDictionary<string, object>> BindActionArgumentsCoreAsync( private async Task<IDictionary<string, object>> BindActionArgumentsCoreAsync(
ActionContext actionContext, ControllerContext context,
ActionBindingContext actionBindingContext,
object controller, object controller,
ControllerActionDescriptor actionDescriptor) ControllerActionDescriptor actionDescriptor)
{ {
var operationBindingContext = GetOperationBindingContext(actionContext, actionBindingContext); var operationBindingContext = GetOperationBindingContext(context);
var controllerProperties = new Dictionary<string, object>(StringComparer.Ordinal); var controllerProperties = new Dictionary<string, object>(StringComparer.Ordinal);
await PopulateArgumentsAsync( await PopulateArgumentsAsync(
operationBindingContext, operationBindingContext,
actionContext.ModelState, context.ModelState,
controllerProperties, controllerProperties,
actionDescriptor.BoundProperties); actionDescriptor.BoundProperties);
var controllerType = actionDescriptor.ControllerTypeInfo.AsType(); var controllerType = actionDescriptor.ControllerTypeInfo.AsType();
@ -100,7 +91,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
var actionArguments = new Dictionary<string, object>(StringComparer.Ordinal); var actionArguments = new Dictionary<string, object>(StringComparer.Ordinal);
await PopulateArgumentsAsync( await PopulateArgumentsAsync(
operationBindingContext, operationBindingContext,
actionContext.ModelState, context.ModelState,
actionArguments, actionArguments,
actionDescriptor.Parameters); actionDescriptor.Parameters);
return actionArguments; return actionArguments;
@ -229,18 +220,16 @@ namespace Microsoft.AspNet.Mvc.Controllers
} }
} }
private OperationBindingContext GetOperationBindingContext( private OperationBindingContext GetOperationBindingContext(ControllerContext context)
ActionContext actionContext,
ActionBindingContext bindingContext)
{ {
return new OperationBindingContext return new OperationBindingContext
{ {
InputFormatters = bindingContext.InputFormatters, InputFormatters = context.InputFormatters,
ModelBinder = bindingContext.ModelBinder, ModelBinder = new CompositeModelBinder(context.ModelBinders),
ValidatorProvider = bindingContext.ValidatorProvider, ValidatorProvider = new CompositeModelValidatorProvider(context.ValidatorProviders),
MetadataProvider = _modelMetadataProvider, MetadataProvider = _modelMetadataProvider,
HttpContext = actionContext.HttpContext, HttpContext = context.HttpContext,
ValueProvider = bindingContext.ValueProvider, ValueProvider = new CompositeValueProvider(context.ValueProviders),
}; };
} }
} }

View File

@ -47,23 +47,21 @@ namespace Microsoft.AspNet.Mvc.Controllers
} }
/// <inheritdoc /> /// <inheritdoc />
public virtual object CreateController(ActionContext actionContext) public virtual object CreateController(ControllerContext context)
{ {
if (actionContext == null) if (context == null)
{ {
throw new ArgumentNullException(nameof(actionContext)); throw new ArgumentNullException(nameof(context));
} }
var actionDescriptor = actionContext.ActionDescriptor as ControllerActionDescriptor; if (context.ActionDescriptor == null)
if (actionDescriptor == null)
{ {
throw new ArgumentException( throw new ArgumentException(Resources.FormatPropertyOfTypeCannotBeNull(
Resources.FormatActionDescriptorMustBeBasedOnControllerAction( nameof(ControllerContext.ActionDescriptor),
typeof(ControllerActionDescriptor)), nameof(ControllerContext)));
nameof(actionContext));
} }
var controllerType = actionDescriptor.ControllerTypeInfo.AsType(); var controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();
var controllerTypeInfo = controllerType.GetTypeInfo(); var controllerTypeInfo = controllerType.GetTypeInfo();
if (controllerTypeInfo.IsValueType || if (controllerTypeInfo.IsValueType ||
controllerTypeInfo.IsInterface || controllerTypeInfo.IsInterface ||
@ -71,14 +69,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
(controllerTypeInfo.IsGenericType && controllerTypeInfo.IsGenericTypeDefinition)) (controllerTypeInfo.IsGenericType && controllerTypeInfo.IsGenericTypeDefinition))
{ {
var message = Resources.FormatValueInterfaceAbstractOrOpenGenericTypesCannotBeActivated( var message = Resources.FormatValueInterfaceAbstractOrOpenGenericTypesCannotBeActivated(
controllerType.FullName, GetType().FullName); controllerType.FullName,
GetType().FullName);
throw new InvalidOperationException(message); throw new InvalidOperationException(message);
} }
var controller = _controllerActivator.Create(actionContext, controllerType); var controller = _controllerActivator.Create(context, controllerType);
foreach (var propertyActivator in _propertyActivators) foreach (var propertyActivator in _propertyActivators)
{ {
propertyActivator.Activate(actionContext, controller); propertyActivator.Activate(context, controller);
} }
return controller; return controller;

View File

@ -12,58 +12,43 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
public class DefaultControllerPropertyActivator : IControllerPropertyActivator public class DefaultControllerPropertyActivator : IControllerPropertyActivator
{ {
private readonly IActionBindingContextAccessor _actionBindingContextAccessor; private readonly ConcurrentDictionary<Type, PropertyActivator<ControllerContext>[]> _activateActions;
private readonly ConcurrentDictionary<Type, PropertyActivator<Contexts>[]> _activateActions; private readonly Func<Type, PropertyActivator<ControllerContext>[]> _getPropertiesToActivate;
private readonly Func<Type, PropertyActivator<Contexts>[]> _getPropertiesToActivate;
public DefaultControllerPropertyActivator(IActionBindingContextAccessor actionBindingContextAccessor) public DefaultControllerPropertyActivator()
{ {
_actionBindingContextAccessor = actionBindingContextAccessor; _activateActions = new ConcurrentDictionary<Type, PropertyActivator<ControllerContext>[]>();
_activateActions = new ConcurrentDictionary<Type, PropertyActivator<Contexts>[]>();
_getPropertiesToActivate = GetPropertiesToActivate; _getPropertiesToActivate = GetPropertiesToActivate;
} }
public void Activate(ActionContext actionContext, object controller) public void Activate(ControllerContext context, object controller)
{ {
var controllerType = controller.GetType(); var controllerType = controller.GetType();
var propertiesToActivate = _activateActions.GetOrAdd( var propertiesToActivate = _activateActions.GetOrAdd(
controllerType, controllerType,
_getPropertiesToActivate); _getPropertiesToActivate);
var contexts = new Contexts()
{
ActionBindingContext = _actionBindingContextAccessor.ActionBindingContext,
ActionContext = actionContext,
};
for (var i = 0; i < propertiesToActivate.Length; i++) for (var i = 0; i < propertiesToActivate.Length; i++)
{ {
var activateInfo = propertiesToActivate[i]; var activateInfo = propertiesToActivate[i];
activateInfo.Activate(controller, contexts); activateInfo.Activate(controller, context);
} }
} }
private PropertyActivator<Contexts>[] GetPropertiesToActivate(Type type) private PropertyActivator<ControllerContext>[] GetPropertiesToActivate(Type type)
{ {
IEnumerable<PropertyActivator<Contexts>> activators; IEnumerable<PropertyActivator<ControllerContext>> activators;
activators = PropertyActivator<Contexts>.GetPropertiesToActivate( activators = PropertyActivator<ControllerContext>.GetPropertiesToActivate(
type, type,
typeof(ActionContextAttribute), typeof(ActionContextAttribute),
p => new PropertyActivator<Contexts>(p, c => c.ActionContext)); p => new PropertyActivator<ControllerContext>(p, c => c));
activators = activators.Concat(PropertyActivator<Contexts>.GetPropertiesToActivate( activators = activators.Concat(PropertyActivator<ControllerContext>.GetPropertiesToActivate(
type, type,
typeof(ActionBindingContextAttribute), typeof(ControllerContextAttribute),
p => new PropertyActivator<Contexts>(p, c => c.ActionBindingContext))); p => new PropertyActivator<ControllerContext>(p, c => c)));
return activators.ToArray(); return activators.ToArray();
} }
private struct Contexts
{
public ActionBindingContext ActionBindingContext;
public ActionContext ActionContext;
}
} }
} }

View File

@ -11,7 +11,6 @@ using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Diagnostics; using Microsoft.AspNet.Mvc.Diagnostics;
using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Mvc.Formatters; using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Internal; using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.Logging; using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -27,10 +26,8 @@ namespace Microsoft.AspNet.Mvc.Controllers
private readonly IReadOnlyList<IFilterProvider> _filterProviders; private readonly IReadOnlyList<IFilterProvider> _filterProviders;
private readonly IReadOnlyList<IInputFormatter> _inputFormatters; private readonly IReadOnlyList<IInputFormatter> _inputFormatters;
private readonly IReadOnlyList<IModelBinder> _modelBinders; private readonly IReadOnlyList<IModelBinder> _modelBinders;
private readonly IReadOnlyList<IOutputFormatter> _outputFormatters;
private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders; private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders;
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories; private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
private readonly IActionBindingContextAccessor _actionBindingContextAccessor;
private readonly DiagnosticSource _diagnosticSource; private readonly DiagnosticSource _diagnosticSource;
private readonly int _maxModelValidationErrors; private readonly int _maxModelValidationErrors;
@ -54,11 +51,9 @@ namespace Microsoft.AspNet.Mvc.Controllers
ActionContext actionContext, ActionContext actionContext,
IReadOnlyList<IFilterProvider> filterProviders, IReadOnlyList<IFilterProvider> filterProviders,
IReadOnlyList<IInputFormatter> inputFormatters, IReadOnlyList<IInputFormatter> inputFormatters,
IReadOnlyList<IOutputFormatter> outputFormatters,
IReadOnlyList<IModelBinder> modelBinders, IReadOnlyList<IModelBinder> modelBinders,
IReadOnlyList<IModelValidatorProvider> modelValidatorProviders, IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
IReadOnlyList<IValueProviderFactory> valueProviderFactories, IReadOnlyList<IValueProviderFactory> valueProviderFactories,
IActionBindingContextAccessor actionBindingContextAccessor,
ILogger logger, ILogger logger,
DiagnosticSource diagnosticSource, DiagnosticSource diagnosticSource,
int maxModelValidationErrors) int maxModelValidationErrors)
@ -78,11 +73,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(inputFormatters)); throw new ArgumentNullException(nameof(inputFormatters));
} }
if (outputFormatters == null)
{
throw new ArgumentNullException(nameof(outputFormatters));
}
if (modelBinders == null) if (modelBinders == null)
{ {
throw new ArgumentNullException(nameof(modelBinders)); throw new ArgumentNullException(nameof(modelBinders));
@ -98,11 +88,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(valueProviderFactories)); throw new ArgumentNullException(nameof(valueProviderFactories));
} }
if (actionBindingContextAccessor == null)
{
throw new ArgumentNullException(nameof(actionBindingContextAccessor));
}
if (logger == null) if (logger == null)
{ {
throw new ArgumentNullException(nameof(logger)); throw new ArgumentNullException(nameof(logger));
@ -113,33 +98,19 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(diagnosticSource)); throw new ArgumentNullException(nameof(diagnosticSource));
} }
ActionContext = actionContext; Context = new ControllerContext(actionContext);
_filterProviders = filterProviders; _filterProviders = filterProviders;
_inputFormatters = inputFormatters; _inputFormatters = inputFormatters;
_outputFormatters = outputFormatters;
_modelBinders = modelBinders; _modelBinders = modelBinders;
_modelValidatorProviders = modelValidatorProviders; _modelValidatorProviders = modelValidatorProviders;
_valueProviderFactories = valueProviderFactories; _valueProviderFactories = valueProviderFactories;
_actionBindingContextAccessor = actionBindingContextAccessor;
Logger = logger; Logger = logger;
_diagnosticSource = diagnosticSource; _diagnosticSource = diagnosticSource;
_maxModelValidationErrors = maxModelValidationErrors; _maxModelValidationErrors = maxModelValidationErrors;
} }
protected ActionContext ActionContext { get; private set; } protected ControllerContext Context { get; }
protected ActionBindingContext ActionBindingContext
{
get
{
return _actionBindingContextAccessor.ActionBindingContext;
}
private set
{
_actionBindingContextAccessor.ActionBindingContext = value;
}
}
protected object Instance { get; private set; } protected object Instance { get; private set; }
@ -160,16 +131,14 @@ namespace Microsoft.AspNet.Mvc.Controllers
protected abstract Task<IActionResult> InvokeActionAsync(ActionExecutingContext actionExecutingContext); protected abstract Task<IActionResult> InvokeActionAsync(ActionExecutingContext actionExecutingContext);
protected abstract Task<IDictionary<string, object>> BindActionArgumentsAsync( protected abstract Task<IDictionary<string, object>> BindActionArgumentsAsync();
ActionContext context,
ActionBindingContext bindingContext);
public virtual async Task InvokeAsync() public virtual async Task InvokeAsync()
{ {
_filters = GetFilters(); _filters = GetFilters();
_cursor = new FilterCursor(_filters); _cursor = new FilterCursor(_filters);
ActionContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors; Context.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
await InvokeAllAuthorizationFiltersAsync(); await InvokeAllAuthorizationFiltersAsync();
@ -215,14 +184,14 @@ namespace Microsoft.AspNet.Mvc.Controllers
private IFilterMetadata[] GetFilters() private IFilterMetadata[] GetFilters()
{ {
var filterDescriptors = ActionContext.ActionDescriptor.FilterDescriptors; var filterDescriptors = Context.ActionDescriptor.FilterDescriptors;
var items = new List<FilterItem>(filterDescriptors.Count); var items = new List<FilterItem>(filterDescriptors.Count);
for (var i = 0; i < filterDescriptors.Count; i++) for (var i = 0; i < filterDescriptors.Count; i++)
{ {
items.Add(new FilterItem(filterDescriptors[i])); items.Add(new FilterItem(filterDescriptors[i]));
} }
var context = new FilterProviderContext(ActionContext, items); var context = new FilterProviderContext(Context, items);
for (var i = 0; i < _filterProviders.Count; i++) for (var i = 0; i < _filterProviders.Count; i++)
{ {
_filterProviders[i].OnProvidersExecuting(context); _filterProviders[i].OnProvidersExecuting(context);
@ -266,7 +235,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
_cursor.Reset(); _cursor.Reset();
_authorizationContext = new AuthorizationContext(ActionContext, _filters); _authorizationContext = new AuthorizationContext(Context, _filters);
return InvokeAuthorizationFilterAsync(); return InvokeAuthorizationFilterAsync();
} }
@ -332,12 +301,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
_cursor.Reset(); _cursor.Reset();
var context = new ResourceExecutingContext(ActionContext, _filters); var context = new ResourceExecutingContext(Context, _filters);
context.InputFormatters = new FormatterCollection<IInputFormatter>( context.InputFormatters = new FormatterCollection<IInputFormatter>(
new CopyOnWriteList<IInputFormatter>(_inputFormatters)); new CopyOnWriteList<IInputFormatter>(_inputFormatters));
context.OutputFormatters = new FormatterCollection<IOutputFormatter>(
new CopyOnWriteList<IOutputFormatter>(_outputFormatters));
context.ModelBinders = new CopyOnWriteList<IModelBinder>(_modelBinders); context.ModelBinders = new CopyOnWriteList<IModelBinder>(_modelBinders);
context.ValidatorProviders = new CopyOnWriteList<IModelValidatorProvider>(_modelValidatorProviders); context.ValidatorProviders = new CopyOnWriteList<IModelValidatorProvider>(_modelValidatorProviders);
context.ValueProviderFactories = new CopyOnWriteList<IValueProviderFactory>(_valueProviderFactories); context.ValueProviderFactories = new CopyOnWriteList<IValueProviderFactory>(_valueProviderFactories);
@ -441,20 +408,22 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
// We've reached the end of resource filters, so move to setting up state to invoke model // We've reached the end of resource filters, so move to setting up state to invoke model
// binding. // binding.
ActionBindingContext = new ActionBindingContext(); Context.InputFormatters = _resourceExecutingContext.InputFormatters;
ActionBindingContext.InputFormatters = _resourceExecutingContext.InputFormatters; Context.ModelBinders = _resourceExecutingContext.ModelBinders;
ActionBindingContext.OutputFormatters = _resourceExecutingContext.OutputFormatters; Context.ValidatorProviders = _resourceExecutingContext.ValidatorProviders;
ActionBindingContext.ModelBinder = new CompositeModelBinder(_resourceExecutingContext.ModelBinders);
ActionBindingContext.ValidatorProvider = new CompositeModelValidatorProvider(
_resourceExecutingContext.ValidatorProviders);
var valueProviderFactoryContext = new ValueProviderFactoryContext( var valueProviders = new List<IValueProvider>();
ActionContext.HttpContext,
ActionContext.RouteData.Values);
ActionBindingContext.ValueProvider = await CompositeValueProvider.CreateAsync( for (var i = 0; i < _resourceExecutingContext.ValueProviderFactories.Count; i++)
_resourceExecutingContext.ValueProviderFactories, {
valueProviderFactoryContext); var factory = _resourceExecutingContext.ValueProviderFactories[i];
var valueProvider = await factory.GetValueProviderAsync(Context);
if (valueProvider != null)
{
valueProviders.Add(valueProvider);
}
}
Context.ValueProviders = valueProviders;
// >> ExceptionFilters >> Model Binding >> ActionFilters >> Action // >> ExceptionFilters >> Model Binding >> ActionFilters >> Action
await InvokeAllExceptionFiltersAsync(); await InvokeAllExceptionFiltersAsync();
@ -587,7 +556,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
// 1) Call the filter (if we have an exception) // 1) Call the filter (if we have an exception)
// 2) No-op (if we don't have an exception) // 2) No-op (if we don't have an exception)
Debug.Assert(_exceptionContext == null); Debug.Assert(_exceptionContext == null);
_exceptionContext = new ExceptionContext(ActionContext, _filters); _exceptionContext = new ExceptionContext(Context, _filters);
try try
{ {
@ -617,10 +586,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
Instance = CreateInstance(); Instance = CreateInstance();
var arguments = await BindActionArgumentsAsync(ActionContext, ActionBindingContext); var arguments = await BindActionArgumentsAsync();
_actionExecutingContext = new ActionExecutingContext( _actionExecutingContext = new ActionExecutingContext(
ActionContext, Context,
_filters, _filters,
arguments, arguments,
Instance); Instance);
@ -723,7 +692,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
try try
{ {
_diagnosticSource.BeforeActionMethod( _diagnosticSource.BeforeActionMethod(
ActionContext, Context,
_actionExecutingContext.ActionArguments, _actionExecutingContext.ActionArguments,
_actionExecutingContext.Controller); _actionExecutingContext.Controller);
@ -732,7 +701,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
finally finally
{ {
_diagnosticSource.AfterActionMethod( _diagnosticSource.AfterActionMethod(
ActionContext, Context,
_actionExecutingContext.ActionArguments, _actionExecutingContext.ActionArguments,
_actionExecutingContext.Controller, _actionExecutingContext.Controller,
result); result);
@ -765,7 +734,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
_cursor.Reset(); _cursor.Reset();
_resultExecutingContext = new ResultExecutingContext(ActionContext, _filters, result, Instance); _resultExecutingContext = new ResultExecutingContext(Context, _filters, result, Instance);
await InvokeResultFilterAsync(); await InvokeResultFilterAsync();
Debug.Assert(_resultExecutingContext != null); Debug.Assert(_resultExecutingContext != null);
@ -908,15 +877,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
private async Task InvokeResultAsync(IActionResult result) private async Task InvokeResultAsync(IActionResult result)
{ {
_diagnosticSource.BeforeActionResult(ActionContext, result); _diagnosticSource.BeforeActionResult(Context, result);
try try
{ {
await result.ExecuteResultAsync(ActionContext); await result.ExecuteResultAsync(Context);
} }
finally finally
{ {
_diagnosticSource.AfterActionResult(ActionContext, result); _diagnosticSource.AfterActionResult(Context, result);
} }
} }

View File

@ -12,16 +12,12 @@ namespace Microsoft.AspNet.Mvc.Controllers
public interface IControllerActionArgumentBinder public interface IControllerActionArgumentBinder
{ {
/// <summary> /// <summary>
/// Returns a dictionary of representing the parameter-argument name-value pairs, /// Returns a dictionary of the parameter-argument name-value pairs,
/// which can be used to invoke the action. Also binds properties explicitly marked properties on the /// which can be used to invoke the action. Also binds properties explicitly marked properties on the
/// <paramref name="controller"/>. /// <paramref name="controller"/>.
/// </summary> /// </summary>
/// <param name="context">The action context assoicated with the current action.</param> /// <param name="context">The <see cref="ControllerContext"/> associated with the current action.</param>
/// <param name="bindingContext">The <see cref="ActionBindingContext"/>.</param>
/// <param name="controller">The controller object which contains the action.</param> /// <param name="controller">The controller object which contains the action.</param>
Task<IDictionary<string, object>> BindActionArgumentsAsync( Task<IDictionary<string, object>> BindActionArgumentsAsync(ControllerContext context, object controller);
ActionContext context,
ActionBindingContext bindingContext,
object controller);
} }
} }

View File

@ -9,11 +9,11 @@ namespace Microsoft.AspNet.Mvc.Controllers
public interface IControllerFactory public interface IControllerFactory
{ {
/// <summary> /// <summary>
/// Creates a new controller for the specified <paramref name="actionContext"/>. /// Creates a new controller for the specified <paramref name="context"/>.
/// </summary> /// </summary>
/// <param name="actionContext"><see cref="ActionContext"/> for the action to execute.</param> /// <param name="context"><see cref="ControllerContext"/> for the action to execute.</param>
/// <returns>The controller.</returns> /// <returns>The controller.</returns>
object CreateController(ActionContext actionContext); object CreateController(ControllerContext context);
/// <summary> /// <summary>
/// Releases a controller instance. /// Releases a controller instance.

View File

@ -5,6 +5,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
public interface IControllerPropertyActivator public interface IControllerPropertyActivator
{ {
void Activate(ActionContext actionContext, object controller); void Activate(ControllerContext context, object controller);
} }
} }

View File

@ -139,7 +139,6 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton<ITypeActivatorCache, DefaultTypeActivatorCache>(); services.TryAddSingleton<ITypeActivatorCache, DefaultTypeActivatorCache>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>(); services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IActionBindingContextAccessor, ActionBindingContextAccessor>();
services.TryAddSingleton<IUrlHelper, UrlHelper>(); services.TryAddSingleton<IUrlHelper, UrlHelper>();
services.TryAddSingleton<IHttpRequestStreamReaderFactory, MemoryPoolHttpRequestStreamReaderFactory>(); services.TryAddSingleton<IHttpRequestStreamReaderFactory, MemoryPoolHttpRequestStreamReaderFactory>();
services.TryAddSingleton<IHttpResponseStreamWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>(); services.TryAddSingleton<IHttpResponseStreamWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>();

View File

@ -1,40 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET451
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
#else
using System.Threading;
#endif
namespace Microsoft.AspNet.Mvc.Infrastructure
{
public class ActionBindingContextAccessor : IActionBindingContextAccessor
{
#if NET451
private static string Key = typeof(ActionBindingContext).FullName;
public ActionBindingContext ActionBindingContext
{
get
{
var handle = CallContext.LogicalGetData(Key) as ObjectHandle;
return handle != null ? (ActionBindingContext)handle.Unwrap() : null;
}
set
{
CallContext.LogicalSetData(Key, new ObjectHandle(value));
}
}
#else
private readonly AsyncLocal<ActionBindingContext> _storage = new AsyncLocal<ActionBindingContext>();
public ActionBindingContext ActionBindingContext
{
get { return _storage.Value; }
set { _storage.Value = value; }
}
#endif
}
}

View File

@ -1,10 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNet.Mvc.Infrastructure
{
public interface IActionBindingContextAccessor
{
ActionBindingContext ActionBindingContext { get; set; }
}
}

View File

@ -22,17 +22,14 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
/// </summary> /// </summary>
public class ObjectResultExecutor public class ObjectResultExecutor
{ {
private readonly IActionBindingContextAccessor _bindingContextAccessor;
/// <summary> /// <summary>
/// Creates a new <see cref="ObjectResultExecutor"/>. /// Creates a new <see cref="ObjectResultExecutor"/>.
/// </summary> /// </summary>
/// <param name="options">An accessor to <see cref="MvcOptions"/>.</param> /// <param name="options">An accessor to <see cref="MvcOptions"/>.</param>
/// <param name="bindingContextAccessor">The <see cref="IActionBindingContextAccessor"/>.</param> /// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param> /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public ObjectResultExecutor( public ObjectResultExecutor(
IOptions<MvcOptions> options, IOptions<MvcOptions> options,
IActionBindingContextAccessor bindingContextAccessor,
IHttpResponseStreamWriterFactory writerFactory, IHttpResponseStreamWriterFactory writerFactory,
ILoggerFactory loggerFactory) ILoggerFactory loggerFactory)
{ {
@ -41,28 +38,16 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
throw new ArgumentNullException(nameof(options)); throw new ArgumentNullException(nameof(options));
} }
if (bindingContextAccessor == null)
{
throw new ArgumentNullException(nameof(bindingContextAccessor));
}
if (loggerFactory == null) if (loggerFactory == null)
{ {
throw new ArgumentNullException(nameof(loggerFactory)); throw new ArgumentNullException(nameof(loggerFactory));
} }
_bindingContextAccessor = bindingContextAccessor;
OptionsFormatters = options.Value.OutputFormatters; OptionsFormatters = options.Value.OutputFormatters;
RespectBrowserAcceptHeader = options.Value.RespectBrowserAcceptHeader; RespectBrowserAcceptHeader = options.Value.RespectBrowserAcceptHeader;
Logger = loggerFactory.CreateLogger<ObjectResultExecutor>(); Logger = loggerFactory.CreateLogger<ObjectResultExecutor>();
WriterFactory = writerFactory.CreateWriter; WriterFactory = writerFactory.CreateWriter;
} }
/// <summary>
/// Gets the <see cref="ActionBindingContext"/> for the current request.
/// </summary>
protected ActionBindingContext BindingContext => _bindingContextAccessor.ActionBindingContext;
/// <summary> /// <summary>
/// Gets the <see cref="ILogger"/>. /// Gets the <see cref="ILogger"/>.
@ -72,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
/// <summary> /// <summary>
/// Gets the list of <see cref="IOutputFormatter"/> instances from <see cref="MvcOptions"/>. /// Gets the list of <see cref="IOutputFormatter"/> instances from <see cref="MvcOptions"/>.
/// </summary> /// </summary>
protected IList<IOutputFormatter> OptionsFormatters { get; } protected FormatterCollection<IOutputFormatter> OptionsFormatters { get; }
/// <summary> /// <summary>
/// Gets the value of <see cref="MvcOptions.RespectBrowserAcceptHeader"/>. /// Gets the value of <see cref="MvcOptions.RespectBrowserAcceptHeader"/>.
@ -109,7 +94,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
var formatters = result.Formatters; var formatters = result.Formatters;
if (formatters == null || formatters.Count == 0) if (formatters == null || formatters.Count == 0)
{ {
formatters = GetDefaultFormatters(); formatters = OptionsFormatters;
} }
var objectType = result.DeclaredType; var objectType = result.DeclaredType;
@ -506,11 +491,5 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
} }
} }
} }
// This can't be cached, because the BindingContext is per-request.
private IList<IOutputFormatter> GetDefaultFormatters()
{
return BindingContext?.OutputFormatters ?? OptionsFormatters;
}
} }
} }

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.ModelBinding namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
@ -30,48 +29,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// </summary> /// </summary>
/// <param name="valueProviders">The sequence of <see cref="IValueProvider"/> to add to this instance of /// <param name="valueProviders">The sequence of <see cref="IValueProvider"/> to add to this instance of
/// <see cref="CompositeValueProvider"/>.</param> /// <see cref="CompositeValueProvider"/>.</param>
protected CompositeValueProvider(IList<IValueProvider> valueProviders) public CompositeValueProvider(IList<IValueProvider> valueProviders)
: base(valueProviders) : base(valueProviders)
{ {
} }
/// <summary>
/// Creates a new <see cref="CompositeValueProvider"/> from the provided <paramref name="context"/>
/// and <paramref name="factories"/>.
/// </summary>
/// <param name="factories">The set of <see cref="IValueProviderFactory"/> instances.</param>
/// <param name="context">The <see cref="ValueProviderFactoryContext"/>.</param>
/// <returns>
/// A <see cref="CompositeValueProvider"/> containing all <see cref="IValueProvider"/> instances
/// created.
/// </returns>
public static async Task<CompositeValueProvider> CreateAsync(
IEnumerable<IValueProviderFactory> factories,
ValueProviderFactoryContext context)
{
if (factories == null)
{
throw new ArgumentNullException(nameof(factories));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var composite = new CompositeValueProvider();
foreach (var valueProvidersFactory in factories)
{
var valueProvider = await valueProvidersFactory.GetValueProviderAsync(context);
if (valueProvider != null)
{
composite.Add(valueProvider);
}
}
return composite;
}
/// <inheritdoc /> /// <inheritdoc />
public virtual bool ContainsPrefix(string prefix) public virtual bool ContainsPrefix(string prefix)
{ {

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
public class FormValueProviderFactory : IValueProviderFactory public class FormValueProviderFactory : IValueProviderFactory
{ {
public Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context) public Task<IValueProvider> GetValueProviderAsync(ActionContext context)
{ {
if (context == null) if (context == null)
{ {

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
public class JQueryFormValueProviderFactory : IValueProviderFactory public class JQueryFormValueProviderFactory : IValueProviderFactory
{ {
public Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context) public Task<IValueProvider> GetValueProviderAsync(ActionContext context)
{ {
if (context == null) if (context == null)
{ {

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
public class QueryStringValueProviderFactory : IValueProviderFactory public class QueryStringValueProviderFactory : IValueProviderFactory
{ {
/// <inheritdoc /> /// <inheritdoc />
public Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context) public Task<IValueProvider> GetValueProviderAsync(ActionContext context)
{ {
if (context == null) if (context == null)
{ {

View File

@ -8,7 +8,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{ {
public class RouteValueValueProviderFactory : IValueProviderFactory public class RouteValueValueProviderFactory : IValueProviderFactory
{ {
public Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context) public Task<IValueProvider> GetValueProviderAsync(ActionContext context)
{ {
if (context == null) if (context == null)
{ {
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return Task.FromResult<IValueProvider>(new DictionaryBasedValueProvider( return Task.FromResult<IValueProvider>(new DictionaryBasedValueProvider(
BindingSource.Path, BindingSource.Path,
context.RouteValues)); context.RouteData.Values));
} }
} }
} }

View File

@ -16,13 +16,13 @@ namespace Microsoft.AspNet.Mvc
public ObjectResult(object value) public ObjectResult(object value)
{ {
Value = value; Value = value;
Formatters = new List<IOutputFormatter>(); Formatters = new FormatterCollection<IOutputFormatter>();
ContentTypes = new List<MediaTypeHeaderValue>(); ContentTypes = new List<MediaTypeHeaderValue>();
} }
public object Value { get; set; } public object Value { get; set; }
public IList<IOutputFormatter> Formatters { get; set; } public FormatterCollection<IOutputFormatter> Formatters { get; set; }
public IList<MediaTypeHeaderValue> ContentTypes { get; set; } public IList<MediaTypeHeaderValue> ContentTypes { get; set; }

View File

@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc
/// </summary> /// </summary>
public abstract class Controller : IActionFilter, IAsyncActionFilter, IDisposable public abstract class Controller : IActionFilter, IAsyncActionFilter, IDisposable
{ {
private ActionContext _actionContext; private ControllerContext _controllerContext;
private IModelMetadataProvider _metadataProvider; private IModelMetadataProvider _metadataProvider;
private IObjectModelValidator _objectValidator; private IObjectModelValidator _objectValidator;
private ITempDataDictionary _tempData; private ITempDataDictionary _tempData;
@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Mvc
{ {
get get
{ {
return ActionContext?.HttpContext?.RequestServices; return HttpContext?.RequestServices;
} }
} }
@ -53,7 +53,7 @@ namespace Microsoft.AspNet.Mvc
{ {
get get
{ {
return ActionContext?.HttpContext; return ControllerContext.HttpContext;
} }
} }
@ -64,7 +64,7 @@ namespace Microsoft.AspNet.Mvc
{ {
get get
{ {
return ActionContext?.HttpContext?.Request; return HttpContext?.Request;
} }
} }
@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Mvc
{ {
get get
{ {
return ActionContext?.HttpContext?.Response; return HttpContext?.Response;
} }
} }
@ -86,7 +86,7 @@ namespace Microsoft.AspNet.Mvc
{ {
get get
{ {
return ActionContext?.RouteData; return ControllerContext.RouteData;
} }
} }
@ -102,21 +102,24 @@ namespace Microsoft.AspNet.Mvc
} }
/// <summary> /// <summary>
/// Gets or sets the <see cref="Mvc.ActionContext"/> object. /// Gets or sets the <see cref="Mvc.ControllerContext"/>.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// <see cref="Controllers.IControllerActivator"/> activates this property while activating controllers. /// <see cref="Controllers.IControllerActivator"/> activates this property while activating controllers.
/// If user code directly instantiates a controller, the getter returns an empty /// If user code directly instantiates a controller, the getter returns an empty
/// <see cref="Mvc.ActionContext"/>. /// <see cref="Mvc.ControllerContext"/>.
/// </remarks> /// </remarks>
[ActionContext] [ControllerContext]
public ActionContext ActionContext public ControllerContext ControllerContext
{ {
get get
{ {
// This should run only for the controller unit test scenarios if (_controllerContext == null)
_actionContext = _actionContext ?? new ActionContext(); {
return _actionContext; _controllerContext = new ControllerContext();
}
return _controllerContext;
} }
set set
{ {
@ -125,16 +128,10 @@ namespace Microsoft.AspNet.Mvc
throw new ArgumentNullException(nameof(value)); throw new ArgumentNullException(nameof(value));
} }
_actionContext = value; _controllerContext = value;
} }
} }
/// <summary>
/// Gets or sets the <see cref="ActionBindingContext"/>.
/// </summary>
[ActionBindingContext]
public ActionBindingContext BindingContext { get; set; }
/// <summary> /// <summary>
/// Gets or sets the <see cref="IModelMetadataProvider"/>. /// Gets or sets the <see cref="IModelMetadataProvider"/>.
/// </summary> /// </summary>
@ -237,9 +234,7 @@ namespace Microsoft.AspNet.Mvc
if (_viewData == null) if (_viewData == null)
{ {
// This should run only for the controller unit test scenarios // This should run only for the controller unit test scenarios
_viewData = _viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), ControllerContext.ModelState);
new ViewDataDictionary(new EmptyModelMetadataProvider(),
ActionContext?.ModelState ?? new ModelStateDictionary());
} }
return _viewData; return _viewData;
@ -1407,15 +1402,7 @@ namespace Microsoft.AspNet.Mvc
throw new ArgumentNullException(nameof(prefix)); throw new ArgumentNullException(nameof(prefix));
} }
if (BindingContext == null) return TryUpdateModelAsync(model, prefix, new CompositeValueProvider(ControllerContext.ValueProviders));
{
var message = Resources.FormatPropertyOfTypeCannotBeNull(
nameof(BindingContext),
typeof(Controller).FullName);
throw new InvalidOperationException(message);
}
return TryUpdateModelAsync(model, prefix, BindingContext.ValueProvider);
} }
/// <summary> /// <summary>
@ -1450,25 +1437,17 @@ namespace Microsoft.AspNet.Mvc
throw new ArgumentNullException(nameof(valueProvider)); throw new ArgumentNullException(nameof(valueProvider));
} }
if (BindingContext == null)
{
var message = Resources.FormatPropertyOfTypeCannotBeNull(
nameof(BindingContext),
typeof(Controller).FullName);
throw new InvalidOperationException(message);
}
return ModelBindingHelper.TryUpdateModelAsync( return ModelBindingHelper.TryUpdateModelAsync(
model, model,
prefix, prefix,
ActionContext.HttpContext, HttpContext,
ModelState, ModelState,
MetadataProvider, MetadataProvider,
BindingContext.ModelBinder, new CompositeModelBinder(ControllerContext.ModelBinders),
valueProvider, valueProvider,
BindingContext.InputFormatters, ControllerContext.InputFormatters,
ObjectValidator, ObjectValidator,
BindingContext.ValidatorProvider); new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders));
} }
/// <summary> /// <summary>
@ -1499,25 +1478,17 @@ namespace Microsoft.AspNet.Mvc
throw new ArgumentNullException(nameof(includeExpressions)); throw new ArgumentNullException(nameof(includeExpressions));
} }
if (BindingContext == null)
{
var message = Resources.FormatPropertyOfTypeCannotBeNull(
nameof(BindingContext),
typeof(Controller).FullName);
throw new InvalidOperationException(message);
}
return ModelBindingHelper.TryUpdateModelAsync( return ModelBindingHelper.TryUpdateModelAsync(
model, model,
prefix, prefix,
ActionContext.HttpContext, HttpContext,
ModelState, ModelState,
MetadataProvider, MetadataProvider,
BindingContext.ModelBinder, new CompositeModelBinder(ControllerContext.ModelBinders),
BindingContext.ValueProvider, new CompositeValueProvider(ControllerContext.ValueProviders),
BindingContext.InputFormatters, ControllerContext.InputFormatters,
ObjectValidator, ObjectValidator,
BindingContext.ValidatorProvider, new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders),
includeExpressions); includeExpressions);
} }
@ -1548,25 +1519,17 @@ namespace Microsoft.AspNet.Mvc
throw new ArgumentNullException(nameof(predicate)); throw new ArgumentNullException(nameof(predicate));
} }
if (BindingContext == null)
{
var message = Resources.FormatPropertyOfTypeCannotBeNull(
nameof(BindingContext),
typeof(Controller).FullName);
throw new InvalidOperationException(message);
}
return ModelBindingHelper.TryUpdateModelAsync( return ModelBindingHelper.TryUpdateModelAsync(
model, model,
prefix, prefix,
ActionContext.HttpContext, HttpContext,
ModelState, ModelState,
MetadataProvider, MetadataProvider,
BindingContext.ModelBinder, new CompositeModelBinder(ControllerContext.ModelBinders),
BindingContext.ValueProvider, new CompositeValueProvider(ControllerContext.ValueProviders),
BindingContext.InputFormatters, ControllerContext.InputFormatters,
ObjectValidator, ObjectValidator,
BindingContext.ValidatorProvider, new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders),
predicate); predicate);
} }
@ -1605,25 +1568,17 @@ namespace Microsoft.AspNet.Mvc
throw new ArgumentNullException(nameof(includeExpressions)); throw new ArgumentNullException(nameof(includeExpressions));
} }
if (BindingContext == null)
{
var message = Resources.FormatPropertyOfTypeCannotBeNull(
nameof(BindingContext),
typeof(Controller).FullName);
throw new InvalidOperationException(message);
}
return ModelBindingHelper.TryUpdateModelAsync( return ModelBindingHelper.TryUpdateModelAsync(
model, model,
prefix, prefix,
ActionContext.HttpContext, HttpContext,
ModelState, ModelState,
MetadataProvider, MetadataProvider,
BindingContext.ModelBinder, new CompositeModelBinder(ControllerContext.ModelBinders),
valueProvider, valueProvider,
BindingContext.InputFormatters, ControllerContext.InputFormatters,
ObjectValidator, ObjectValidator,
BindingContext.ValidatorProvider, new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders),
includeExpressions); includeExpressions);
} }
@ -1661,25 +1616,17 @@ namespace Microsoft.AspNet.Mvc
throw new ArgumentNullException(nameof(predicate)); throw new ArgumentNullException(nameof(predicate));
} }
if (BindingContext == null)
{
var message = Resources.FormatPropertyOfTypeCannotBeNull(
nameof(BindingContext),
typeof(Controller).FullName);
throw new InvalidOperationException(message);
}
return ModelBindingHelper.TryUpdateModelAsync( return ModelBindingHelper.TryUpdateModelAsync(
model, model,
prefix, prefix,
ActionContext.HttpContext, HttpContext,
ModelState, ModelState,
MetadataProvider, MetadataProvider,
BindingContext.ModelBinder, new CompositeModelBinder(ControllerContext.ModelBinders),
valueProvider, valueProvider,
BindingContext.InputFormatters, ControllerContext.InputFormatters,
ObjectValidator, ObjectValidator,
BindingContext.ValidatorProvider, new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders),
predicate); predicate);
} }
@ -1708,26 +1655,18 @@ namespace Microsoft.AspNet.Mvc
throw new ArgumentNullException(nameof(modelType)); throw new ArgumentNullException(nameof(modelType));
} }
if (BindingContext == null)
{
var message = Resources.FormatPropertyOfTypeCannotBeNull(
nameof(BindingContext),
typeof(Controller).FullName);
throw new InvalidOperationException(message);
}
return ModelBindingHelper.TryUpdateModelAsync( return ModelBindingHelper.TryUpdateModelAsync(
model, model,
modelType, modelType,
prefix, prefix,
ActionContext.HttpContext, HttpContext,
ModelState, ModelState,
MetadataProvider, MetadataProvider,
BindingContext.ModelBinder, new CompositeModelBinder(ControllerContext.ModelBinders),
BindingContext.ValueProvider, new CompositeValueProvider(ControllerContext.ValueProviders),
BindingContext.InputFormatters, ControllerContext.InputFormatters,
ObjectValidator, ObjectValidator,
BindingContext.ValidatorProvider); new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders));
} }
/// <summary> /// <summary>
@ -1769,26 +1708,18 @@ namespace Microsoft.AspNet.Mvc
throw new ArgumentNullException(nameof(predicate)); throw new ArgumentNullException(nameof(predicate));
} }
if (BindingContext == null)
{
var message = Resources.FormatPropertyOfTypeCannotBeNull(
nameof(BindingContext),
typeof(Controller).FullName);
throw new InvalidOperationException(message);
}
return ModelBindingHelper.TryUpdateModelAsync( return ModelBindingHelper.TryUpdateModelAsync(
model, model,
modelType, modelType,
prefix, prefix,
ActionContext.HttpContext, HttpContext,
ModelState, ModelState,
MetadataProvider, MetadataProvider,
BindingContext.ModelBinder, new CompositeModelBinder(ControllerContext.ModelBinders),
valueProvider, valueProvider,
BindingContext.InputFormatters, ControllerContext.InputFormatters,
ObjectValidator, ObjectValidator,
BindingContext.ValidatorProvider, new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders),
predicate); predicate);
} }
@ -1826,14 +1757,6 @@ namespace Microsoft.AspNet.Mvc
throw new ArgumentNullException(nameof(model)); throw new ArgumentNullException(nameof(model));
} }
if (BindingContext == null)
{
var message = Resources.FormatPropertyOfTypeCannotBeNull(
nameof(BindingContext),
typeof(Controller).FullName);
throw new InvalidOperationException(message);
}
var modelExplorer = MetadataProvider.GetModelExplorerForType(model.GetType(), model); var modelExplorer = MetadataProvider.GetModelExplorerForType(model.GetType(), model);
var modelName = prefix ?? string.Empty; var modelName = prefix ?? string.Empty;
@ -1846,7 +1769,7 @@ namespace Microsoft.AspNet.Mvc
modelName); modelName);
ObjectValidator.Validate( ObjectValidator.Validate(
BindingContext.ValidatorProvider, new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders),
ModelState, ModelState,
validationState: null, validationState: null,
prefix: prefix, prefix: prefix,

View File

@ -12,18 +12,18 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public class ViewDataDictionaryControllerPropertyActivator : IControllerPropertyActivator public class ViewDataDictionaryControllerPropertyActivator : IControllerPropertyActivator
{ {
private readonly IModelMetadataProvider _modelMetadataProvider; private readonly IModelMetadataProvider _modelMetadataProvider;
private readonly ConcurrentDictionary<Type, PropertyActivator<ActionContext>[]> _activateActions; private readonly ConcurrentDictionary<Type, PropertyActivator<ControllerContext>[]> _activateActions;
private readonly Func<Type, PropertyActivator<ActionContext>[]> _getPropertiesToActivate; private readonly Func<Type, PropertyActivator<ControllerContext>[]> _getPropertiesToActivate;
public ViewDataDictionaryControllerPropertyActivator(IModelMetadataProvider modelMetadataProvider) public ViewDataDictionaryControllerPropertyActivator(IModelMetadataProvider modelMetadataProvider)
{ {
_modelMetadataProvider = modelMetadataProvider; _modelMetadataProvider = modelMetadataProvider;
_activateActions = new ConcurrentDictionary<Type, PropertyActivator<ActionContext>[]>(); _activateActions = new ConcurrentDictionary<Type, PropertyActivator<ControllerContext>[]>();
_getPropertiesToActivate = GetPropertiesToActivate; _getPropertiesToActivate = GetPropertiesToActivate;
} }
public void Activate(ActionContext actionContext, object controller) public void Activate(ControllerContext actionContext, object controller)
{ {
var controllerType = controller.GetType(); var controllerType = controller.GetType();
var propertiesToActivate = _activateActions.GetOrAdd( var propertiesToActivate = _activateActions.GetOrAdd(
@ -37,17 +37,17 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
} }
} }
private PropertyActivator<ActionContext>[] GetPropertiesToActivate(Type type) private PropertyActivator<ControllerContext>[] GetPropertiesToActivate(Type type)
{ {
var activators = PropertyActivator<ActionContext>.GetPropertiesToActivate( var activators = PropertyActivator<ControllerContext>.GetPropertiesToActivate(
type, type,
typeof(ViewDataDictionaryAttribute), typeof(ViewDataDictionaryAttribute),
p => new PropertyActivator<ActionContext>(p, GetViewDataDictionary)); p => new PropertyActivator<ControllerContext>(p, GetViewDataDictionary));
return activators; return activators;
} }
private ViewDataDictionary GetViewDataDictionary(ActionContext context) private ViewDataDictionary GetViewDataDictionary(ControllerContext context)
{ {
var serviceProvider = context.HttpContext.RequestServices; var serviceProvider = context.HttpContext.RequestServices;
return new ViewDataDictionary( return new ViewDataDictionary(

View File

@ -22,24 +22,43 @@ namespace System.Web.Http
[UseWebApiOverloading] [UseWebApiOverloading]
public abstract class ApiController : IDisposable public abstract class ApiController : IDisposable
{ {
private ControllerContext _controllerContext;
private HttpRequestMessage _request; private HttpRequestMessage _request;
private IModelMetadataProvider _metadataProvider; private IModelMetadataProvider _metadataProvider;
private IObjectModelValidator _objectValidator; private IObjectModelValidator _objectValidator;
private IUrlHelper _urlHelper; private IUrlHelper _urlHelper;
/// <summary> /// <summary>
/// Gets the action context. /// Gets the <see cref="Microsoft.AspNet.Mvc.ActionContext"/>.
/// </summary> /// </summary>
/// <remarks>The setter is intended for unit testing purposes only.</remarks> public ActionContext ActionContext => ControllerContext;
[ActionContext]
public ActionContext ActionContext { get; set; }
/// <summary> /// <summary>
/// Gets the <see cref="ActionBindingContext"/>. /// Gets or sets the <see cref="ControllerContext"/>.
/// </summary> /// </summary>
/// <remarks>The setter is intended for unit testing purposes only.</remarks> /// <remarks>The setter is intended for unit testing purposes only.</remarks>
[ActionBindingContext] [ControllerContext]
public ActionBindingContext BindingContext { get; set; } public ControllerContext ControllerContext
{
get
{
if (_controllerContext == null)
{
_controllerContext = new ControllerContext();
}
return _controllerContext;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_controllerContext = value;
}
}
/// <summary> /// <summary>
/// Gets the http context. /// Gets the http context.
@ -48,7 +67,7 @@ namespace System.Web.Http
{ {
get get
{ {
return ActionContext?.HttpContext; return ControllerContext.HttpContext;
} }
} }
@ -101,7 +120,7 @@ namespace System.Web.Http
{ {
get get
{ {
return ActionContext?.ModelState; return ControllerContext.ModelState;
} }
} }
@ -115,7 +134,7 @@ namespace System.Web.Http
{ {
if (_request == null && ActionContext != null) if (_request == null && ActionContext != null)
{ {
_request = ActionContext.HttpContext.GetHttpRequestMessage(); _request = ControllerContext.HttpContext.GetHttpRequestMessage();
} }
return _request; return _request;
@ -553,7 +572,7 @@ namespace System.Web.Http
{ {
var validatidationState = new ValidationStateDictionary(); var validatidationState = new ValidationStateDictionary();
ObjectValidator.Validate( ObjectValidator.Validate(
BindingContext.ValidatorProvider, new CompositeModelValidatorProvider(ControllerContext.ValidatorProviders),
ModelState, ModelState,
validatidationState, validatidationState,
keyPrefix, keyPrefix,

View File

@ -7,6 +7,7 @@ using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Test; using Microsoft.AspNet.Mvc.ModelBinding.Test;
using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.ModelBinding.Validation;
@ -31,24 +32,21 @@ namespace Microsoft.AspNet.Mvc.Controllers
BindingInfo = new BindingInfo(), BindingInfo = new BindingInfo(),
}); });
var actionContext = GetActionContext(actionDescriptor);
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
binder binder
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(ModelBindingResult.NoResultAsync); .Returns(ModelBindingResult.NoResultAsync);
var actionBindingContext = new ActionBindingContext()
{ var controllerContext = GetControllerContext(actionDescriptor);
ModelBinder = binder.Object, controllerContext.ModelBinders.Add(binder.Object);
ValueProvider = new SimpleValueProvider(), controllerContext.ValueProviders.Add(new SimpleValueProvider());
};
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
var argumentBinder = GetArgumentBinder(); var argumentBinder = GetArgumentBinder();
// Act // Act
var result = await argumentBinder var result = await argumentBinder
.BindActionArgumentsAsync(actionContext, actionBindingContext, new TestController()); .BindActionArgumentsAsync(controllerContext, new TestController());
// Assert // Assert
Assert.Empty(result); Assert.Empty(result);
@ -72,23 +70,16 @@ namespace Microsoft.AspNet.Mvc.Controllers
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(ModelBindingResult.FailedAsync(string.Empty)); .Returns(ModelBindingResult.FailedAsync(string.Empty));
var actionContext = new ActionContext( var controllerContext = GetControllerContext(actionDescriptor);
new DefaultHttpContext(), controllerContext.ModelBinders.Add(binder.Object);
new RouteData(), controllerContext.ValueProviders.Add(new SimpleValueProvider());
actionDescriptor);
var actionBindingContext = new ActionBindingContext()
{
ModelBinder = binder.Object,
ValueProvider = new SimpleValueProvider(),
};
var argumentBinder = GetArgumentBinder(); var argumentBinder = GetArgumentBinder();
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
// Act // Act
var result = await argumentBinder var result = await argumentBinder
.BindActionArgumentsAsync(actionContext, actionBindingContext, new TestController()); .BindActionArgumentsAsync(controllerContext, new TestController());
// Assert // Assert
Assert.Empty(result); Assert.Empty(result);
@ -120,22 +111,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
}) })
.Returns(ModelBindingResult.SuccessAsync(string.Empty, value)); .Returns(ModelBindingResult.SuccessAsync(string.Empty, value));
var actionContext = new ActionContext( var controllerContext = GetControllerContext(actionDescriptor);
new DefaultHttpContext(), controllerContext.ModelBinders.Add(binder.Object);
new RouteData(), controllerContext.ValueProviders.Add(new SimpleValueProvider());
actionDescriptor);
var actionBindingContext = new ActionBindingContext()
{
ModelBinder = binder.Object,
ValueProvider = new SimpleValueProvider(),
};
var argumentBinder = GetArgumentBinder(); var argumentBinder = GetArgumentBinder();
// Act // Act
var result = await argumentBinder var result = await argumentBinder
.BindActionArgumentsAsync(actionContext, actionBindingContext, new TestController()); .BindActionArgumentsAsync(controllerContext, new TestController());
// Assert // Assert
Assert.Equal(1, result.Count); Assert.Equal(1, result.Count);
@ -154,8 +138,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
ParameterType = typeof(object), ParameterType = typeof(object),
}); });
var actionContext = GetActionContext(actionDescriptor); var controllerContext = GetControllerContext(actionDescriptor, "Hello");
var actionBindingContext = GetActionBindingContext();
var mockValidator = new Mock<IObjectModelValidator>(MockBehavior.Strict); var mockValidator = new Mock<IObjectModelValidator>(MockBehavior.Strict);
mockValidator mockValidator
@ -169,8 +152,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
var argumentBinder = GetArgumentBinder(mockValidator.Object); var argumentBinder = GetArgumentBinder(mockValidator.Object);
// Act // Act
var result = await argumentBinder var result = await argumentBinder.BindActionArgumentsAsync(controllerContext, new TestController());
.BindActionArgumentsAsync(actionContext, actionBindingContext, new TestController());
// Assert // Assert
mockValidator mockValidator
@ -197,21 +179,14 @@ namespace Microsoft.AspNet.Mvc.Controllers
BindingInfo = new BindingInfo(), BindingInfo = new BindingInfo(),
}); });
var actionContext = new ActionContext(
new DefaultHttpContext(),
new RouteData(),
actionDescriptor);
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
binder binder
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(ModelBindingResult.NoResultAsync); .Returns(ModelBindingResult.NoResultAsync);
var actionBindingContext = new ActionBindingContext() var controllerContext = GetControllerContext(actionDescriptor);
{ controllerContext.ModelBinders.Add(binder.Object);
ModelBinder = binder.Object, controllerContext.ValueProviders.Add(new SimpleValueProvider());
ValueProvider = new SimpleValueProvider(),
};
var mockValidator = new Mock<IObjectModelValidator>(MockBehavior.Strict); var mockValidator = new Mock<IObjectModelValidator>(MockBehavior.Strict);
mockValidator mockValidator
@ -225,8 +200,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
var argumentBinder = GetArgumentBinder(mockValidator.Object); var argumentBinder = GetArgumentBinder(mockValidator.Object);
// Act // Act
var result = await argumentBinder var result = await argumentBinder.BindActionArgumentsAsync(controllerContext, new TestController());
.BindActionArgumentsAsync(actionContext, actionBindingContext, new TestController());
// Assert // Assert
mockValidator mockValidator
@ -251,8 +225,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
ParameterType = typeof(string), ParameterType = typeof(string),
}); });
var actionContext = GetActionContext(actionDescriptor); var controllerContext = GetControllerContext(actionDescriptor, "Hello");
var actionBindingContext = GetActionBindingContext();
var mockValidator = new Mock<IObjectModelValidator>(MockBehavior.Strict); var mockValidator = new Mock<IObjectModelValidator>(MockBehavior.Strict);
mockValidator mockValidator
@ -266,8 +239,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
var argumentBinder = GetArgumentBinder(mockValidator.Object); var argumentBinder = GetArgumentBinder(mockValidator.Object);
// Act // Act
var result = await argumentBinder var result = await argumentBinder.BindActionArgumentsAsync(controllerContext, new TestController());
.BindActionArgumentsAsync(actionContext, actionBindingContext, new TestController());
// Assert // Assert
mockValidator mockValidator
@ -293,21 +265,14 @@ namespace Microsoft.AspNet.Mvc.Controllers
ParameterType = typeof(string), ParameterType = typeof(string),
}); });
var actionContext = new ActionContext(
new DefaultHttpContext(),
new RouteData(),
actionDescriptor);
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
binder binder
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(ModelBindingResult.NoResultAsync); .Returns(ModelBindingResult.NoResultAsync);
var actionBindingContext = new ActionBindingContext() var controllerContext = GetControllerContext(actionDescriptor);
{ controllerContext.ModelBinders.Add(binder.Object);
ModelBinder = binder.Object, controllerContext.ValueProviders.Add(new SimpleValueProvider());
ValueProvider = new SimpleValueProvider(),
};
var mockValidator = new Mock<IObjectModelValidator>(MockBehavior.Strict); var mockValidator = new Mock<IObjectModelValidator>(MockBehavior.Strict);
mockValidator mockValidator
@ -321,8 +286,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
var argumentBinder = GetArgumentBinder(mockValidator.Object); var argumentBinder = GetArgumentBinder(mockValidator.Object);
// Act // Act
var result = await argumentBinder var result = await argumentBinder.BindActionArgumentsAsync(controllerContext, new TestController());
.BindActionArgumentsAsync(actionContext, actionBindingContext, new TestController());
// Assert // Assert
mockValidator mockValidator
@ -348,13 +312,12 @@ namespace Microsoft.AspNet.Mvc.Controllers
ParameterType = typeof(string) ParameterType = typeof(string)
}); });
var actionContext = GetActionContext(actionDescriptor); var controllerContext = GetControllerContext(actionDescriptor, "Hello");
var actionBindingContext = GetActionBindingContext();
var argumentBinder = GetArgumentBinder(); var argumentBinder = GetArgumentBinder();
var controller = new TestController(); var controller = new TestController();
// Act // Act
var result = await argumentBinder.BindActionArgumentsAsync(actionContext, actionBindingContext, controller); var result = await argumentBinder.BindActionArgumentsAsync(controllerContext, controller);
// Assert // Assert
Assert.Equal("Hello", controller.StringProperty); Assert.Equal("Hello", controller.StringProperty);
@ -376,13 +339,13 @@ namespace Microsoft.AspNet.Mvc.Controllers
}); });
var expected = new List<string> { "Hello", "World", "!!" }; var expected = new List<string> { "Hello", "World", "!!" };
var actionContext = GetActionContext(actionDescriptor); var controllerContext = GetControllerContext(actionDescriptor, expected);
var actionBindingContext = GetActionBindingContext(model: expected);
var argumentBinder = GetArgumentBinder(); var argumentBinder = GetArgumentBinder();
var controller = new TestController(); var controller = new TestController();
// Act // Act
var result = await argumentBinder.BindActionArgumentsAsync(actionContext, actionBindingContext, controller); var result = await argumentBinder.BindActionArgumentsAsync(controllerContext, controller);
// Assert // Assert
Assert.Equal(expected, controller.CollectionProperty); Assert.Equal(expected, controller.CollectionProperty);
@ -405,18 +368,14 @@ namespace Microsoft.AspNet.Mvc.Controllers
ParameterType = typeof(int) ParameterType = typeof(int)
}); });
var actionContext = GetActionContext(actionDescriptor);
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
binder binder
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(ModelBindingResult.SuccessAsync(string.Empty, model: null)); .Returns(ModelBindingResult.SuccessAsync(string.Empty, model: null));
var actionBindingContext = new ActionBindingContext() var controllerContext = GetControllerContext(actionDescriptor);
{ controllerContext.ModelBinders.Add(binder.Object);
ModelBinder = binder.Object, controllerContext.ValueProviders.Add(new SimpleValueProvider());
ValueProvider = new SimpleValueProvider(),
};
var argumentBinder = GetArgumentBinder(); var argumentBinder = GetArgumentBinder();
var controller = new TestController(); var controller = new TestController();
@ -425,7 +384,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
controller.NonNullableProperty = -1; controller.NonNullableProperty = -1;
// Act // Act
var result = await argumentBinder.BindActionArgumentsAsync(actionContext, actionBindingContext, controller); var result = await argumentBinder.BindActionArgumentsAsync(controllerContext, controller);
// Assert // Assert
Assert.Equal(-1, controller.NonNullableProperty); Assert.Equal(-1, controller.NonNullableProperty);
@ -444,18 +403,14 @@ namespace Microsoft.AspNet.Mvc.Controllers
ParameterType = typeof(int?) ParameterType = typeof(int?)
}); });
var actionContext = GetActionContext(actionDescriptor);
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
binder binder
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(ModelBindingResult.SuccessAsync(key: string.Empty, model: null)); .Returns(ModelBindingResult.SuccessAsync(key: string.Empty, model: null));
var actionBindingContext = new ActionBindingContext() var controllerContext = GetControllerContext(actionDescriptor);
{ controllerContext.ModelBinders.Add(binder.Object);
ModelBinder = binder.Object, controllerContext.ValueProviders.Add(new SimpleValueProvider());
ValueProvider = new SimpleValueProvider(),
};
var argumentBinder = GetArgumentBinder(); var argumentBinder = GetArgumentBinder();
var controller = new TestController(); var controller = new TestController();
@ -464,7 +419,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
controller.NullableProperty = -1; controller.NullableProperty = -1;
// Act // Act
var result = await argumentBinder.BindActionArgumentsAsync(actionContext, actionBindingContext, controller); var result = await argumentBinder.BindActionArgumentsAsync(controllerContext, controller);
// Assert // Assert
Assert.Null(controller.NullableProperty); Assert.Null(controller.NullableProperty);
@ -528,13 +483,12 @@ namespace Microsoft.AspNet.Mvc.Controllers
ParameterType = propertyType, ParameterType = propertyType,
}); });
var actionContext = GetActionContext(actionDescriptor); var controllerContext = GetControllerContext(actionDescriptor, inputValue);
var actionBindingContext = GetActionBindingContext(model: inputValue);
var argumentBinder = GetArgumentBinder(); var argumentBinder = GetArgumentBinder();
var controller = new TestController(); var controller = new TestController();
// Act // Act
var result = await argumentBinder.BindActionArgumentsAsync(actionContext, actionBindingContext, controller); var result = await argumentBinder.BindActionArgumentsAsync(controllerContext, controller);
// Assert // Assert
Assert.Equal(expectedValue, propertyAccessor(controller)); Assert.Equal(expectedValue, propertyAccessor(controller));
@ -583,16 +537,19 @@ namespace Microsoft.AspNet.Mvc.Controllers
}); });
} }
var actionContext = GetActionContext(actionDescriptor); var controllerContext = GetControllerContext(actionDescriptor);
var argumentBinder = GetArgumentBinder(); var argumentBinder = GetArgumentBinder();
var controller = new TestController(); var controller = new TestController();
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
binder binder
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) .Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns<ModelBindingContext>(bindingContext => .Returns<ModelBindingContext>(bindingContext =>
{ {
// BindingContext.ModelName will be string.Empty here. This is a 'fallback to empty prefix'
// because the value providers have no data.
object model; object model;
if (inputPropertyValues.TryGetValue(bindingContext.ModelName, out model)) if (inputPropertyValues.TryGetValue(bindingContext.FieldName, out model))
{ {
return ModelBindingResult.SuccessAsync(bindingContext.ModelName, model); return ModelBindingResult.SuccessAsync(bindingContext.ModelName, model);
} }
@ -601,14 +558,11 @@ namespace Microsoft.AspNet.Mvc.Controllers
return ModelBindingResult.FailedAsync(bindingContext.ModelName); return ModelBindingResult.FailedAsync(bindingContext.ModelName);
} }
}); });
var actionBindingContext = new ActionBindingContext controllerContext.ModelBinders.Add(binder.Object);
{ controllerContext.ValueProviders.Add(new SimpleValueProvider());
ModelBinder = binder.Object,
ValueProvider = new SimpleValueProvider(),
};
// Act // Act
var result = await argumentBinder.BindActionArgumentsAsync(actionContext, actionBindingContext, controller); var result = await argumentBinder.BindActionArgumentsAsync(controllerContext, controller);
// Assert // Assert
Assert.Equal(new string[] { "goodbye" }, controller.ArrayProperty); // Skipped Assert.Equal(new string[] { "goodbye" }, controller.ArrayProperty); // Skipped
@ -619,15 +573,19 @@ namespace Microsoft.AspNet.Mvc.Controllers
Assert.Equal("Hello", controller.StringProperty); Assert.Equal("Hello", controller.StringProperty);
} }
private static ActionContext GetActionContext(ActionDescriptor descriptor = null) private static ControllerContext GetControllerContext(ControllerActionDescriptor descriptor = null)
{ {
return new ActionContext( var context = new ControllerContext()
new DefaultHttpContext(), {
new RouteData(), ActionDescriptor = descriptor ?? GetActionDescriptor(),
descriptor ?? GetActionDescriptor()); HttpContext = new DefaultHttpContext(),
RouteData = new RouteData(),
};
return context;
} }
private static ActionDescriptor GetActionDescriptor() private static ControllerActionDescriptor GetActionDescriptor()
{ {
Func<object, int> method = foo => 1; Func<object, int> method = foo => 1;
return new ControllerActionDescriptor return new ControllerActionDescriptor
@ -639,13 +597,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
}; };
} }
private static ActionBindingContext GetActionBindingContext() private static ControllerContext GetControllerContext(ControllerActionDescriptor descriptor = null, object model = null)
{ {
return GetActionBindingContext("Hello"); var context = new ControllerContext()
} {
ActionDescriptor = descriptor ?? GetActionDescriptor(),
HttpContext = new DefaultHttpContext(),
RouteData = new RouteData(),
};
private static ActionBindingContext GetActionBindingContext(object model)
{
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns<ModelBindingContext>(mbc => .Returns<ModelBindingContext>(mbc =>
@ -653,11 +613,9 @@ namespace Microsoft.AspNet.Mvc.Controllers
return ModelBindingResult.SuccessAsync(string.Empty, model); return ModelBindingResult.SuccessAsync(string.Empty, model);
}); });
return new ActionBindingContext() context.ModelBinders.Add(binder.Object);
{ context.ValueProviders.Add(new SimpleValueProvider());
ModelBinder = binder.Object, return context;
ValueProvider = new SimpleValueProvider(),
};
} }
private static DefaultControllerActionArgumentBinder GetArgumentBinder(IObjectModelValidator validator = null) private static DefaultControllerActionArgumentBinder GetArgumentBinder(IObjectModelValidator validator = null)

View File

@ -2040,7 +2040,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
var actionArgumentsBinder = new Mock<IControllerActionArgumentBinder>(); var actionArgumentsBinder = new Mock<IControllerActionArgumentBinder>();
actionArgumentsBinder.Setup( actionArgumentsBinder.Setup(
b => b.BindActionArgumentsAsync(actionContext, It.IsAny<ActionBindingContext>(), It.IsAny<object>())) b => b.BindActionArgumentsAsync(It.IsAny<ControllerContext>(), It.IsAny<object>()))
.Returns(Task.FromResult<IDictionary<string, object>>(new Dictionary<string, object>())); .Returns(Task.FromResult<IDictionary<string, object>>(new Dictionary<string, object>()));
filterProvider filterProvider
@ -2053,12 +2053,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
new MockControllerFactory(this), new MockControllerFactory(this),
actionDescriptor, actionDescriptor,
new IInputFormatter[0], new IInputFormatter[0],
new IOutputFormatter[0],
actionArgumentsBinder.Object, actionArgumentsBinder.Object,
new IModelBinder[0], new IModelBinder[0],
new IModelValidatorProvider[0], new IModelValidatorProvider[0],
new IValueProviderFactory[0], new IValueProviderFactory[0],
new ActionBindingContextAccessor(),
new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(), new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(),
new DiagnosticListener("Microsoft.AspNet"), new DiagnosticListener("Microsoft.AspNet"),
maxAllowedErrorsInModelState); maxAllowedErrorsInModelState);
@ -2101,7 +2099,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
var actionContext = new ActionContext(context.Object, new RouteData(), actionDescriptor); var actionContext = new ActionContext(context.Object, new RouteData(), actionDescriptor);
var controllerFactory = new Mock<IControllerFactory>(); var controllerFactory = new Mock<IControllerFactory>();
controllerFactory.Setup(c => c.CreateController(It.IsAny<ActionContext>())) controllerFactory.Setup(c => c.CreateController(It.IsAny<ControllerContext>()))
.Returns(new TestController()); .Returns(new TestController());
var metadataProvider = new EmptyModelMetadataProvider(); var metadataProvider = new EmptyModelMetadataProvider();
@ -2112,14 +2110,12 @@ namespace Microsoft.AspNet.Mvc.Controllers
controllerFactory.Object, controllerFactory.Object,
actionDescriptor, actionDescriptor,
new IInputFormatter[0], new IInputFormatter[0],
new IOutputFormatter[0],
new DefaultControllerActionArgumentBinder( new DefaultControllerActionArgumentBinder(
metadataProvider, metadataProvider,
new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider)), new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider)),
new IModelBinder[] { binder.Object }, new IModelBinder[] { binder.Object },
new IModelValidatorProvider[0], new IModelValidatorProvider[0],
new IValueProviderFactory[0], new IValueProviderFactory[0],
new ActionBindingContextAccessor(),
new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(), new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(),
new DiagnosticListener("Microsoft.AspNet"), new DiagnosticListener("Microsoft.AspNet"),
200); 200);
@ -2204,7 +2200,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
public bool ReleaseCalled { get; private set; } public bool ReleaseCalled { get; private set; }
public object CreateController(ActionContext actionContext) public object CreateController(ControllerContext context)
{ {
CreateCalled = true; CreateCalled = true;
return _controller; return _controller;
@ -2234,12 +2230,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
MockControllerFactory controllerFactory, MockControllerFactory controllerFactory,
ControllerActionDescriptor descriptor, ControllerActionDescriptor descriptor,
IReadOnlyList<IInputFormatter> inputFormatters, IReadOnlyList<IInputFormatter> inputFormatters,
IReadOnlyList<IOutputFormatter> outputFormatters,
IControllerActionArgumentBinder controllerActionArgumentBinder, IControllerActionArgumentBinder controllerActionArgumentBinder,
IReadOnlyList<IModelBinder> modelBinders, IReadOnlyList<IModelBinder> modelBinders,
IReadOnlyList<IModelValidatorProvider> modelValidatorProviders, IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
IReadOnlyList<IValueProviderFactory> valueProviderFactories, IReadOnlyList<IValueProviderFactory> valueProviderFactories,
IActionBindingContextAccessor actionBindingContext,
ILogger logger, ILogger logger,
DiagnosticSource diagnosticSource, DiagnosticSource diagnosticSource,
int maxAllowedErrorsInModelState) int maxAllowedErrorsInModelState)
@ -2249,12 +2243,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
controllerFactory, controllerFactory,
descriptor, descriptor,
inputFormatters, inputFormatters,
outputFormatters,
controllerActionArgumentBinder, controllerActionArgumentBinder,
modelBinders, modelBinders,
modelValidatorProviders, modelValidatorProviders,
valueProviderFactories, valueProviderFactories,
actionBindingContext,
logger, logger,
diagnosticSource, diagnosticSource,
maxAllowedErrorsInModelState) maxAllowedErrorsInModelState)

View File

@ -4,12 +4,9 @@
using System; using System;
using System.Reflection; using System.Reflection;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Infrastructure; using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
using Xunit; using Xunit;
@ -17,27 +14,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
public class DefaultControllerFactoryTest public class DefaultControllerFactoryTest
{ {
[Fact]
public void CreateController_ThrowsIfActionDescriptorIsNotControllerActionDescriptor()
{
// Arrange
var expected =
$"The action descriptor must be of type '{typeof(ControllerActionDescriptor).FullName}'." +
Environment.NewLine + "Parameter name: actionContext";
var actionDescriptor = new ActionDescriptor();
var controllerFactory = CreateControllerFactory();
var httpContext = new DefaultHttpContext();
var actionContext = new ActionContext(httpContext,
new RouteData(),
actionDescriptor);
// Act and Assert
var ex = Assert.Throws<ArgumentException>(() =>
controllerFactory.CreateController(actionContext));
Assert.Equal(expected, ex.Message);
Assert.Equal("actionContext", ex.ParamName);
}
[Fact] [Fact]
public void CreateController_UsesControllerActivatorToInstantiateController() public void CreateController_UsesControllerActivatorToInstantiateController()
{ {
@ -47,20 +23,25 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
ControllerTypeInfo = typeof(MyController).GetTypeInfo() ControllerTypeInfo = typeof(MyController).GetTypeInfo()
}; };
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = GetServices(); var context = new ControllerContext()
var actionContext = new ActionContext(httpContext, {
new RouteData(), ActionDescriptor = actionDescriptor,
actionDescriptor); HttpContext = new DefaultHttpContext()
{
RequestServices = GetServices(),
},
};
var activator = new Mock<IControllerActivator>(); var activator = new Mock<IControllerActivator>();
activator.Setup(a => a.Create(actionContext, typeof(MyController))) activator.Setup(a => a.Create(context, typeof(MyController)))
.Returns(expected) .Returns(expected)
.Verifiable(); .Verifiable();
var controllerFactory = CreateControllerFactory(activator.Object); var controllerFactory = CreateControllerFactory(activator.Object);
// Act // Act
var result = controllerFactory.CreateController(actionContext); var result = controllerFactory.CreateController(context);
// Assert // Assert
var controller = Assert.IsType<MyController>(result); var controller = Assert.IsType<MyController>(result);
@ -76,12 +57,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
ControllerTypeInfo = typeof(ControllerWithAttributes).GetTypeInfo() ControllerTypeInfo = typeof(ControllerWithAttributes).GetTypeInfo()
}; };
var services = GetServices();
var httpContext = new DefaultHttpContext var context = new ControllerContext()
{ {
RequestServices = services ActionDescriptor = actionDescriptor,
HttpContext = new DefaultHttpContext()
{
RequestServices = GetServices(),
},
}; };
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache())); var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
// Act // Act
@ -93,22 +77,22 @@ namespace Microsoft.AspNet.Mvc.Controllers
} }
[Fact] [Fact]
public void CreateController_SetsBindingContext() public void CreateController_SetsControllerContext()
{ {
// Arrange // Arrange
var actionDescriptor = new ControllerActionDescriptor var actionDescriptor = new ControllerActionDescriptor
{ {
ControllerTypeInfo = typeof(ControllerWithAttributes).GetTypeInfo() ControllerTypeInfo = typeof(ControllerWithAttributes).GetTypeInfo()
}; };
var bindingContext = new ActionBindingContext();
var services = GetServices(); var context = new ControllerContext()
services.GetRequiredService<IActionBindingContextAccessor>().ActionBindingContext = bindingContext;
var httpContext = new DefaultHttpContext
{ {
RequestServices = services ActionDescriptor = actionDescriptor,
HttpContext = new DefaultHttpContext()
{
RequestServices = GetServices(),
},
}; };
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache())); var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
// Act // Act
@ -116,7 +100,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
// Assert // Assert
var controller = Assert.IsType<ControllerWithAttributes>(result); var controller = Assert.IsType<ControllerWithAttributes>(result);
Assert.Same(bindingContext, controller.BindingContext); Assert.Same(context, controller.ControllerContext);
} }
[Fact] [Fact]
@ -127,12 +111,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
ControllerTypeInfo = typeof(ControllerWithoutAttributes).GetTypeInfo() ControllerTypeInfo = typeof(ControllerWithoutAttributes).GetTypeInfo()
}; };
var services = GetServices();
var httpContext = new DefaultHttpContext var context = new ControllerContext()
{ {
RequestServices = services ActionDescriptor = actionDescriptor,
HttpContext = new DefaultHttpContext()
{
RequestServices = GetServices(),
},
}; };
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache())); var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
// Act // Act
@ -151,12 +138,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
ControllerTypeInfo = typeof(ControllerWithNonVisibleProperties).GetTypeInfo() ControllerTypeInfo = typeof(ControllerWithNonVisibleProperties).GetTypeInfo()
}; };
var services = GetServices();
var httpContext = new DefaultHttpContext var context = new ControllerContext()
{ {
RequestServices = services ActionDescriptor = actionDescriptor,
HttpContext = new DefaultHttpContext()
{
RequestServices = GetServices(),
},
}; };
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache())); var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
// Act // Act
@ -165,7 +155,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
// Assert // Assert
var controller = Assert.IsType<ControllerWithNonVisibleProperties>(result); var controller = Assert.IsType<ControllerWithNonVisibleProperties>(result);
Assert.Null(controller.ActionContext); Assert.Null(controller.ActionContext);
Assert.Null(controller.BindingContext); Assert.Null(controller.ControllerContext);
} }
[Fact] [Fact]
@ -176,12 +166,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
ControllerTypeInfo = typeof(ControllerThatCannotBeActivated).GetTypeInfo() ControllerTypeInfo = typeof(ControllerThatCannotBeActivated).GetTypeInfo()
}; };
var services = GetServices();
var httpContext = new DefaultHttpContext var context = new ControllerContext()
{ {
RequestServices = services ActionDescriptor = actionDescriptor,
HttpContext = new DefaultHttpContext()
{
RequestServices = GetServices(),
},
}; };
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache())); var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
// Act and Assert // Act and Assert
@ -204,12 +197,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
ControllerTypeInfo = type.GetTypeInfo() ControllerTypeInfo = type.GetTypeInfo()
}; };
var services = GetServices();
var httpContext = new DefaultHttpContext var context = new ControllerContext()
{ {
RequestServices = services ActionDescriptor = actionDescriptor,
HttpContext = new DefaultHttpContext()
{
RequestServices = GetServices(),
},
}; };
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache())); var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));
// Act and Assert // Act and Assert
@ -256,8 +252,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
.Returns(metadataProvider); .Returns(metadataProvider);
services.Setup(s => s.GetService(typeof(IObjectModelValidator))) services.Setup(s => s.GetService(typeof(IObjectModelValidator)))
.Returns(new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider)); .Returns(new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider));
services.Setup(s => s.GetService(typeof(IActionBindingContextAccessor)))
.Returns(new ActionBindingContextAccessor());
return services.Object; return services.Object;
} }
@ -266,7 +260,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
controllerActivator = controllerActivator ?? Mock.Of<IControllerActivator>(); controllerActivator = controllerActivator ?? Mock.Of<IControllerActivator>();
var propertyActivators = new IControllerPropertyActivator[] var propertyActivators = new IControllerPropertyActivator[]
{ {
new DefaultControllerPropertyActivator(new ActionBindingContextAccessor()), new DefaultControllerPropertyActivator(),
}; };
return new DefaultControllerFactory(controllerActivator, propertyActivators); return new DefaultControllerFactory(controllerActivator, propertyActivators);
@ -276,14 +270,14 @@ namespace Microsoft.AspNet.Mvc.Controllers
{ {
public ActionContext ActionContext { get; set; } public ActionContext ActionContext { get; set; }
public ActionBindingContext BindingContext { get; set; } public ControllerContext ControllerContext { get; set; }
} }
public class ControllerWithNonVisibleProperties public class ControllerWithNonVisibleProperties
{ {
internal ActionContext ActionContext { get; set; } internal ActionContext ActionContext { get; set; }
public ActionBindingContext BindingContext { get; private set; } public ControllerContext ControllerContext { get; private set; }
} }
private class ControllerWithAttributes private class ControllerWithAttributes
@ -291,8 +285,8 @@ namespace Microsoft.AspNet.Mvc.Controllers
[ActionContext] [ActionContext]
public ActionContext ActionContext { get; set; } public ActionContext ActionContext { get; set; }
[ActionBindingContext] [ControllerContext]
public ActionBindingContext BindingContext { get; set; } public ControllerContext ControllerContext { get; set; }
} }
private class MyController : IDisposable private class MyController : IDisposable

View File

@ -97,7 +97,6 @@ namespace Microsoft.AspNet.Mvc
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(
options, options,
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance)); NullLoggerFactory.Instance));

View File

@ -111,7 +111,6 @@ namespace Microsoft.AspNet.Mvc
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(
options, options,
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance)); NullLoggerFactory.Instance));

View File

@ -98,7 +98,6 @@ namespace Microsoft.AspNet.Mvc
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(
options, options,
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance)); NullLoggerFactory.Instance));

View File

@ -74,7 +74,6 @@ namespace Microsoft.AspNet.Mvc
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(
options, options,
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance)); NullLoggerFactory.Instance));

View File

@ -78,7 +78,6 @@ namespace Microsoft.AspNet.Mvc
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(
options, options,
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance)); NullLoggerFactory.Instance));

View File

@ -573,11 +573,9 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
var actionDescriptorProvider = GetActionDescriptorProvider(); var actionDescriptorProvider = GetActionDescriptorProvider();
// Act // Act
var result = actionDescriptorProvider.GetDescriptors() var result = actionDescriptorProvider
.Select(x => x as ControllerActionDescriptor) .GetDescriptors()
.FirstOrDefault( .FirstOrDefault(x => x.ControllerName == "NonAction" && x.Name == actionName);
x => x.ControllerName == "NonAction" &&
x.Name == actionName);
// Assert // Assert
Assert.Null(result); Assert.Null(result);

View File

@ -261,7 +261,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
var result = new ObjectResult("input"); var result = new ObjectResult("input");
// This formatter won't write anything // This formatter won't write anything
result.Formatters = new List<IOutputFormatter> result.Formatters = new FormatterCollection<IOutputFormatter>
{ {
new CannotWriteFormatter(), new CannotWriteFormatter(),
}; };
@ -273,36 +273,6 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
Assert.Equal(StatusCodes.Status406NotAcceptable, actionContext.HttpContext.Response.StatusCode); Assert.Equal(StatusCodes.Status406NotAcceptable, actionContext.HttpContext.Response.StatusCode);
} }
[Fact]
public async Task ExecuteAsync_FallsBackOnFormattersInBindingContext()
{
// Arrange
var bindingContext = new ActionBindingContext()
{
OutputFormatters = new List<IOutputFormatter>()
{
new TestJsonOutputFormatter(),
}
};
var executor = CreateExecutor(bindingContext: bindingContext);
var actionContext = new ActionContext()
{
HttpContext = GetHttpContext(),
};
var result = new ObjectResult("someValue");
// Act
await executor.ExecuteAsync(actionContext, result);
// Assert
Assert.Equal(
"application/json; charset=utf-8",
actionContext.HttpContext.Response.Headers[HeaderNames.ContentType]);
}
[Fact] [Fact]
public async Task ExecuteAsync_FallsBackOnFormattersInOptions() public async Task ExecuteAsync_FallsBackOnFormattersInOptions()
{ {
@ -450,19 +420,10 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
return httpContext; return httpContext;
} }
private static TestObjectResultExecutor CreateExecutor( private static TestObjectResultExecutor CreateExecutor(IOptions<MvcOptions> options = null)
IOptions<MvcOptions> options = null,
ActionBindingContext bindingContext = null)
{ {
var bindingContextAccessor = new ActionBindingContextAccessor();
if (bindingContext != null)
{
bindingContextAccessor.ActionBindingContext = bindingContext;
}
return new TestObjectResultExecutor( return new TestObjectResultExecutor(
options ?? new TestOptionsManager<MvcOptions>(), options ?? new TestOptionsManager<MvcOptions>(),
bindingContextAccessor,
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance); NullLoggerFactory.Instance);
} }
@ -516,10 +477,9 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
{ {
public TestObjectResultExecutor( public TestObjectResultExecutor(
IOptions<MvcOptions> options, IOptions<MvcOptions> options,
IActionBindingContextAccessor bindingContextAccessor,
IHttpResponseStreamWriterFactory writerFactory, IHttpResponseStreamWriterFactory writerFactory,
ILoggerFactory loggerFactory) ILoggerFactory loggerFactory)
: base(options, bindingContextAccessor, writerFactory, loggerFactory) : base(options, writerFactory, loggerFactory)
{ {
} }

View File

@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Xunit; using Xunit;
@ -46,7 +48,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
Assert.Equal(CultureInfo.CurrentCulture, valueProvider.Culture); Assert.Equal(CultureInfo.CurrentCulture, valueProvider.Culture);
} }
private static ValueProviderFactoryContext CreateContext(string contentType) private static ActionContext CreateContext(string contentType)
{ {
var context = new DefaultHttpContext(); var context = new DefaultHttpContext();
context.Request.ContentType = contentType; context.Request.ContentType = contentType;
@ -56,9 +58,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
context.Request.Form = new FormCollection(new Dictionary<string, StringValues>()); context.Request.Form = new FormCollection(new Dictionary<string, StringValues>());
} }
return new ValueProviderFactoryContext( return new ActionContext(context, new RouteData(), new ActionDescriptor());
context,
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase));
} }
} }
} }

View File

@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Xunit; using Xunit;
@ -114,9 +116,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
Assert.Equal("found", (string)result); Assert.Equal("found", (string)result);
} }
private static ValueProviderFactoryContext CreateContext( private static ActionContext CreateContext(string contentType, Dictionary<string, StringValues> formValues)
string contentType,
Dictionary<string, StringValues> formValues)
{ {
var context = new DefaultHttpContext(); var context = new DefaultHttpContext();
context.Request.ContentType = contentType; context.Request.ContentType = contentType;
@ -126,9 +126,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
context.Request.Form = new FormCollection(formValues ?? new Dictionary<string, StringValues>()); context.Request.Form = new FormCollection(formValues ?? new Dictionary<string, StringValues>());
} }
return new ValueProviderFactoryContext( return new ActionContext(context, new RouteData(), new ActionDescriptor());
context,
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase));
} }
} }
} }

View File

@ -2,11 +2,12 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if DNX451 #if DNX451
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Routing;
using Moq; using Moq;
using Xunit; using Xunit;
#endif #endif
@ -27,12 +28,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
var context = new Mock<HttpContext>(); var context = new Mock<HttpContext>();
context.SetupGet(c => c.Items).Returns(new Dictionary<object, object>()); context.SetupGet(c => c.Items).Returns(new Dictionary<object, object>());
context.SetupGet(c => c.Request).Returns(request.Object); context.SetupGet(c => c.Request).Returns(request.Object);
var factoryContext = new ValueProviderFactoryContext( var actionContext = new ActionContext(context.Object, new RouteData(), new ActionDescriptor());
context.Object,
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase));
// Act // Act
var result = await _factory.GetValueProviderAsync(factoryContext); var result = await _factory.GetValueProviderAsync(actionContext);
// Assert // Assert
var valueProvider = Assert.IsType<QueryStringValueProvider>(result); var valueProvider = Assert.IsType<QueryStringValueProvider>(result);

View File

@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Mvc
var result = new ObjectResult("Hello") var result = new ObjectResult("Hello")
{ {
StatusCode = 404, StatusCode = 404,
Formatters = new List<IOutputFormatter>() Formatters = new FormatterCollection<IOutputFormatter>()
{ {
new NoOpOutputFormatter(), new NoOpOutputFormatter(),
}, },
@ -67,7 +67,6 @@ namespace Microsoft.AspNet.Mvc
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(
new TestOptionsManager<MvcOptions>(), new TestOptionsManager<MvcOptions>(),
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance)); NullLoggerFactory.Instance));
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance); services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);

View File

@ -2,51 +2,40 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Controllers; using Microsoft.AspNet.Mvc.Controllers;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.OptionsModel;
namespace Microsoft.AspNet.Mvc.IntegrationTests namespace Microsoft.AspNet.Mvc.IntegrationTests
{ {
public static class ModelBindingTestHelper public static class ModelBindingTestHelper
{ {
public static HttpContext GetHttpContext(
Action<HttpRequest> updateRequest = null,
Action<MvcOptions> updateOptions = null)
{
var httpContext = new DefaultHttpContext();
if (updateRequest != null)
{
updateRequest(httpContext.Request);
}
InitializeServices(httpContext, updateOptions);
return httpContext;
}
public static OperationBindingContext GetOperationBindingContext( public static OperationBindingContext GetOperationBindingContext(
Action<HttpRequest> updateRequest = null, Action<HttpRequest> updateRequest = null,
Action<MvcOptions> updateOptions = null) Action<MvcOptions> updateOptions = null)
{ {
var httpContext = GetHttpContext(updateRequest, updateOptions); var httpContext = GetHttpContext(updateRequest, updateOptions);
var services = httpContext.RequestServices; var services = httpContext.RequestServices;
var actionBindingContext = services.GetRequiredService<IActionBindingContextAccessor>().ActionBindingContext;
var actionContext = new ActionContext(httpContext, new RouteData(), new ControllerActionDescriptor());
var controllerContext = GetControllerContext(
services.GetRequiredService<IOptions<MvcOptions>>().Value,
actionContext);
return new OperationBindingContext() return new OperationBindingContext()
{ {
HttpContext = httpContext, HttpContext = httpContext,
InputFormatters = actionBindingContext.InputFormatters, InputFormatters = controllerContext.InputFormatters,
MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(), MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
ValidatorProvider = actionBindingContext.ValidatorProvider, ValidatorProvider = new CompositeModelValidatorProvider(controllerContext.ValidatorProviders),
ValueProvider = actionBindingContext.ValueProvider, ValueProvider = new CompositeValueProvider(controllerContext.ValueProviders),
ModelBinder = actionBindingContext.ModelBinder ModelBinder = new CompositeModelBinder(controllerContext.ModelBinders),
}; };
} }
@ -68,47 +57,47 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
metadataProvider); metadataProvider);
} }
private static void InitializeServices(HttpContext httpContext, Action<MvcOptions> updateOptions = null) private static HttpContext GetHttpContext(
Action<HttpRequest> updateRequest = null,
Action<MvcOptions> updateOptions = null)
{ {
var httpContext = new DefaultHttpContext();
if (updateRequest != null)
{
updateRequest(httpContext.Request);
}
var serviceCollection = new ServiceCollection(); var serviceCollection = new ServiceCollection();
serviceCollection.AddMvc(); serviceCollection.AddMvc();
httpContext.RequestServices = serviceCollection.BuildServiceProvider();
var actionContext = new ActionContext(httpContext, new RouteData(), new ControllerActionDescriptor());
var actionContextAccessor =
httpContext.RequestServices.GetRequiredService<IActionContextAccessor>();
actionContextAccessor.ActionContext = actionContext;
var options = new TestMvcOptions().Value;
if (updateOptions != null) if (updateOptions != null)
{ {
updateOptions(options); serviceCollection.Configure(updateOptions);
} }
var actionBindingContextAccessor = httpContext.RequestServices = serviceCollection.BuildServiceProvider();
httpContext.RequestServices.GetRequiredService<IActionBindingContextAccessor>(); return httpContext;
actionBindingContextAccessor.ActionBindingContext = GetActionBindingContext(options, actionContext);
} }
private static ActionBindingContext GetActionBindingContext(MvcOptions options, ActionContext actionContext) private static ControllerContext GetControllerContext(MvcOptions options, ActionContext context)
{ {
var valueProviderFactoryContext = new ValueProviderFactoryContext( var valueProviders = new List<IValueProvider>();
actionContext.HttpContext, foreach (var factory in options.ValueProviderFactories)
actionContext.RouteData.Values); {
var valueProvider = factory.GetValueProviderAsync(context).Result;
if (valueProvider != null)
{
valueProviders.Add(valueProvider);
}
}
var valueProvider = CompositeValueProvider.CreateAsync( return new ControllerContext(context)
options.ValueProviderFactories,
valueProviderFactoryContext).Result;
return new ActionBindingContext()
{ {
InputFormatters = options.InputFormatters, InputFormatters = options.InputFormatters,
OutputFormatters = options.OutputFormatters, // Not required for model binding. ValidatorProviders = options.ModelValidatorProviders,
ValidatorProvider = new TestModelValidatorProvider(options.ModelValidatorProviders), ModelBinders = options.ModelBinders,
ModelBinder = new CompositeModelBinder(options.ModelBinders), ValueProviders = valueProviders
ValueProvider = valueProvider
}; };
} }
} }

View File

@ -1351,6 +1351,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var model = Assert.IsType<Order9>(modelBindingResult.Model); var model = Assert.IsType<Order9>(modelBindingResult.Model);
Assert.NotNull(model.Customer); Assert.NotNull(model.Customer);
Assert.NotNull(model.Customer.Address); Assert.NotNull(model.Customer.Address);
Assert.Equal(AddressStreetContent, model.Customer.Address.Street); Assert.Equal(AddressStreetContent, model.Customer.Address.Street);

View File

@ -11,7 +11,6 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Mvc.Formatters; using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
@ -479,10 +478,9 @@ namespace Microsoft.AspNet.Mvc.Test
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var uri = new Uri("/test/url", UriKind.Relative); var uri = new Uri("/test/url", UriKind.Relative);
var controller = new TestableController() var controller = new TestableController();
{ controller.ControllerContext.HttpContext = mockHttpContext.Object;
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor())
};
var input = new DisposableObject(); var input = new DisposableObject();
// Act // Act
@ -565,10 +563,9 @@ namespace Microsoft.AspNet.Mvc.Test
var mockHttpContext = new Mock<DefaultHttpContext>(); var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestableController() var controller = new TestableController();
{ controller.ControllerContext.HttpContext = mockHttpContext.Object;
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor())
};
var input = new DisposableObject(); var input = new DisposableObject();
// Act // Act
@ -648,10 +645,9 @@ namespace Microsoft.AspNet.Mvc.Test
var mockHttpContext = new Mock<DefaultHttpContext>(); var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestableController() var controller = new TestableController();
{ controller.ControllerContext.HttpContext = mockHttpContext.Object;
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor())
};
var input = new DisposableObject(); var input = new DisposableObject();
// Act // Act
@ -741,10 +737,10 @@ namespace Microsoft.AspNet.Mvc.Test
// Arrange // Arrange
var mockHttpContext = new Mock<DefaultHttpContext>(); var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestableController()
{ var controller = new TestableController();
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor()) controller.ControllerContext.HttpContext = mockHttpContext.Object;
};
var fileStream = Stream.Null; var fileStream = Stream.Null;
// Act // Act
@ -764,10 +760,9 @@ namespace Microsoft.AspNet.Mvc.Test
var mockHttpContext = new Mock<DefaultHttpContext>(); var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestableController() var controller = new TestableController();
{ controller.ControllerContext.HttpContext = mockHttpContext.Object;
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor())
};
var fileStream = Stream.Null; var fileStream = Stream.Null;
// Act // Act
@ -833,10 +828,9 @@ namespace Microsoft.AspNet.Mvc.Test
var mockHttpContext = new Mock<DefaultHttpContext>(); var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestableController() var controller = new TestableController();
{ controller.ControllerContext.HttpContext = mockHttpContext.Object;
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor())
};
var input = new DisposableObject(); var input = new DisposableObject();
// Act // Act
@ -872,10 +866,9 @@ namespace Microsoft.AspNet.Mvc.Test
var mockHttpContext = new Mock<DefaultHttpContext>(); var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestableController() var controller = new TestableController();
{ controller.ControllerContext.HttpContext = mockHttpContext.Object;
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor())
};
var input = new DisposableObject(); var input = new DisposableObject();
// Act // Act
@ -927,10 +920,9 @@ namespace Microsoft.AspNet.Mvc.Test
var mockHttpContext = new Mock<DefaultHttpContext>(); var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestableController() var controller = new TestableController();
{ controller.ControllerContext.HttpContext = mockHttpContext.Object;
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor())
};
var input = new DisposableObject(); var input = new DisposableObject();
// Act // Act
@ -1153,10 +1145,9 @@ namespace Microsoft.AspNet.Mvc.Test
var mockHttpContext = new Mock<DefaultHttpContext>(); var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestableController() var controller = new TestableController();
{ controller.ControllerContext.HttpContext = mockHttpContext.Object;
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor())
};
var input = new DisposableObject(); var input = new DisposableObject();
// Act // Act
@ -1177,10 +1168,9 @@ namespace Microsoft.AspNet.Mvc.Test
var mockHttpContext = new Mock<DefaultHttpContext>(); var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestableController() var controller = new TestableController();
{ controller.ControllerContext.HttpContext = mockHttpContext.Object;
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor())
};
var input = new DisposableObject(); var input = new DisposableObject();
var serializerSettings = new JsonSerializerSettings(); var serializerSettings = new JsonSerializerSettings();
@ -1255,7 +1245,7 @@ namespace Microsoft.AspNet.Mvc.Test
.Callback((ModelBindingContext context) => .Callback((ModelBindingContext context) =>
{ {
Assert.Empty(context.ModelName); Assert.Empty(context.ModelName);
Assert.Same(valueProvider, context.ValueProvider); Assert.Same(valueProvider, Assert.IsType<CompositeValueProvider>(context.ValueProvider)[0]);
// Include and exclude should be null, resulting in property // Include and exclude should be null, resulting in property
// being included. // being included.
@ -1287,8 +1277,7 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Callback((ModelBindingContext context) => .Callback((ModelBindingContext context) =>
{ {
Assert.Equal(modelName, context.ModelName); Assert.Same(valueProvider, Assert.IsType<CompositeValueProvider>(context.ValueProvider)[0]);
Assert.Same(valueProvider, context.ValueProvider);
// Include and exclude should be null, resulting in property // Include and exclude should be null, resulting in property
// being included. // being included.
@ -1319,7 +1308,6 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Callback((ModelBindingContext context) => .Callback((ModelBindingContext context) =>
{ {
Assert.Equal(modelName, context.ModelName);
Assert.Same(valueProvider, context.ValueProvider); Assert.Same(valueProvider, context.ValueProvider);
// Include and exclude should be null, resulting in property // Include and exclude should be null, resulting in property
@ -1330,7 +1318,7 @@ namespace Microsoft.AspNet.Mvc.Test
.Returns(ModelBindingResult.NoResultAsync) .Returns(ModelBindingResult.NoResultAsync)
.Verifiable(); .Verifiable();
var controller = GetController(binder.Object, provider: null); var controller = GetController(binder.Object, valueProvider: null);
var model = new MyModel(); var model = new MyModel();
// Act // Act
@ -1355,8 +1343,7 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Callback((ModelBindingContext context) => .Callback((ModelBindingContext context) =>
{ {
Assert.Equal(modelName, context.ModelName); Assert.Same(valueProvider, Assert.IsType<CompositeValueProvider>(context.ValueProvider)[0]);
Assert.Same(valueProvider, context.ValueProvider);
Assert.True(context.PropertyFilter(context, "include1")); Assert.True(context.PropertyFilter(context, "include1"));
Assert.True(context.PropertyFilter(context, "include2")); Assert.True(context.PropertyFilter(context, "include2"));
@ -1392,7 +1379,6 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Callback((ModelBindingContext context) => .Callback((ModelBindingContext context) =>
{ {
Assert.Equal(modelName, context.ModelName);
Assert.Same(valueProvider, context.ValueProvider); Assert.Same(valueProvider, context.ValueProvider);
Assert.True(context.PropertyFilter(context, "include1")); Assert.True(context.PropertyFilter(context, "include1"));
@ -1404,7 +1390,7 @@ namespace Microsoft.AspNet.Mvc.Test
.Returns(ModelBindingResult.NoResultAsync) .Returns(ModelBindingResult.NoResultAsync)
.Verifiable(); .Verifiable();
var controller = GetController(binder.Object, provider: null); var controller = GetController(binder.Object, valueProvider: null);
var model = new MyModel(); var model = new MyModel();
@ -1421,13 +1407,18 @@ namespace Microsoft.AspNet.Mvc.Test
public async Task TryUpdateModel_IncludeExpressionOverload_UsesPassedArguments(string prefix) public async Task TryUpdateModel_IncludeExpressionOverload_UsesPassedArguments(string prefix)
{ {
// Arrange // Arrange
var valueProvider = new Mock<IValueProvider>();
valueProvider
.Setup(v => v.ContainsPrefix(prefix))
.Returns(true);
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
var valueProvider = Mock.Of<IValueProvider>();
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Callback((ModelBindingContext context) => .Callback((ModelBindingContext context) =>
{ {
Assert.Equal(prefix, context.ModelName); Assert.Same(
Assert.Same(valueProvider, context.ValueProvider); valueProvider.Object,
Assert.IsType<CompositeValueProvider>(context.ValueProvider)[0]);
Assert.True(context.PropertyFilter(context, "Property1")); Assert.True(context.PropertyFilter(context, "Property1"));
Assert.True(context.PropertyFilter(context, "Property2")); Assert.True(context.PropertyFilter(context, "Property2"));
@ -1439,7 +1430,7 @@ namespace Microsoft.AspNet.Mvc.Test
.Verifiable(); .Verifiable();
var controller = GetController(binder.Object, valueProvider); var controller = GetController(binder.Object, valueProvider.Object);
var model = new MyModel(); var model = new MyModel();
// Act // Act
@ -1456,12 +1447,15 @@ namespace Microsoft.AspNet.Mvc.Test
TryUpdateModel_IncludeExpressionWithValueProviderOverload_UsesPassedArguments(string prefix) TryUpdateModel_IncludeExpressionWithValueProviderOverload_UsesPassedArguments(string prefix)
{ {
// Arrange // Arrange
var binder = new Mock<IModelBinder>();
var valueProvider = new Mock<IValueProvider>(); var valueProvider = new Mock<IValueProvider>();
valueProvider
.Setup(v => v.ContainsPrefix(prefix))
.Returns(true);
var binder = new Mock<IModelBinder>();
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Callback((ModelBindingContext context) => .Callback((ModelBindingContext context) =>
{ {
Assert.Equal(prefix, context.ModelName);
Assert.Same(valueProvider.Object, context.ValueProvider); Assert.Same(valueProvider.Object, context.ValueProvider);
Assert.True(context.PropertyFilter(context, "Property1")); Assert.True(context.PropertyFilter(context, "Property1"));
@ -1473,7 +1467,7 @@ namespace Microsoft.AspNet.Mvc.Test
.Returns(ModelBindingResult.NoResultAsync) .Returns(ModelBindingResult.NoResultAsync)
.Verifiable(); .Verifiable();
var controller = GetController(binder.Object, provider: null); var controller = GetController(binder.Object, valueProvider: null);
var model = new MyModel(); var model = new MyModel();
// Act // Act
@ -1493,12 +1487,12 @@ namespace Microsoft.AspNet.Mvc.Test
(context, propertyName) => string.Equals(propertyName, "include1", StringComparison.OrdinalIgnoreCase) || (context, propertyName) => string.Equals(propertyName, "include1", StringComparison.OrdinalIgnoreCase) ||
string.Equals(propertyName, "include2", StringComparison.OrdinalIgnoreCase); string.Equals(propertyName, "include2", StringComparison.OrdinalIgnoreCase);
var binder = new Mock<IModelBinder>();
var valueProvider = Mock.Of<IValueProvider>(); var valueProvider = Mock.Of<IValueProvider>();
var binder = new Mock<IModelBinder>();
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Callback((ModelBindingContext context) => .Callback((ModelBindingContext context) =>
{ {
Assert.Equal(modelName, context.ModelName);
Assert.Same(valueProvider, context.ValueProvider); Assert.Same(valueProvider, context.ValueProvider);
Assert.True(context.PropertyFilter(context, "include1")); Assert.True(context.PropertyFilter(context, "include1"));
@ -1510,7 +1504,7 @@ namespace Microsoft.AspNet.Mvc.Test
.Returns(ModelBindingResult.NoResultAsync) .Returns(ModelBindingResult.NoResultAsync)
.Verifiable(); .Verifiable();
var controller = GetController(binder.Object, provider: null); var controller = GetController(binder.Object, valueProvider: null);
var model = new MyModel(); var model = new MyModel();
@ -1533,8 +1527,7 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Callback((ModelBindingContext context) => .Callback((ModelBindingContext context) =>
{ {
Assert.Equal(modelName, context.ModelName); Assert.Same(valueProvider, Assert.IsType<CompositeValueProvider>(context.ValueProvider)[0]);
Assert.Same(valueProvider, context.ValueProvider);
// Include and exclude should be null, resulting in property // Include and exclude should be null, resulting in property
// being included. // being included.
@ -1566,8 +1559,7 @@ namespace Microsoft.AspNet.Mvc.Test
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>())) binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Callback((ModelBindingContext context) => .Callback((ModelBindingContext context) =>
{ {
Assert.Equal(modelName, context.ModelName); Assert.Same(valueProvider, Assert.IsType<CompositeValueProvider>(context.ValueProvider)[0]);
Assert.Same(valueProvider, context.ValueProvider);
// Include and exclude should be null, resulting in property // Include and exclude should be null, resulting in property
// being included. // being included.
@ -1600,9 +1592,7 @@ namespace Microsoft.AspNet.Mvc.Test
httpContext.Setup(c => c.RequestServices) httpContext.Setup(c => c.RequestServices)
.Returns(serviceProvider); .Returns(serviceProvider);
controller.ActionContext = new ActionContext(httpContext.Object, controller.ControllerContext.HttpContext = httpContext.Object;
Mock.Of<RouteData>(),
new ActionDescriptor());
// Act // Act
var innerServiceProvider = controller.Resolver; var innerServiceProvider = controller.Resolver;
@ -1622,9 +1612,7 @@ namespace Microsoft.AspNet.Mvc.Test
httpContext.Setup(c => c.Request) httpContext.Setup(c => c.Request)
.Returns(request); .Returns(request);
controller.ActionContext = new ActionContext(httpContext.Object, controller.ControllerContext.HttpContext = httpContext.Object;
Mock.Of<RouteData>(),
new ActionDescriptor());
// Act // Act
var innerRequest = controller.Request; var innerRequest = controller.Request;
@ -1644,9 +1632,7 @@ namespace Microsoft.AspNet.Mvc.Test
httpContext.Setup(c => c.Response) httpContext.Setup(c => c.Response)
.Returns(response); .Returns(response);
controller.ActionContext = new ActionContext(httpContext.Object, controller.ControllerContext.HttpContext = httpContext.Object;
Mock.Of<RouteData>(),
new ActionDescriptor());
// Act // Act
var innerResponse = controller.Response; var innerResponse = controller.Response;
@ -1662,10 +1648,7 @@ namespace Microsoft.AspNet.Mvc.Test
var controller = new TestableController(); var controller = new TestableController();
var routeData = Mock.Of<RouteData>(); var routeData = Mock.Of<RouteData>();
controller.ControllerContext.RouteData = routeData;
controller.ActionContext = new ActionContext(Mock.Of<HttpContext>(),
routeData,
new ActionDescriptor());
// Act // Act
var innerRouteData = controller.RouteData; var innerRouteData = controller.RouteData;
@ -1692,8 +1675,12 @@ namespace Microsoft.AspNet.Mvc.Test
{ {
// Arrange // Arrange
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
var controller = GetController(binder.Object, provider: null); var controller = GetController(binder.Object, valueProvider: null);
controller.BindingContext.ValidatorProvider = Mock.Of<IModelValidatorProvider>(); controller.ControllerContext.ValidatorProviders = new List<IModelValidatorProvider>()
{
Mock.Of<IModelValidatorProvider>(),
};
var model = new TryValidateModelModel(); var model = new TryValidateModelModel();
// Act // Act
@ -1724,8 +1711,11 @@ namespace Microsoft.AspNet.Mvc.Test
.Callback<ModelValidatorProviderContext>(c => c.Validators.Add(validator1.Object)); .Callback<ModelValidatorProviderContext>(c => c.Validators.Add(validator1.Object));
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
var controller = GetController(binder.Object, provider: null); var controller = GetController(binder.Object, valueProvider: null);
controller.BindingContext.ValidatorProvider = provider.Object; controller.ControllerContext.ValidatorProviders = new List<IModelValidatorProvider>()
{
provider.Object,
};
// Act // Act
var result = controller.TryValidateModel(model, "Prefix"); var result = controller.TryValidateModel(model, "Prefix");
@ -1757,8 +1747,11 @@ namespace Microsoft.AspNet.Mvc.Test
.Callback<ModelValidatorProviderContext>(c => c.Validators.Add(validator1.Object)); .Callback<ModelValidatorProviderContext>(c => c.Validators.Add(validator1.Object));
var binder = new Mock<IModelBinder>(); var binder = new Mock<IModelBinder>();
var controller = GetController(binder.Object, provider: null); var controller = GetController(binder.Object, valueProvider: null);
controller.BindingContext.ValidatorProvider = provider.Object; controller.ControllerContext.ValidatorProviders = new List<IModelValidatorProvider>()
{
provider.Object,
};
// Act // Act
var result = controller.TryValidateModel(model); var result = controller.TryValidateModel(model);
@ -1777,7 +1770,7 @@ namespace Microsoft.AspNet.Mvc.Test
// Do not add a Mock validator provider to this test. Test is intended to demonstrate ease of unit testing // Do not add a Mock validator provider to this test. Test is intended to demonstrate ease of unit testing
// and exercise DataAnnotationsModelValidatorProvider, avoiding #3586 regressions. // and exercise DataAnnotationsModelValidatorProvider, avoiding #3586 regressions.
var model = new TryValidateModelModel(); var model = new TryValidateModelModel();
var controller = GetController(binder: null, provider: null); var controller = GetController(binder: null, valueProvider: null);
// Act // Act
var result = controller.TryValidateModel(model); var result = controller.TryValidateModel(model);
@ -1786,19 +1779,6 @@ namespace Microsoft.AspNet.Mvc.Test
Assert.True(controller.ModelState.IsValid); Assert.True(controller.ModelState.IsValid);
} }
[Fact]
public void TryValidateModelEmptyBindingContextThrowsException()
{
// Arrange
var controller = new TestableController();
var model = new TryValidateModelModel();
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(() => controller.TryValidateModel(model));
Assert.Equal("The 'BindingContext' property of 'Microsoft.AspNet.Mvc.Controller' must not be null.", exception.Message);
}
[Fact]
public void TempData_CanSetAndGetValues() public void TempData_CanSetAndGetValues()
{ {
// Arrange // Arrange
@ -1813,34 +1793,34 @@ namespace Microsoft.AspNet.Mvc.Test
Assert.Equal(input, result); Assert.Equal(input, result);
} }
private static Controller GetController(IModelBinder binder, IValueProvider provider) private static Controller GetController(IModelBinder binder, IValueProvider valueProvider)
{ {
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider(); var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary()); var viewData = new ViewDataDictionary(metadataProvider, new ModelStateDictionary());
var tempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>()); var tempData = new TempDataDictionary(Mock.Of<IHttpContextAccessor>(), Mock.Of<ITempDataProvider>());
var bindingContext = new ActionBindingContext() var controllerContext = new ControllerContext()
{ {
ModelBinder = binder, HttpContext = httpContext,
ValueProvider = provider, ModelBinders = new[] { binder, },
InputFormatters = new List<IInputFormatter>(), ValueProviders = new[] { valueProvider, },
ValidatorProvider = new DataAnnotationsModelValidatorProvider( ValidatorProviders = new []
options: null, {
stringLocalizerFactory: null) new DataAnnotationsModelValidatorProvider(options: null, stringLocalizerFactory: null),
},
}; };
return new TestableController() var controller = new TestableController()
{ {
ActionContext = actionContext, ControllerContext = controllerContext,
BindingContext = bindingContext,
MetadataProvider = metadataProvider, MetadataProvider = metadataProvider,
ViewData = viewData, ObjectValidator = new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider),
TempData = tempData, TempData = tempData,
ObjectValidator = new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider) ViewData = viewData,
}; };
return controller;
} }
private class MyModel private class MyModel

View File

@ -7,7 +7,7 @@ using System.IO;
using System.Text; using System.Text;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.Controllers;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
#if MOCK_SUPPORT #if MOCK_SUPPORT
using Moq; using Moq;
@ -154,10 +154,9 @@ namespace Microsoft.AspNet.Mvc
var fileName = "Created.html"; var fileName = "Created.html";
var mockHttpContext = new Mock<DefaultHttpContext>(); var mockHttpContext = new Mock<DefaultHttpContext>();
mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>())); mockHttpContext.Setup(x => x.Response.RegisterForDispose(It.IsAny<IDisposable>()));
var controller = new TestabilityController()
{ var controller = new TestabilityController();
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor()) controller.ControllerContext.HttpContext = mockHttpContext.Object;
};
// Act // Act
var result = controller.FileStream_Action(content, contentType, fileName); var result = controller.FileStream_Action(content, contentType, fileName);
@ -488,38 +487,38 @@ namespace Microsoft.AspNet.Mvc
var controller = new TestabilityController(); var controller = new TestabilityController();
// Assert // Assert
Assert.NotNull(controller.ActionContext); Assert.NotNull(controller.ControllerContext);
Assert.NotNull(controller.ActionContext.ModelState); Assert.NotNull(controller.ControllerContext.ModelState);
Assert.Null(controller.ActionContext.ActionDescriptor); Assert.Null(controller.ControllerContext.ActionDescriptor);
Assert.Null(controller.ActionContext.HttpContext); Assert.Null(controller.ControllerContext.HttpContext);
Assert.Null(controller.ActionContext.RouteData); Assert.Null(controller.ControllerContext.RouteData);
} }
[Fact] [Fact]
public void ActionContextDefaultConstructor_CanBeUsedForControllerActionContext() public void ContextDefaultConstructor_CanBeUsedForControllerContext()
{ {
// Arrange // Arrange
var actionContext = new ActionContext(); var controllerContext = new ControllerContext();
var controller = new TestabilityController(); var controller = new TestabilityController();
// Act // Act
controller.ActionContext = actionContext; controller.ControllerContext = controllerContext;
// Assert // Assert
Assert.Equal(actionContext.HttpContext, controller.HttpContext); Assert.Equal(controllerContext.HttpContext, controller.HttpContext);
Assert.Equal(actionContext.RouteData, controller.RouteData); Assert.Equal(controllerContext.RouteData, controller.RouteData);
Assert.Equal(actionContext.ModelState, controller.ModelState); Assert.Equal(controllerContext.ModelState, controller.ModelState);
} }
[Fact] [Fact]
public void ActionContextSetters_CanBeUsedWithControllerActionContext() public void ControllerContextSetter_CanBeUsedWithControllerActionContext()
{ {
// Arrange // Arrange
var actionDescriptor = new ActionDescriptor(); var actionDescriptor = new ControllerActionDescriptor();
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
var routeData = new RouteData(); var routeData = new RouteData();
var actionContext = new ActionContext() var controllerContext = new ControllerContext()
{ {
ActionDescriptor = actionDescriptor, ActionDescriptor = actionDescriptor,
HttpContext = httpContext, HttpContext = httpContext,
@ -529,33 +528,32 @@ namespace Microsoft.AspNet.Mvc
var controller = new TestabilityController(); var controller = new TestabilityController();
// Act // Act
controller.ActionContext = actionContext; controller.ControllerContext = controllerContext;
// Assert // Assert
Assert.Same(httpContext, controller.HttpContext); Assert.Same(httpContext, controller.HttpContext);
Assert.Same(routeData, controller.RouteData); Assert.Same(routeData, controller.RouteData);
Assert.Equal(actionContext.ModelState, controller.ModelState); Assert.Equal(controllerContext.ModelState, controller.ModelState);
Assert.Same(actionDescriptor, actionContext.ActionDescriptor); Assert.Same(actionDescriptor, controllerContext.ActionDescriptor);
} }
[Fact] [Fact]
public void ActionContextModelState_ShouldBeSameAsViewDataAndControllerModelState() public void ContextModelState_ShouldBeSameAsViewDataAndControllerModelState()
{ {
// Arrange // Arrange
var actionContext = new ActionContext();
var controller1 = new TestabilityController(); var controller1 = new TestabilityController();
var controller2 = new TestabilityController(); var controller2 = new TestabilityController();
// Act // Act
controller2.ActionContext = actionContext; controller2.ControllerContext = new ControllerContext();
// Assert // Assert
Assert.Equal(controller1.ModelState, controller1.ActionContext.ModelState); Assert.Equal(controller1.ModelState, controller1.ControllerContext.ModelState);
Assert.Equal(controller1.ModelState, controller1.ViewData.ModelState); Assert.Equal(controller1.ModelState, controller1.ViewData.ModelState);
Assert.Equal(actionContext.ModelState, controller2.ModelState); Assert.Equal(controller1.ControllerContext.ModelState, controller2.ModelState);
Assert.Equal(actionContext.ModelState, controller2.ActionContext.ModelState); Assert.Equal(controller1.ControllerContext.ModelState, controller2.ControllerContext.ModelState);
Assert.Equal(actionContext.ModelState, controller2.ViewData.ModelState); Assert.Equal(controller1.ControllerContext.ModelState, controller2.ViewData.ModelState);
} }
[Fact] [Fact]

View File

@ -9,7 +9,7 @@ using System.Text;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.Controllers;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -27,12 +27,11 @@ namespace System.Web.Http
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
httpContext.User = new ClaimsPrincipal(); httpContext.User = new ClaimsPrincipal();
var routeContext = new RouteContext(httpContext); var actionContext = new ActionContext(httpContext, new RouteData(), new ControllerActionDescriptor());
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
// Act // Act
controller.ActionContext = actionContext; controller.ControllerContext = new ControllerContext(actionContext);
// Assert // Assert
Assert.Same(httpContext, controller.Context); Assert.Same(httpContext, controller.Context);
@ -48,7 +47,7 @@ namespace System.Web.Http
// Act & Assert // Act & Assert
Assert.Null(controller.Context); Assert.Null(controller.Context);
Assert.Null(controller.ModelState); Assert.NotNull(controller.ModelState);
Assert.Null(controller.User); Assert.Null(controller.User);
} }

View File

@ -76,7 +76,6 @@ namespace System.Web.Http
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(
options, options,
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance)); NullLoggerFactory.Instance));

View File

@ -74,7 +74,6 @@ namespace System.Web.Http
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(
options, options,
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance)); NullLoggerFactory.Instance));

View File

@ -87,7 +87,6 @@ namespace System.Web.Http
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(
options, options,
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance)); NullLoggerFactory.Instance));

View File

@ -74,7 +74,6 @@ namespace System.Web.Http
var services = new ServiceCollection(); var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor( services.AddSingleton(new ObjectResultExecutor(
options, options,
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(), new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance)); NullLoggerFactory.Instance));

View File

@ -4,7 +4,6 @@
using System; using System;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ApplicationModels; using Microsoft.AspNet.Mvc.ApplicationModels;
using Microsoft.AspNet.Mvc.Controllers;
namespace ApplicationModelWebSite namespace ApplicationModelWebSite
{ {
@ -15,9 +14,7 @@ namespace ApplicationModelWebSite
[ActionName2("ActionName")] [ActionName2("ActionName")]
public string GetActionName() public string GetActionName()
{ {
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor; return ControllerContext.ActionDescriptor.Name;
return actionDescriptor.Name;
} }
private class ActionName2Attribute : Attribute, IActionModelConvention private class ActionName2Attribute : Attribute, IActionModelConvention

View File

@ -12,15 +12,13 @@ namespace ApplicationModelWebSite
{ {
public string GetControllerDescription() public string GetControllerDescription()
{ {
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor; return ControllerContext.ActionDescriptor.Properties["description"].ToString();
return actionDescriptor.Properties["description"].ToString();
} }
[ActionDescription("Specific Action Description")] [ActionDescription("Specific Action Description")]
public string GetActionSpecificDescription() public string GetActionSpecificDescription()
{ {
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor; return ControllerContext.ActionDescriptor.Properties["description"].ToString();
return actionDescriptor.Properties["description"].ToString();
} }
} }
} }

View File

@ -15,9 +15,7 @@ namespace ApplicationModelWebSite
{ {
public string GetControllerName() public string GetControllerName()
{ {
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor; return ControllerContext.ActionDescriptor.ControllerName;
return actionDescriptor.ControllerName;
} }
private class ControllerNameAttribute : Attribute, IControllerModelConvention private class ControllerNameAttribute : Attribute, IControllerModelConvention

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Controllers;
namespace ApplicationModelWebSite namespace ApplicationModelWebSite
{ {
@ -10,15 +9,13 @@ namespace ApplicationModelWebSite
{ {
public string GetCommonDescription() public string GetCommonDescription()
{ {
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor; return ControllerContext.ActionDescriptor.Properties["description"].ToString();
return actionDescriptor.Properties["description"].ToString();
} }
[HttpGet("Home/GetHelloWorld")] [HttpGet("Home/GetHelloWorld")]
public object GetHelloWorld([FromHeader] string helloWorld) public object GetHelloWorld([FromHeader] string helloWorld)
{ {
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor; return ControllerContext.ActionDescriptor.Properties["source"].ToString() + " - " + helloWorld;
return actionDescriptor.Properties["source"].ToString() + " - " + helloWorld;
} }
} }
} }

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Controllers;
namespace ApplicationModelWebSite.Controllers namespace ApplicationModelWebSite.Controllers
{ {
@ -11,8 +10,7 @@ namespace ApplicationModelWebSite.Controllers
[HttpGet("Lisence/GetLisence")] [HttpGet("Lisence/GetLisence")]
public string GetLisence() public string GetLisence()
{ {
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor; return ControllerContext.ActionDescriptor.Properties["lisence"].ToString();
return actionDescriptor.Properties["lisence"].ToString();
} }
} }
} }

View File

@ -16,7 +16,7 @@ namespace ApplicationModelWebSite
{ {
public string GetParameterMetadata([Cool] int? id) public string GetParameterMetadata([Cool] int? id)
{ {
return ActionContext.ActionDescriptor.Parameters[0].BindingInfo.BinderModelName; return ControllerContext.ActionDescriptor.Parameters[0].BindingInfo.BinderModelName;
} }
private class CoolAttribute : Attribute, IParameterModelConvention private class CoolAttribute : Attribute, IParameterModelConvention

View File

@ -95,8 +95,7 @@ namespace BasicWebSite.Controllers
public string GetApplicationDescription() public string GetApplicationDescription()
{ {
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor; return ControllerContext.ActionDescriptor.Properties["description"].ToString();
return actionDescriptor.Properties["description"].ToString();
} }
} }
} }

View File

@ -35,8 +35,8 @@ namespace BasicWebSite
private object GetData() private object GetData()
{ {
var routers = ActionContext.RouteData.Routers.Select(r => r.GetType().FullName).ToArray(); var routers = RouteData.Routers.Select(r => r.GetType().FullName).ToArray();
var dataTokens = ActionContext.RouteData.DataTokens; var dataTokens = RouteData.DataTokens;
return new return new
{ {

View File

@ -41,7 +41,7 @@ namespace BasicWebSite
} }
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
private class CamelCaseJsonFormattersAttribute : Attribute, IResourceFilter private class CamelCaseJsonFormattersAttribute : Attribute, IResourceFilter, IResultFilter
{ {
private readonly JsonSerializerSettings _serializerSettings; private readonly JsonSerializerSettings _serializerSettings;
@ -61,10 +61,22 @@ namespace BasicWebSite
// Instead remove and add new formatters which only effects the controllers this // Instead remove and add new formatters which only effects the controllers this
// attribute is decorated on. // attribute is decorated on.
context.InputFormatters.RemoveType<JsonInputFormatter>(); context.InputFormatters.RemoveType<JsonInputFormatter>();
context.OutputFormatters.RemoveType<JsonOutputFormatter>();
context.InputFormatters.Add(new JsonInputFormatter(_serializerSettings)); context.InputFormatters.Add(new JsonInputFormatter(_serializerSettings));
context.OutputFormatters.Add(new JsonOutputFormatter(_serializerSettings));
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
public void OnResultExecuting(ResultExecutingContext context)
{
var objectResult = context.Result as ObjectResult;
if (objectResult != null)
{
objectResult.Formatters.RemoveType<JsonOutputFormatter>();
objectResult.Formatters.Add(new JsonOutputFormatter(_serializerSettings));
}
} }
} }
} }

View File

@ -52,7 +52,7 @@ namespace ContentNegotiationWebSite
public IActionResult OverrideTheFallback_WithDefaultFormatters(int input) public IActionResult OverrideTheFallback_WithDefaultFormatters(int input)
{ {
var objectResult = new ObjectResult(input); var objectResult = new ObjectResult(input);
var optionsAccessor = ActionContext.HttpContext.RequestServices var optionsAccessor = HttpContext.RequestServices
.GetRequiredService<IOptions<MvcOptions>>(); .GetRequiredService<IOptions<MvcOptions>>();
objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter()); objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
foreach (var formatter in optionsAccessor.Value.OutputFormatters) foreach (var formatter in optionsAccessor.Value.OutputFormatters)

View File

@ -10,7 +10,7 @@ namespace CustomRouteWebSite.Controllers
[HttpGet("CustomRoute_Orders/{id}")] [HttpGet("CustomRoute_Orders/{id}")]
public string Index(int id) public string Index(int id)
{ {
return "Hello from " + ActionContext.RouteData.Values["locale"] + "."; return "Hello from " + RouteData.Values["locale"] + ".";
} }
} }
} }

View File

@ -6,6 +6,8 @@ using System.Linq;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Mvc.Formatters; using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.OptionsModel;
namespace FiltersWebSite.Controllers namespace FiltersWebSite.Controllers
{ {
@ -19,7 +21,7 @@ namespace FiltersWebSite.Controllers
return (dummy?.SampleInt ?? 0).ToString(); return (dummy?.SampleInt ?? 0).ToString();
} }
private class JsonOnlyAttribute : Attribute, IResourceFilter private class JsonOnlyAttribute : Attribute, IResultFilter
{ {
public void OnResourceExecuted(ResourceExecutedContext context) public void OnResourceExecuted(ResourceExecutedContext context)
{ {
@ -28,17 +30,26 @@ namespace FiltersWebSite.Controllers
public void OnResourceExecuting(ResourceExecutingContext context) public void OnResourceExecuting(ResourceExecutingContext context)
{ {
// InputFormatters collection contains JsonInputFormatter and JsonPatchInputFormatter. Picking // InputFormatters collection contains JsonInputFormatter and JsonPatchInputFormatter. Picking
// JsonInputFormatter by matching the typename // JsonInputFormatter by matching the type exactly rather than using OfType.
var jsonFormatter = context.InputFormatters.OfType<JsonInputFormatter>() var jsonFormatter = context.InputFormatters.OfType<JsonInputFormatter>()
.Where(t => t.GetType() == typeof(JsonInputFormatter)).FirstOrDefault(); .Where(t => t.GetType() == typeof(JsonInputFormatter)).FirstOrDefault();
context.InputFormatters.Clear(); context.InputFormatters.Clear();
context.InputFormatters.Add(jsonFormatter); context.InputFormatters.Add(jsonFormatter);
}
public void OnResultExecuted(ResultExecutedContext context)
{
}
public void OnResultExecuting(ResultExecutingContext context)
{
var options = context.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>();
var jsonFormatter = options.Value.OutputFormatters.OfType<JsonOutputFormatter>().Single();
// Update the output formatter collection to only return JSON. // Update the output formatter collection to only return JSON.
var jsonOutputFormatter = context.OutputFormatters.OfType<JsonOutputFormatter>().Single(); var result = (ObjectResult)context.Result;
context.OutputFormatters.Clear(); result.Formatters.Add(jsonFormatter);
context.OutputFormatters.Add(jsonOutputFormatter);
} }
} }
} }

View File

@ -12,11 +12,10 @@ namespace FormatterWebSite.Controllers
[HttpPost] [HttpPost]
public object ActionHandlesError([FromBody] DummyClass dummy) public object ActionHandlesError([FromBody] DummyClass dummy)
{ {
if (!ActionContext.ModelState.IsValid) if (!ModelState.IsValid)
{ {
// Body model binder normally reports errors for parameters using the empty name. // Body model binder normally reports errors for parameters using the empty name.
var parameterBindingErrors = ActionContext.ModelState["dummy"]?.Errors ?? var parameterBindingErrors = ModelState["dummy"]?.Errors ?? ModelState[string.Empty]?.Errors;
ActionContext.ModelState[string.Empty]?.Errors;
if (parameterBindingErrors != null && parameterBindingErrors.Count != 0) if (parameterBindingErrors != null && parameterBindingErrors.Count != 0)
{ {
return new ErrorInfo return new ErrorInfo

View File

@ -13,60 +13,60 @@ namespace InlineConstraintsWebSite.Controllers
{ {
public IDictionary<string, object> Index() public IDictionary<string, object> Index()
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
[HttpGet("{id:int?}")] [HttpGet("{id:int?}")]
public IDictionary<string, object> GetProductById(int id) public IDictionary<string, object> GetProductById(int id)
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
[HttpGet("{name:alpha}")] [HttpGet("{name:alpha}")]
public IDictionary<string, object> GetProductByName(string name) public IDictionary<string, object> GetProductByName(string name)
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
[HttpGet("{dateTime:datetime}")] [HttpGet("{dateTime:datetime}")]
public IDictionary<string, object> GetProductByManufacturingDate(DateTime dateTime) public IDictionary<string, object> GetProductByManufacturingDate(DateTime dateTime)
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
[HttpGet("{name:length(1,20)?}")] [HttpGet("{name:length(1,20)?}")]
public IDictionary<string, object> GetProductByCategoryName(string name) public IDictionary<string, object> GetProductByCategoryName(string name)
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
[HttpGet("{catId:int:range(10, 100)}")] [HttpGet("{catId:int:range(10, 100)}")]
public IDictionary<string, object> GetProductByCategoryId(int catId) public IDictionary<string, object> GetProductByCategoryId(int catId)
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
[HttpGet("{price:float?}")] [HttpGet("{price:float?}")]
public IDictionary<string, object> GetProductByPrice(float price) public IDictionary<string, object> GetProductByPrice(float price)
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
[HttpGet("{manId:int:min(10)?}")] [HttpGet("{manId:int:min(10)?}")]
public IDictionary<string, object> GetProductByManufacturerId(int manId) public IDictionary<string, object> GetProductByManufacturerId(int manId)
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
[HttpGet(@"{name:regex(^abc$)}")] [HttpGet(@"{name:regex(^abc$)}")]
public IDictionary<string, object> GetUserByName(string name) public IDictionary<string, object> GetUserByName(string name)
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
public string GetGeneratedLink() public string GetGeneratedLink()
{ {
var query = ActionContext.HttpContext.Request.Query; var query = HttpContext.Request.Query;
var values = query var values = query
.Where(kvp => kvp.Key != "newAction" && kvp.Key != "newController") .Where(kvp => kvp.Key != "newAction" && kvp.Key != "newController")
.ToDictionary(kvp => kvp.Key, kvp => (object)kvp.Value[0]); .ToDictionary(kvp => kvp.Key, kvp => (object)kvp.Value[0]);

View File

@ -11,12 +11,12 @@ namespace InlineConstraintsWebSite.Controllers
{ {
public IDictionary<string, object> GetStoreById(Guid id) public IDictionary<string, object> GetStoreById(Guid id)
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
public IDictionary<string, object> GetStoreByLocation(string location) public IDictionary<string, object> GetStoreByLocation(string location)
{ {
return ActionContext.RouteData.Values; return RouteData.Values;
} }
} }
} }

View File

@ -47,12 +47,12 @@ namespace ModelBindingWebSite.Controllers
public bool ActionWithCancellationToken(CancellationToken token) public bool ActionWithCancellationToken(CancellationToken token)
{ {
return token == ActionContext.HttpContext.RequestAborted; return token == HttpContext.RequestAborted;
} }
public bool ActionWithCancellationTokenModel(CancellationTokenModel wrapper) public bool ActionWithCancellationTokenModel(CancellationTokenModel wrapper)
{ {
return wrapper.CancellationToken == ActionContext.HttpContext.RequestAborted; return wrapper.CancellationToken == HttpContext.RequestAborted;
} }
[HttpGet("Home/ActionWithPersonFromUrlWithPrefix/{person.name}/{person.age}")] [HttpGet("Home/ActionWithPersonFromUrlWithPrefix/{person.name}/{person.age}")]

View File

@ -32,7 +32,7 @@ namespace ModelBindingWebSite.Controllers
_activated = true; _activated = true;
var viewData = new ViewDataDictionary<Person>(ViewData); var viewData = new ViewDataDictionary<Person>(ViewData);
var context = new ViewContext( var context = new ViewContext(
ActionContext, ControllerContext,
new TestView(), new TestView(),
viewData, viewData,
TempData, TempData,

View File

@ -4,13 +4,14 @@
using System; using System;
using System.Globalization; using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
namespace ValueProvidersWebSite namespace ValueProvidersWebSite
{ {
public class CustomValueProviderFactory : IValueProviderFactory public class CustomValueProviderFactory : IValueProviderFactory
{ {
public Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context) public Task<IValueProvider> GetValueProviderAsync(ActionContext context)
{ {
if (context.HttpContext.Request.Path.Value.Contains("TestValueProvider")) if (context.HttpContext.Request.Path.Value.Contains("TestValueProvider"))
{ {