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
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
VisualStudioVersion = 14.0.24711.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject

View File

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

View File

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

View File

@ -29,11 +29,6 @@ namespace Microsoft.AspNet.Mvc.Filters
/// </summary>
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>
/// Gets or sets the list of <see cref="IModelBinder"/> instances used by model binding.
/// </summary>

View File

@ -10,10 +10,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// <summary>
/// Gets a <see cref="IValueProvider"/> with values from the current request.
/// </summary>
/// <param name="context">The <see cref="ValueProviderFactoryContext"/>.</param>
/// <param name="context">The <see cref="ActionContext"/>.</param>
/// <returns>
/// A <see cref="Task"/> that when completed will yield a <see cref="IValueProvider"/> instance or <c>null</c>.
/// </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>
/// 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.
/// </summary>
[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.Filters;
using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
@ -30,12 +29,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
IControllerFactory controllerFactory,
ControllerActionDescriptor descriptor,
IReadOnlyList<IInputFormatter> inputFormatters,
IReadOnlyList<IOutputFormatter> outputFormatters,
IControllerActionArgumentBinder controllerActionArgumentBinder,
IReadOnlyList<IModelBinder> modelBinders,
IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
IReadOnlyList<IValueProviderFactory> valueProviderFactories,
IActionBindingContextAccessor actionBindingContextAccessor,
ILogger logger,
DiagnosticSource diagnosticSource,
int maxModelValidationErrors)
@ -43,11 +40,9 @@ namespace Microsoft.AspNet.Mvc.Controllers
actionContext,
filterProviders,
inputFormatters,
outputFormatters,
modelBinders,
modelValidatorProviders,
valueProviderFactories,
actionBindingContextAccessor,
logger,
diagnosticSource,
maxModelValidationErrors)
@ -77,11 +72,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(inputFormatters));
}
if (outputFormatters == null)
{
throw new ArgumentNullException(nameof(outputFormatters));
}
if (controllerActionArgumentBinder == null)
{
throw new ArgumentNullException(nameof(controllerActionArgumentBinder));
@ -102,11 +92,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(valueProviderFactories));
}
if (actionBindingContextAccessor == null)
{
throw new ArgumentNullException(nameof(actionBindingContextAccessor));
}
if (logger == null)
{
throw new ArgumentNullException(nameof(logger));
@ -132,9 +117,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
protected override object CreateInstance()
{
// The binding context is used in activation
Debug.Assert(ActionBindingContext != null);
return _controllerFactory.CreateController(ActionContext);
return _controllerFactory.CreateController(Context);
}
protected override void ReleaseInstance(object instance)
@ -165,21 +148,9 @@ namespace Microsoft.AspNet.Mvc.Controllers
return actionResult;
}
protected override Task<IDictionary<string, object>> BindActionArgumentsAsync(
ActionContext context,
ActionBindingContext bindingContext)
protected override Task<IDictionary<string, object>> BindActionArgumentsAsync()
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
return _argumentBinder.BindActionArgumentsAsync(context, bindingContext, Instance);
return _argumentBinder.BindActionArgumentsAsync(Context, Instance);
}
// 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.Filters;
using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Logging;
@ -23,10 +22,8 @@ namespace Microsoft.AspNet.Mvc.Controllers
private readonly IFilterProvider[] _filterProviders;
private readonly IReadOnlyList<IInputFormatter> _inputFormatters;
private readonly IReadOnlyList<IModelBinder> _modelBinders;
private readonly IReadOnlyList<IOutputFormatter> _outputFormatters;
private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders;
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
private readonly IActionBindingContextAccessor _actionBindingContextAccessor;
private readonly int _maxModelValidationErrors;
private readonly ILogger _logger;
private readonly DiagnosticSource _diagnosticSource;
@ -36,7 +33,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
IEnumerable<IFilterProvider> filterProviders,
IControllerActionArgumentBinder argumentBinder,
IOptions<MvcOptions> optionsAccessor,
IActionBindingContextAccessor actionBindingContextAccessor,
ILoggerFactory loggerFactory,
DiagnosticSource diagnosticSource)
{
@ -44,11 +40,9 @@ namespace Microsoft.AspNet.Mvc.Controllers
_filterProviders = filterProviders.OrderBy(item => item.Order).ToArray();
_argumentBinder = argumentBinder;
_inputFormatters = optionsAccessor.Value.InputFormatters.ToArray();
_outputFormatters = optionsAccessor.Value.OutputFormatters.ToArray();
_modelBinders = optionsAccessor.Value.ModelBinders.ToArray();
_modelValidatorProviders = optionsAccessor.Value.ModelValidatorProviders.ToArray();
_valueProviderFactories = optionsAccessor.Value.ValueProviderFactories.ToArray();
_actionBindingContextAccessor = actionBindingContextAccessor;
_maxModelValidationErrors = optionsAccessor.Value.MaxModelValidationErrors;
_logger = loggerFactory.CreateLogger<ControllerActionInvoker>();
_diagnosticSource = diagnosticSource;
@ -77,12 +71,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
_controllerFactory,
actionDescriptor,
_inputFormatters,
_outputFormatters,
_argumentBinder,
_modelBinders,
_modelValidatorProviders,
_valueProviderFactories,
_actionBindingContextAccessor,
_logger,
_diagnosticSource,
_maxModelValidationErrors);

View File

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

View File

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

View File

@ -12,58 +12,43 @@ namespace Microsoft.AspNet.Mvc.Controllers
{
public class DefaultControllerPropertyActivator : IControllerPropertyActivator
{
private readonly IActionBindingContextAccessor _actionBindingContextAccessor;
private readonly ConcurrentDictionary<Type, PropertyActivator<Contexts>[]> _activateActions;
private readonly Func<Type, PropertyActivator<Contexts>[]> _getPropertiesToActivate;
private readonly ConcurrentDictionary<Type, PropertyActivator<ControllerContext>[]> _activateActions;
private readonly Func<Type, PropertyActivator<ControllerContext>[]> _getPropertiesToActivate;
public DefaultControllerPropertyActivator(IActionBindingContextAccessor actionBindingContextAccessor)
public DefaultControllerPropertyActivator()
{
_actionBindingContextAccessor = actionBindingContextAccessor;
_activateActions = new ConcurrentDictionary<Type, PropertyActivator<Contexts>[]>();
_activateActions = new ConcurrentDictionary<Type, PropertyActivator<ControllerContext>[]>();
_getPropertiesToActivate = GetPropertiesToActivate;
}
public void Activate(ActionContext actionContext, object controller)
public void Activate(ControllerContext context, object controller)
{
var controllerType = controller.GetType();
var propertiesToActivate = _activateActions.GetOrAdd(
controllerType,
_getPropertiesToActivate);
var contexts = new Contexts()
{
ActionBindingContext = _actionBindingContextAccessor.ActionBindingContext,
ActionContext = actionContext,
};
for (var i = 0; i < propertiesToActivate.Length; 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;
activators = PropertyActivator<Contexts>.GetPropertiesToActivate(
IEnumerable<PropertyActivator<ControllerContext>> activators;
activators = PropertyActivator<ControllerContext>.GetPropertiesToActivate(
type,
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,
typeof(ActionBindingContextAttribute),
p => new PropertyActivator<Contexts>(p, c => c.ActionBindingContext)));
typeof(ControllerContextAttribute),
p => new PropertyActivator<ControllerContext>(p, c => c)));
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.Filters;
using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.ModelBinding;
@ -27,10 +26,8 @@ namespace Microsoft.AspNet.Mvc.Controllers
private readonly IReadOnlyList<IFilterProvider> _filterProviders;
private readonly IReadOnlyList<IInputFormatter> _inputFormatters;
private readonly IReadOnlyList<IModelBinder> _modelBinders;
private readonly IReadOnlyList<IOutputFormatter> _outputFormatters;
private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders;
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
private readonly IActionBindingContextAccessor _actionBindingContextAccessor;
private readonly DiagnosticSource _diagnosticSource;
private readonly int _maxModelValidationErrors;
@ -54,11 +51,9 @@ namespace Microsoft.AspNet.Mvc.Controllers
ActionContext actionContext,
IReadOnlyList<IFilterProvider> filterProviders,
IReadOnlyList<IInputFormatter> inputFormatters,
IReadOnlyList<IOutputFormatter> outputFormatters,
IReadOnlyList<IModelBinder> modelBinders,
IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
IReadOnlyList<IValueProviderFactory> valueProviderFactories,
IActionBindingContextAccessor actionBindingContextAccessor,
ILogger logger,
DiagnosticSource diagnosticSource,
int maxModelValidationErrors)
@ -78,11 +73,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(inputFormatters));
}
if (outputFormatters == null)
{
throw new ArgumentNullException(nameof(outputFormatters));
}
if (modelBinders == null)
{
throw new ArgumentNullException(nameof(modelBinders));
@ -98,11 +88,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(valueProviderFactories));
}
if (actionBindingContextAccessor == null)
{
throw new ArgumentNullException(nameof(actionBindingContextAccessor));
}
if (logger == null)
{
throw new ArgumentNullException(nameof(logger));
@ -113,33 +98,19 @@ namespace Microsoft.AspNet.Mvc.Controllers
throw new ArgumentNullException(nameof(diagnosticSource));
}
ActionContext = actionContext;
Context = new ControllerContext(actionContext);
_filterProviders = filterProviders;
_inputFormatters = inputFormatters;
_outputFormatters = outputFormatters;
_modelBinders = modelBinders;
_modelValidatorProviders = modelValidatorProviders;
_valueProviderFactories = valueProviderFactories;
_actionBindingContextAccessor = actionBindingContextAccessor;
Logger = logger;
_diagnosticSource = diagnosticSource;
_maxModelValidationErrors = maxModelValidationErrors;
}
protected ActionContext ActionContext { get; private set; }
protected ActionBindingContext ActionBindingContext
{
get
{
return _actionBindingContextAccessor.ActionBindingContext;
}
private set
{
_actionBindingContextAccessor.ActionBindingContext = value;
}
}
protected ControllerContext Context { get; }
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<IDictionary<string, object>> BindActionArgumentsAsync(
ActionContext context,
ActionBindingContext bindingContext);
protected abstract Task<IDictionary<string, object>> BindActionArgumentsAsync();
public virtual async Task InvokeAsync()
{
_filters = GetFilters();
_cursor = new FilterCursor(_filters);
ActionContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
Context.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
await InvokeAllAuthorizationFiltersAsync();
@ -215,14 +184,14 @@ namespace Microsoft.AspNet.Mvc.Controllers
private IFilterMetadata[] GetFilters()
{
var filterDescriptors = ActionContext.ActionDescriptor.FilterDescriptors;
var filterDescriptors = Context.ActionDescriptor.FilterDescriptors;
var items = new List<FilterItem>(filterDescriptors.Count);
for (var i = 0; i < filterDescriptors.Count; 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++)
{
_filterProviders[i].OnProvidersExecuting(context);
@ -266,7 +235,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
{
_cursor.Reset();
_authorizationContext = new AuthorizationContext(ActionContext, _filters);
_authorizationContext = new AuthorizationContext(Context, _filters);
return InvokeAuthorizationFilterAsync();
}
@ -332,12 +301,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
{
_cursor.Reset();
var context = new ResourceExecutingContext(ActionContext, _filters);
var context = new ResourceExecutingContext(Context, _filters);
context.InputFormatters = new FormatterCollection<IInputFormatter>(
new CopyOnWriteList<IInputFormatter>(_inputFormatters));
context.OutputFormatters = new FormatterCollection<IOutputFormatter>(
new CopyOnWriteList<IOutputFormatter>(_outputFormatters));
context.ModelBinders = new CopyOnWriteList<IModelBinder>(_modelBinders);
context.ValidatorProviders = new CopyOnWriteList<IModelValidatorProvider>(_modelValidatorProviders);
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
// binding.
ActionBindingContext = new ActionBindingContext();
ActionBindingContext.InputFormatters = _resourceExecutingContext.InputFormatters;
ActionBindingContext.OutputFormatters = _resourceExecutingContext.OutputFormatters;
ActionBindingContext.ModelBinder = new CompositeModelBinder(_resourceExecutingContext.ModelBinders);
ActionBindingContext.ValidatorProvider = new CompositeModelValidatorProvider(
_resourceExecutingContext.ValidatorProviders);
Context.InputFormatters = _resourceExecutingContext.InputFormatters;
Context.ModelBinders = _resourceExecutingContext.ModelBinders;
Context.ValidatorProviders = _resourceExecutingContext.ValidatorProviders;
var valueProviderFactoryContext = new ValueProviderFactoryContext(
ActionContext.HttpContext,
ActionContext.RouteData.Values);
var valueProviders = new List<IValueProvider>();
ActionBindingContext.ValueProvider = await CompositeValueProvider.CreateAsync(
_resourceExecutingContext.ValueProviderFactories,
valueProviderFactoryContext);
for (var i = 0; i < _resourceExecutingContext.ValueProviderFactories.Count; i++)
{
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
await InvokeAllExceptionFiltersAsync();
@ -587,7 +556,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
// 1) Call the filter (if we have an exception)
// 2) No-op (if we don't have an exception)
Debug.Assert(_exceptionContext == null);
_exceptionContext = new ExceptionContext(ActionContext, _filters);
_exceptionContext = new ExceptionContext(Context, _filters);
try
{
@ -617,10 +586,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
Instance = CreateInstance();
var arguments = await BindActionArgumentsAsync(ActionContext, ActionBindingContext);
var arguments = await BindActionArgumentsAsync();
_actionExecutingContext = new ActionExecutingContext(
ActionContext,
Context,
_filters,
arguments,
Instance);
@ -723,7 +692,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
try
{
_diagnosticSource.BeforeActionMethod(
ActionContext,
Context,
_actionExecutingContext.ActionArguments,
_actionExecutingContext.Controller);
@ -732,7 +701,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
finally
{
_diagnosticSource.AfterActionMethod(
ActionContext,
Context,
_actionExecutingContext.ActionArguments,
_actionExecutingContext.Controller,
result);
@ -765,7 +734,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
{
_cursor.Reset();
_resultExecutingContext = new ResultExecutingContext(ActionContext, _filters, result, Instance);
_resultExecutingContext = new ResultExecutingContext(Context, _filters, result, Instance);
await InvokeResultFilterAsync();
Debug.Assert(_resultExecutingContext != null);
@ -908,15 +877,15 @@ namespace Microsoft.AspNet.Mvc.Controllers
private async Task InvokeResultAsync(IActionResult result)
{
_diagnosticSource.BeforeActionResult(ActionContext, result);
_diagnosticSource.BeforeActionResult(Context, result);
try
{
await result.ExecuteResultAsync(ActionContext);
await result.ExecuteResultAsync(Context);
}
finally
{
_diagnosticSource.AfterActionResult(ActionContext, result);
_diagnosticSource.AfterActionResult(Context, result);
}
}

View File

@ -12,16 +12,12 @@ namespace Microsoft.AspNet.Mvc.Controllers
public interface IControllerActionArgumentBinder
{
/// <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
/// <paramref name="controller"/>.
/// </summary>
/// <param name="context">The action context assoicated with the current action.</param>
/// <param name="bindingContext">The <see cref="ActionBindingContext"/>.</param>
/// <param name="context">The <see cref="ControllerContext"/> associated with the current action.</param>
/// <param name="controller">The controller object which contains the action.</param>
Task<IDictionary<string, object>> BindActionArgumentsAsync(
ActionContext context,
ActionBindingContext bindingContext,
object controller);
Task<IDictionary<string, object>> BindActionArgumentsAsync(ControllerContext context, object controller);
}
}

View File

@ -9,11 +9,11 @@ namespace Microsoft.AspNet.Mvc.Controllers
public interface IControllerFactory
{
/// <summary>
/// Creates a new controller for the specified <paramref name="actionContext"/>.
/// Creates a new controller for the specified <paramref name="context"/>.
/// </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>
object CreateController(ActionContext actionContext);
object CreateController(ControllerContext context);
/// <summary>
/// Releases a controller instance.

View File

@ -5,6 +5,6 @@ namespace Microsoft.AspNet.Mvc.Controllers
{
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<IActionContextAccessor, ActionContextAccessor>();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IActionBindingContextAccessor, ActionBindingContextAccessor>();
services.TryAddSingleton<IUrlHelper, UrlHelper>();
services.TryAddSingleton<IHttpRequestStreamReaderFactory, MemoryPoolHttpRequestStreamReaderFactory>();
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>
public class ObjectResultExecutor
{
private readonly IActionBindingContextAccessor _bindingContextAccessor;
/// <summary>
/// Creates a new <see cref="ObjectResultExecutor"/>.
/// </summary>
/// <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>
public ObjectResultExecutor(
IOptions<MvcOptions> options,
IActionBindingContextAccessor bindingContextAccessor,
IHttpResponseStreamWriterFactory writerFactory,
ILoggerFactory loggerFactory)
{
@ -41,28 +38,16 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
throw new ArgumentNullException(nameof(options));
}
if (bindingContextAccessor == null)
{
throw new ArgumentNullException(nameof(bindingContextAccessor));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_bindingContextAccessor = bindingContextAccessor;
OptionsFormatters = options.Value.OutputFormatters;
RespectBrowserAcceptHeader = options.Value.RespectBrowserAcceptHeader;
Logger = loggerFactory.CreateLogger<ObjectResultExecutor>();
WriterFactory = writerFactory.CreateWriter;
}
/// <summary>
/// Gets the <see cref="ActionBindingContext"/> for the current request.
/// </summary>
protected ActionBindingContext BindingContext => _bindingContextAccessor.ActionBindingContext;
/// <summary>
/// Gets the <see cref="ILogger"/>.
@ -72,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
/// <summary>
/// Gets the list of <see cref="IOutputFormatter"/> instances from <see cref="MvcOptions"/>.
/// </summary>
protected IList<IOutputFormatter> OptionsFormatters { get; }
protected FormatterCollection<IOutputFormatter> OptionsFormatters { get; }
/// <summary>
/// Gets the value of <see cref="MvcOptions.RespectBrowserAcceptHeader"/>.
@ -109,7 +94,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
var formatters = result.Formatters;
if (formatters == null || formatters.Count == 0)
{
formatters = GetDefaultFormatters();
formatters = OptionsFormatters;
}
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.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
@ -30,48 +29,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// </summary>
/// <param name="valueProviders">The sequence of <see cref="IValueProvider"/> to add to this instance of
/// <see cref="CompositeValueProvider"/>.</param>
protected CompositeValueProvider(IList<IValueProvider> valueProviders)
public CompositeValueProvider(IList<IValueProvider> 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 />
public virtual bool ContainsPrefix(string prefix)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -261,7 +261,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
var result = new ObjectResult("input");
// This formatter won't write anything
result.Formatters = new List<IOutputFormatter>
result.Formatters = new FormatterCollection<IOutputFormatter>
{
new CannotWriteFormatter(),
};
@ -273,36 +273,6 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
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]
public async Task ExecuteAsync_FallsBackOnFormattersInOptions()
{
@ -450,19 +420,10 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
return httpContext;
}
private static TestObjectResultExecutor CreateExecutor(
IOptions<MvcOptions> options = null,
ActionBindingContext bindingContext = null)
private static TestObjectResultExecutor CreateExecutor(IOptions<MvcOptions> options = null)
{
var bindingContextAccessor = new ActionBindingContextAccessor();
if (bindingContext != null)
{
bindingContextAccessor.ActionBindingContext = bindingContext;
}
return new TestObjectResultExecutor(
options ?? new TestOptionsManager<MvcOptions>(),
bindingContextAccessor,
new TestHttpResponseStreamWriterFactory(),
NullLoggerFactory.Instance);
}
@ -516,10 +477,9 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
{
public TestObjectResultExecutor(
IOptions<MvcOptions> options,
IActionBindingContextAccessor bindingContextAccessor,
IHttpResponseStreamWriterFactory writerFactory,
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.Threading.Tasks;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.Primitives;
using Xunit;
@ -46,7 +48,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
Assert.Equal(CultureInfo.CurrentCulture, valueProvider.Culture);
}
private static ValueProviderFactoryContext CreateContext(string contentType)
private static ActionContext CreateContext(string contentType)
{
var context = new DefaultHttpContext();
context.Request.ContentType = contentType;
@ -56,9 +58,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
context.Request.Form = new FormCollection(new Dictionary<string, StringValues>());
}
return new ValueProviderFactoryContext(
context,
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase));
return new ActionContext(context, new RouteData(), new ActionDescriptor());
}
}
}

View File

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

View File

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

View File

@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Mvc
var result = new ObjectResult("Hello")
{
StatusCode = 404,
Formatters = new List<IOutputFormatter>()
Formatters = new FormatterCollection<IOutputFormatter>()
{
new NoOpOutputFormatter(),
},
@ -67,7 +67,6 @@ namespace Microsoft.AspNet.Mvc
var services = new ServiceCollection();
services.AddSingleton(new ObjectResultExecutor(
new TestOptionsManager<MvcOptions>(),
new ActionBindingContextAccessor(),
new TestHttpResponseStreamWriterFactory(),
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.
using System;
using System.Collections.Generic;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Controllers;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.OptionsModel;
namespace Microsoft.AspNet.Mvc.IntegrationTests
{
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(
Action<HttpRequest> updateRequest = null,
Action<MvcOptions> updateOptions = null)
{
var httpContext = GetHttpContext(updateRequest, updateOptions);
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()
{
HttpContext = httpContext,
InputFormatters = actionBindingContext.InputFormatters,
InputFormatters = controllerContext.InputFormatters,
MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
ValidatorProvider = actionBindingContext.ValidatorProvider,
ValueProvider = actionBindingContext.ValueProvider,
ModelBinder = actionBindingContext.ModelBinder
ValidatorProvider = new CompositeModelValidatorProvider(controllerContext.ValidatorProviders),
ValueProvider = new CompositeValueProvider(controllerContext.ValueProviders),
ModelBinder = new CompositeModelBinder(controllerContext.ModelBinders),
};
}
@ -68,47 +57,47 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
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();
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)
{
updateOptions(options);
serviceCollection.Configure(updateOptions);
}
var actionBindingContextAccessor =
httpContext.RequestServices.GetRequiredService<IActionBindingContextAccessor>();
actionBindingContextAccessor.ActionBindingContext = GetActionBindingContext(options, actionContext);
httpContext.RequestServices = serviceCollection.BuildServiceProvider();
return httpContext;
}
private static ActionBindingContext GetActionBindingContext(MvcOptions options, ActionContext actionContext)
private static ControllerContext GetControllerContext(MvcOptions options, ActionContext context)
{
var valueProviderFactoryContext = new ValueProviderFactoryContext(
actionContext.HttpContext,
actionContext.RouteData.Values);
var valueProviders = new List<IValueProvider>();
foreach (var factory in options.ValueProviderFactories)
{
var valueProvider = factory.GetValueProviderAsync(context).Result;
if (valueProvider != null)
{
valueProviders.Add(valueProvider);
}
}
var valueProvider = CompositeValueProvider.CreateAsync(
options.ValueProviderFactories,
valueProviderFactoryContext).Result;
return new ActionBindingContext()
return new ControllerContext(context)
{
InputFormatters = options.InputFormatters,
OutputFormatters = options.OutputFormatters, // Not required for model binding.
ValidatorProvider = new TestModelValidatorProvider(options.ModelValidatorProviders),
ModelBinder = new CompositeModelBinder(options.ModelBinders),
ValueProvider = valueProvider
ValidatorProviders = options.ModelValidatorProviders,
ModelBinders = options.ModelBinders,
ValueProviders = valueProviders
};
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -15,9 +15,7 @@ namespace ApplicationModelWebSite
{
public string GetControllerName()
{
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor;
return actionDescriptor.ControllerName;
return ControllerContext.ActionDescriptor.ControllerName;
}
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.
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Controllers;
namespace ApplicationModelWebSite
{
@ -10,15 +9,13 @@ namespace ApplicationModelWebSite
{
public string GetCommonDescription()
{
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor;
return actionDescriptor.Properties["description"].ToString();
return ControllerContext.ActionDescriptor.Properties["description"].ToString();
}
[HttpGet("Home/GetHelloWorld")]
public object GetHelloWorld([FromHeader] string helloWorld)
{
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor;
return actionDescriptor.Properties["source"].ToString() + " - " + helloWorld;
return ControllerContext.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.
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Controllers;
namespace ApplicationModelWebSite.Controllers
{
@ -11,8 +10,7 @@ namespace ApplicationModelWebSite.Controllers
[HttpGet("Lisence/GetLisence")]
public string GetLisence()
{
var actionDescriptor = (ControllerActionDescriptor)ActionContext.ActionDescriptor;
return actionDescriptor.Properties["lisence"].ToString();
return ControllerContext.ActionDescriptor.Properties["lisence"].ToString();
}
}
}

View File

@ -16,7 +16,7 @@ namespace ApplicationModelWebSite
{
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

View File

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

View File

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

View File

@ -41,7 +41,7 @@ namespace BasicWebSite
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
private class CamelCaseJsonFormattersAttribute : Attribute, IResourceFilter
private class CamelCaseJsonFormattersAttribute : Attribute, IResourceFilter, IResultFilter
{
private readonly JsonSerializerSettings _serializerSettings;
@ -61,10 +61,22 @@ namespace BasicWebSite
// Instead remove and add new formatters which only effects the controllers this
// attribute is decorated on.
context.InputFormatters.RemoveType<JsonInputFormatter>();
context.OutputFormatters.RemoveType<JsonOutputFormatter>();
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)
{
var objectResult = new ObjectResult(input);
var optionsAccessor = ActionContext.HttpContext.RequestServices
var optionsAccessor = HttpContext.RequestServices
.GetRequiredService<IOptions<MvcOptions>>();
objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
foreach (var formatter in optionsAccessor.Value.OutputFormatters)

View File

@ -10,7 +10,7 @@ namespace CustomRouteWebSite.Controllers
[HttpGet("CustomRoute_Orders/{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.Filters;
using Microsoft.AspNet.Mvc.Formatters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.OptionsModel;
namespace FiltersWebSite.Controllers
{
@ -19,7 +21,7 @@ namespace FiltersWebSite.Controllers
return (dummy?.SampleInt ?? 0).ToString();
}
private class JsonOnlyAttribute : Attribute, IResourceFilter
private class JsonOnlyAttribute : Attribute, IResultFilter
{
public void OnResourceExecuted(ResourceExecutedContext context)
{
@ -28,17 +30,26 @@ namespace FiltersWebSite.Controllers
public void OnResourceExecuting(ResourceExecutingContext context)
{
// 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>()
.Where(t => t.GetType() == typeof(JsonInputFormatter)).FirstOrDefault();
context.InputFormatters.Clear();
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.
var jsonOutputFormatter = context.OutputFormatters.OfType<JsonOutputFormatter>().Single();
context.OutputFormatters.Clear();
context.OutputFormatters.Add(jsonOutputFormatter);
var result = (ObjectResult)context.Result;
result.Formatters.Add(jsonFormatter);
}
}
}

View File

@ -12,11 +12,10 @@ namespace FormatterWebSite.Controllers
[HttpPost]
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.
var parameterBindingErrors = ActionContext.ModelState["dummy"]?.Errors ??
ActionContext.ModelState[string.Empty]?.Errors;
var parameterBindingErrors = ModelState["dummy"]?.Errors ?? ModelState[string.Empty]?.Errors;
if (parameterBindingErrors != null && parameterBindingErrors.Count != 0)
{
return new ErrorInfo

View File

@ -13,60 +13,60 @@ namespace InlineConstraintsWebSite.Controllers
{
public IDictionary<string, object> Index()
{
return ActionContext.RouteData.Values;
return RouteData.Values;
}
[HttpGet("{id:int?}")]
public IDictionary<string, object> GetProductById(int id)
{
return ActionContext.RouteData.Values;
return RouteData.Values;
}
[HttpGet("{name:alpha}")]
public IDictionary<string, object> GetProductByName(string name)
{
return ActionContext.RouteData.Values;
return RouteData.Values;
}
[HttpGet("{dateTime:datetime}")]
public IDictionary<string, object> GetProductByManufacturingDate(DateTime dateTime)
{
return ActionContext.RouteData.Values;
return RouteData.Values;
}
[HttpGet("{name:length(1,20)?}")]
public IDictionary<string, object> GetProductByCategoryName(string name)
{
return ActionContext.RouteData.Values;
return RouteData.Values;
}
[HttpGet("{catId:int:range(10, 100)}")]
public IDictionary<string, object> GetProductByCategoryId(int catId)
{
return ActionContext.RouteData.Values;
return RouteData.Values;
}
[HttpGet("{price:float?}")]
public IDictionary<string, object> GetProductByPrice(float price)
{
return ActionContext.RouteData.Values;
return RouteData.Values;
}
[HttpGet("{manId:int:min(10)?}")]
public IDictionary<string, object> GetProductByManufacturerId(int manId)
{
return ActionContext.RouteData.Values;
return RouteData.Values;
}
[HttpGet(@"{name:regex(^abc$)}")]
public IDictionary<string, object> GetUserByName(string name)
{
return ActionContext.RouteData.Values;
return RouteData.Values;
}
public string GetGeneratedLink()
{
var query = ActionContext.HttpContext.Request.Query;
var query = HttpContext.Request.Query;
var values = query
.Where(kvp => kvp.Key != "newAction" && kvp.Key != "newController")
.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)
{
return ActionContext.RouteData.Values;
return RouteData.Values;
}
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)
{
return token == ActionContext.HttpContext.RequestAborted;
return token == HttpContext.RequestAborted;
}
public bool ActionWithCancellationTokenModel(CancellationTokenModel wrapper)
{
return wrapper.CancellationToken == ActionContext.HttpContext.RequestAborted;
return wrapper.CancellationToken == HttpContext.RequestAborted;
}
[HttpGet("Home/ActionWithPersonFromUrlWithPrefix/{person.name}/{person.age}")]

View File

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

View File

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