Consume ModelBinding from Mvc
* Modify ReflectedActionInvoker to model bind parameters * Introduce IBodyReader for reading request bodies * Introduce types for per-action-context specific binders, value providers and body readers
This commit is contained in:
parent
9dc79df9cf
commit
e87f8c372c
|
|
@ -10,6 +10,22 @@ namespace MvcSample
|
||||||
return View("MyView", User());
|
return View("MyView", User());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Action that exercises query\form based model binding.
|
||||||
|
/// </summary>
|
||||||
|
public IActionResult SaveUser(User user)
|
||||||
|
{
|
||||||
|
return View("MyView", user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Action that exercises input formatter
|
||||||
|
/// </summary>
|
||||||
|
public IActionResult Post([FromBody]User user)
|
||||||
|
{
|
||||||
|
return View("MyView", user);
|
||||||
|
}
|
||||||
|
|
||||||
public IActionResult Something()
|
public IActionResult Something()
|
||||||
{
|
{
|
||||||
return new ContentResult
|
return new ContentResult
|
||||||
|
|
|
||||||
|
|
@ -40,14 +40,16 @@ namespace MvcSample
|
||||||
|
|
||||||
var endpoint = ActivatorUtilities.CreateInstance<RouteEndpoint>(mvcServices.Services);
|
var endpoint = ActivatorUtilities.CreateInstance<RouteEndpoint>(mvcServices.Services);
|
||||||
|
|
||||||
router.Add(new TemplateRoute(
|
|
||||||
endpoint,
|
|
||||||
"{controller}/{action}",
|
|
||||||
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) { { "controller", "Home" }, { "action", "Index" } }));
|
|
||||||
router.Add(new TemplateRoute(
|
router.Add(new TemplateRoute(
|
||||||
endpoint,
|
endpoint,
|
||||||
"{controller}",
|
"{controller}",
|
||||||
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) { { "controller", "Home" } }));
|
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) { { "controller", "Home" } }));
|
||||||
|
|
||||||
|
router.Add(new TemplateRoute(
|
||||||
|
endpoint,
|
||||||
|
"{controller}/{action}",
|
||||||
|
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) { { "controller", "Home" }, { "action", "Index" } }));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
private readonly IActionResultFactory _actionResultFactory;
|
private readonly IActionResultFactory _actionResultFactory;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly IControllerFactory _controllerFactory;
|
private readonly IControllerFactory _controllerFactory;
|
||||||
|
private readonly IActionBindingContextProvider _bindingProvider;
|
||||||
|
|
||||||
public ActionInvokerProvider(IActionResultFactory actionResultFactory,
|
public ActionInvokerProvider(IActionResultFactory actionResultFactory,
|
||||||
IControllerFactory controllerFactory,
|
IControllerFactory controllerFactory,
|
||||||
|
IActionBindingContextProvider bindingProvider,
|
||||||
IServiceProvider serviceProvider)
|
IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
_actionResultFactory = actionResultFactory;
|
_actionResultFactory = actionResultFactory;
|
||||||
_controllerFactory = controllerFactory;
|
_controllerFactory = controllerFactory;
|
||||||
|
_bindingProvider = bindingProvider;
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,21 +27,20 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public void Invoke(ActionInvokerProviderContext context, Action callNext)
|
public void Invoke(ActionInvokerProviderContext context, Action callNext)
|
||||||
{
|
{
|
||||||
var ad = context.ActionContext.ActionDescriptor as ReflectedActionDescriptor;
|
var actionDescriptor = context.ActionContext.ActionDescriptor as ReflectedActionDescriptor;
|
||||||
|
|
||||||
if (ad != null)
|
if (actionDescriptor != null)
|
||||||
{
|
{
|
||||||
context.Result = new ReflectedActionInvoker(
|
context.Result = new ReflectedActionInvoker(
|
||||||
context.ActionContext,
|
context.ActionContext,
|
||||||
ad,
|
actionDescriptor,
|
||||||
_actionResultFactory,
|
_actionResultFactory,
|
||||||
_controllerFactory,
|
_controllerFactory,
|
||||||
_serviceProvider);
|
_bindingProvider,
|
||||||
|
_serviceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
callNext();
|
callNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class BodyParameterInfo
|
||||||
|
{
|
||||||
|
public BodyParameterInfo(Type parameterType)
|
||||||
|
{
|
||||||
|
ParameterType = parameterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type ParameterType { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -3,21 +3,19 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.DependencyInjection;
|
using Microsoft.AspNet.DependencyInjection;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class DefaultActionSelector : IActionSelector
|
public class DefaultActionSelector : IActionSelector
|
||||||
{
|
{
|
||||||
private readonly INestedProviderManager<ActionDescriptorProviderContext> _actionDescriptorProvider;
|
private readonly INestedProviderManager<ActionDescriptorProviderContext> _actionDescriptorProvider;
|
||||||
private readonly IEnumerable<IValueProviderFactory> _valueProviderFactory;
|
private readonly IActionBindingContextProvider _bindingProvider;
|
||||||
|
|
||||||
public DefaultActionSelector(
|
public DefaultActionSelector(INestedProviderManager<ActionDescriptorProviderContext> actionDescriptorProvider,
|
||||||
INestedProviderManager<ActionDescriptorProviderContext> actionDescriptorProvider,
|
IActionBindingContextProvider bindingProvider)
|
||||||
IEnumerable<IValueProviderFactory> valueProviderFactories)
|
|
||||||
{
|
{
|
||||||
_actionDescriptorProvider = actionDescriptorProvider;
|
_actionDescriptorProvider = actionDescriptorProvider;
|
||||||
_valueProviderFactory = valueProviderFactories;
|
_bindingProvider = bindingProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ActionDescriptor> SelectAsync(RequestContext context)
|
public async Task<ActionDescriptor> SelectAsync(RequestContext context)
|
||||||
|
|
@ -61,9 +59,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
protected virtual async Task<ActionDescriptor> SelectBestCandidate(RequestContext context, List<ActionDescriptor> candidates)
|
protected virtual async Task<ActionDescriptor> SelectBestCandidate(RequestContext context, List<ActionDescriptor> candidates)
|
||||||
{
|
{
|
||||||
var valueProviders = await Task.WhenAll(_valueProviderFactory.Select(vpf => vpf.GetValueProviderAsync(context)));
|
|
||||||
valueProviders = valueProviders.Where(vp => vp != null).ToArray();
|
|
||||||
|
|
||||||
var applicableCandiates = new List<ActionDescriptorCandidate>();
|
var applicableCandiates = new List<ActionDescriptorCandidate>();
|
||||||
foreach (var action in candidates)
|
foreach (var action in candidates)
|
||||||
{
|
{
|
||||||
|
|
@ -72,18 +67,20 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
Action = action,
|
Action = action,
|
||||||
};
|
};
|
||||||
|
var actionContext = new ActionContext(context.HttpContext, context.RouteValues, action);
|
||||||
|
var actionBindingContext = await _bindingProvider.GetActionBindingContextAsync(actionContext);
|
||||||
|
|
||||||
foreach (var parameter in action.Parameters.Where(p => !p.Binding.IsFromBody))
|
foreach (var parameter in action.Parameters.Where(p => p.ParameterBindingInfo != null))
|
||||||
{
|
{
|
||||||
if (valueProviders.Any(vp => vp.ContainsPrefix(parameter.Binding.Prefix)))
|
if (actionBindingContext.ValueProvider.ContainsPrefix(parameter.ParameterBindingInfo.Prefix))
|
||||||
{
|
{
|
||||||
candidate.FoundParameters++;
|
candidate.FoundParameters++;
|
||||||
if (parameter.Binding.IsOptional)
|
if (parameter.IsOptional)
|
||||||
{
|
{
|
||||||
candidate.FoundOptionalParameters++;
|
candidate.FoundOptionalParameters++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!parameter.Binding.IsOptional)
|
else if (!parameter.IsOptional)
|
||||||
{
|
{
|
||||||
isApplicable = false;
|
isApplicable = false;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
|
using System.Reflection;
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -7,24 +6,29 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public ParameterDescriptor GetDescriptor(ParameterInfo parameter)
|
public ParameterDescriptor GetDescriptor(ParameterInfo parameter)
|
||||||
{
|
{
|
||||||
var bindingInfo = new ParameterBindingInfo()
|
bool isFromBody = IsFromBody(parameter);
|
||||||
{
|
|
||||||
IsOptional = parameter.IsOptional,
|
|
||||||
IsFromBody = IsFromBody(parameter),
|
|
||||||
Prefix = parameter.Name,
|
|
||||||
};
|
|
||||||
|
|
||||||
return new ParameterDescriptor()
|
return new ParameterDescriptor
|
||||||
{
|
{
|
||||||
Name = parameter.Name,
|
Name = parameter.Name,
|
||||||
Binding = bindingInfo,
|
IsOptional = parameter.IsOptional,
|
||||||
|
ParameterBindingInfo = isFromBody ? null : GetParameterBindingInfo(parameter),
|
||||||
|
BodyParameterInfo = isFromBody ? GetBodyParameterInfo(parameter) : null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool IsFromBody(ParameterInfo parameter)
|
public virtual bool IsFromBody(ParameterInfo parameter)
|
||||||
{
|
{
|
||||||
// Assume for now everything is read from value providers
|
return parameter.GetCustomAttribute<FromBodyAttribute>() != null;
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
private ParameterBindingInfo GetParameterBindingInfo(ParameterInfo parameter)
|
||||||
|
{
|
||||||
|
return new ParameterBindingInfo(parameter.Name, parameter.ParameterType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BodyParameterInfo GetBodyParameterInfo(ParameterInfo parameter)
|
||||||
|
{
|
||||||
|
return new BodyParameterInfo(parameter.ParameterType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Internal
|
||||||
|
{
|
||||||
|
public static class ActionBindingContextExtensions
|
||||||
|
{
|
||||||
|
public static InputFormatterContext CreateInputFormatterContext(this ActionBindingContext actionBindingContext,
|
||||||
|
ModelStateDictionary modelState,
|
||||||
|
ParameterDescriptor parameter)
|
||||||
|
{
|
||||||
|
var metadataProvider = actionBindingContext.MetadataProvider;
|
||||||
|
var parameterType = parameter.BodyParameterInfo.ParameterType;
|
||||||
|
var modelMetadata = metadataProvider.GetMetadataForType(modelAccessor: null, modelType: parameterType);
|
||||||
|
return new InputFormatterContext(modelMetadata, modelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModelBindingContext CreateModelBindingContext(this ActionBindingContext actionBindingContext,
|
||||||
|
ModelStateDictionary modelState,
|
||||||
|
ParameterDescriptor parameter)
|
||||||
|
{
|
||||||
|
var metadataProvider = actionBindingContext.MetadataProvider;
|
||||||
|
var parameterType = parameter.ParameterBindingInfo.ParameterType;
|
||||||
|
var modelMetadata = metadataProvider.GetMetadataForType(modelAccessor: null, modelType: parameterType);
|
||||||
|
|
||||||
|
return new ModelBindingContext
|
||||||
|
{
|
||||||
|
ModelName = parameter.Name,
|
||||||
|
ModelState = modelState,
|
||||||
|
ModelMetadata = modelMetadata,
|
||||||
|
ModelBinder = actionBindingContext.ModelBinder,
|
||||||
|
ValueProvider = actionBindingContext.ValueProvider,
|
||||||
|
MetadataProvider = metadataProvider,
|
||||||
|
HttpContext = actionBindingContext.ActionContext.HttpContext,
|
||||||
|
FallbackToEmptyPrefix = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class ActionBindingContext
|
||||||
|
{
|
||||||
|
public ActionBindingContext(ActionContext context,
|
||||||
|
IModelMetadataProvider metadataProvider,
|
||||||
|
IModelBinder modelBinder,
|
||||||
|
IValueProvider valueProvider,
|
||||||
|
IInputFormatter inputFormatter)
|
||||||
|
{
|
||||||
|
ActionContext = context;
|
||||||
|
MetadataProvider = metadataProvider;
|
||||||
|
ModelBinder = modelBinder;
|
||||||
|
ValueProvider = valueProvider;
|
||||||
|
InputFormatter = inputFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionContext ActionContext { get; private set; }
|
||||||
|
|
||||||
|
public IModelMetadataProvider MetadataProvider { get; private set; }
|
||||||
|
|
||||||
|
public IModelBinder ModelBinder { get; private set; }
|
||||||
|
|
||||||
|
public IValueProvider ValueProvider { get; private set; }
|
||||||
|
|
||||||
|
public IInputFormatter InputFormatter { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public class DefaultActionBindingContextProvider : IActionBindingContextProvider
|
||||||
|
{
|
||||||
|
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||||
|
private readonly IEnumerable<IModelBinder> _modelBinders;
|
||||||
|
private readonly IEnumerable<IValueProviderFactory> _valueProviderFactories;
|
||||||
|
private readonly IEnumerable<IInputFormatter> _bodyReaders;
|
||||||
|
|
||||||
|
public DefaultActionBindingContextProvider(IModelMetadataProvider modelMetadataProvider,
|
||||||
|
IEnumerable<IModelBinder> modelBinders,
|
||||||
|
IEnumerable<IValueProviderFactory> valueProviderFactories,
|
||||||
|
IEnumerable<IInputFormatter> bodyReaders)
|
||||||
|
{
|
||||||
|
_modelMetadataProvider = modelMetadataProvider;
|
||||||
|
_modelBinders = modelBinders.OrderBy(binder => binder.GetType() == typeof(ComplexModelDtoModelBinder) ? 1 : 0);
|
||||||
|
_valueProviderFactories = valueProviderFactories;
|
||||||
|
_bodyReaders = bodyReaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ActionBindingContext> GetActionBindingContextAsync(ActionContext actionContext)
|
||||||
|
{
|
||||||
|
var requestContext = new RequestContext(actionContext.HttpContext, actionContext.RouteValues);
|
||||||
|
var valueProviders = await Task.WhenAll(_valueProviderFactories.Select(factory => factory.GetValueProviderAsync(requestContext)));
|
||||||
|
valueProviders = valueProviders.Where(vp => vp != null)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return new ActionBindingContext(
|
||||||
|
actionContext,
|
||||||
|
_modelMetadataProvider,
|
||||||
|
new CompositeModelBinder(_modelBinders),
|
||||||
|
new CompositeValueProvider(valueProviders),
|
||||||
|
new CompositeInputFormatter(_bodyReaders)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter)]
|
||||||
|
public sealed class FromBodyAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
public interface IActionBindingContextProvider
|
||||||
|
{
|
||||||
|
Task<ActionBindingContext> GetActionBindingContextAsync(ActionContext actionContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
// This is a placeholder and is missing things that we'll need for real model binding
|
|
||||||
public class ParameterBindingInfo
|
public class ParameterBindingInfo
|
||||||
{
|
{
|
||||||
public bool IsOptional { get; set; }
|
public ParameterBindingInfo(string prefix, Type parameterType)
|
||||||
|
{
|
||||||
|
Prefix = prefix;
|
||||||
|
ParameterType = parameterType;
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsFromBody { get; set; }
|
public string Prefix { get; private set; }
|
||||||
|
|
||||||
public string Prefix { get; set; }
|
public Type ParameterType { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -6,6 +6,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public ParameterBindingInfo Binding { get; set; }
|
public bool IsOptional { get; set; }
|
||||||
|
|
||||||
|
public ParameterBindingInfo ParameterBindingInfo { get; set; }
|
||||||
|
|
||||||
|
public BodyParameterInfo BodyParameterInfo { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Abstractions;
|
using Microsoft.AspNet.Abstractions;
|
||||||
|
using Microsoft.AspNet.Mvc.Internal;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -13,21 +16,24 @@ namespace Microsoft.AspNet.Mvc
|
||||||
private readonly IActionResultFactory _actionResultFactory;
|
private readonly IActionResultFactory _actionResultFactory;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly IControllerFactory _controllerFactory;
|
private readonly IControllerFactory _controllerFactory;
|
||||||
|
private readonly IActionBindingContextProvider _bindingProvider;
|
||||||
|
|
||||||
public ReflectedActionInvoker(ActionContext actionContext,
|
public ReflectedActionInvoker(ActionContext actionContext,
|
||||||
ReflectedActionDescriptor descriptor,
|
ReflectedActionDescriptor descriptor,
|
||||||
IActionResultFactory actionResultFactory,
|
IActionResultFactory actionResultFactory,
|
||||||
IControllerFactory controllerFactory,
|
IControllerFactory controllerFactory,
|
||||||
|
IActionBindingContextProvider bindingContextProvider,
|
||||||
IServiceProvider serviceProvider)
|
IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
_actionContext = actionContext;
|
_actionContext = actionContext;
|
||||||
_descriptor = descriptor;
|
_descriptor = descriptor;
|
||||||
_actionResultFactory = actionResultFactory;
|
_actionResultFactory = actionResultFactory;
|
||||||
_controllerFactory = controllerFactory;
|
_controllerFactory = controllerFactory;
|
||||||
|
_bindingProvider = bindingContextProvider;
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task InvokeActionAsync()
|
public async Task InvokeActionAsync()
|
||||||
{
|
{
|
||||||
IActionResult actionResult = null;
|
IActionResult actionResult = null;
|
||||||
|
|
||||||
|
|
@ -39,7 +45,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Initialize(controller);
|
var modelState = new ModelStateDictionary();
|
||||||
|
InitializeController(controller, modelState);
|
||||||
|
|
||||||
var method = _descriptor.MethodInfo;
|
var method = _descriptor.MethodInfo;
|
||||||
|
|
||||||
|
|
@ -49,17 +56,19 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
object actionReturnValue = method.Invoke(controller, null);
|
var parameterValues = await GetParameterValues(modelState);
|
||||||
|
|
||||||
|
object actionReturnValue = method.Invoke(controller, GetArgumentValues(parameterValues));
|
||||||
|
|
||||||
actionResult = _actionResultFactory.CreateActionResult(method.ReturnType, actionReturnValue, _actionContext);
|
actionResult = _actionResultFactory.CreateActionResult(method.ReturnType, actionReturnValue, _actionContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This will probably move out once we got filters
|
// TODO: This will probably move out once we got filters
|
||||||
return actionResult.ExecuteResultAsync(_actionContext);
|
await actionResult.ExecuteResultAsync(_actionContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Initialize(object controller)
|
private void InitializeController(object controller, ModelStateDictionary modelState)
|
||||||
{
|
{
|
||||||
var controllerType = controller.GetType();
|
var controllerType = controller.GetType();
|
||||||
|
|
||||||
|
|
@ -72,6 +81,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
prop.SetValue(controller, _actionContext.HttpContext);
|
prop.SetValue(controller, _actionContext.HttpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (prop.Name == "ModelState" && prop.PropertyType == typeof(ModelStateDictionary))
|
||||||
|
{
|
||||||
|
prop.SetValue(controller, modelState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var method = controllerType.GetRuntimeMethods().FirstOrDefault(m => m.Name.Equals("Initialize", StringComparison.OrdinalIgnoreCase));
|
var method = controllerType.GetRuntimeMethods().FirstOrDefault(m => m.Name.Equals("Initialize", StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
@ -86,5 +99,57 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
method.Invoke(controller, args);
|
method.Invoke(controller, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<IDictionary<string, object>> GetParameterValues(ModelStateDictionary modelState)
|
||||||
|
{
|
||||||
|
var actionBindingContext = await _bindingProvider.GetActionBindingContextAsync(_actionContext);
|
||||||
|
var parameters = _descriptor.Parameters;
|
||||||
|
|
||||||
|
var parameterValues = new Dictionary<string, object>(parameters.Count, StringComparer.Ordinal);
|
||||||
|
for (int i = 0; i < parameters.Count; i++)
|
||||||
|
{
|
||||||
|
var parameter = parameters[i];
|
||||||
|
if (parameter.BodyParameterInfo != null)
|
||||||
|
{
|
||||||
|
var inputFormatterContext = actionBindingContext.CreateInputFormatterContext(
|
||||||
|
modelState,
|
||||||
|
parameter);
|
||||||
|
await actionBindingContext.InputFormatter.ReadAsync(inputFormatterContext);
|
||||||
|
parameterValues[parameter.Name] = inputFormatterContext.Model;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var modelBindingContext = actionBindingContext.CreateModelBindingContext(
|
||||||
|
modelState,
|
||||||
|
parameter);
|
||||||
|
actionBindingContext.ModelBinder.BindModel(modelBindingContext);
|
||||||
|
parameterValues[parameter.Name] = modelBindingContext.Model;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameterValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object[] GetArgumentValues(IDictionary<string, object> parameterValues)
|
||||||
|
{
|
||||||
|
var parameters = _descriptor.MethodInfo.GetParameters();
|
||||||
|
var arguments = new object[parameters.Length];
|
||||||
|
|
||||||
|
for (int i = 0; i < arguments.Length; i++)
|
||||||
|
{
|
||||||
|
object value;
|
||||||
|
if (parameterValues.TryGetValue(parameters[i].Name, out value))
|
||||||
|
{
|
||||||
|
arguments[i] = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arguments[i] = parameters[i].DefaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
public class CompositeInputFormatter : IInputFormatter
|
||||||
|
{
|
||||||
|
private IInputFormatter[] _bodyReaders;
|
||||||
|
|
||||||
|
public CompositeInputFormatter(IEnumerable<IInputFormatter> bodyReaders)
|
||||||
|
{
|
||||||
|
_bodyReaders = bodyReaders.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ReadAsync(InputFormatterContext context)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < _bodyReaders.Length; i++)
|
||||||
|
{
|
||||||
|
if (await _bodyReaders[i].ReadAsync(context))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
public interface IInputFormatter
|
||||||
|
{
|
||||||
|
Task<bool> ReadAsync(InputFormatterContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
public class InputFormatterContext
|
||||||
|
{
|
||||||
|
public InputFormatterContext(ModelMetadata metadata, ModelStateDictionary modelState)
|
||||||
|
{
|
||||||
|
Metadata = metadata;
|
||||||
|
ModelState = modelState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelMetadata Metadata { get; private set; }
|
||||||
|
|
||||||
|
public ModelStateDictionary ModelState { get; private set; }
|
||||||
|
|
||||||
|
public object Model { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
{
|
||||||
|
public class JsonInputFormatter : IInputFormatter
|
||||||
|
{
|
||||||
|
public Task<bool> ReadAsync(InputFormatterContext bindingContext)
|
||||||
|
{
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
@ -14,8 +15,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompositeValueProvider(IList<IValueProvider> list)
|
public CompositeValueProvider(IEnumerable<IValueProvider> valueProviders)
|
||||||
: base(list)
|
: base(valueProviders.ToList())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ using Microsoft.AspNet.DependencyInjection.NestedProviders;
|
||||||
using Microsoft.AspNet.FileSystems;
|
using Microsoft.AspNet.FileSystems;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.Razor;
|
using Microsoft.AspNet.Mvc.Razor;
|
||||||
using Microsoft.AspNet.Mvc.Razor.Compilation;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -28,8 +27,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
Add<IActionResultHelper, ActionResultHelper>();
|
Add<IActionResultHelper, ActionResultHelper>();
|
||||||
Add<IActionResultFactory, ActionResultFactory>();
|
Add<IActionResultFactory, ActionResultFactory>();
|
||||||
Add<IParameterDescriptorFactory, DefaultParameterDescriptorFactory>();
|
Add<IParameterDescriptorFactory, DefaultParameterDescriptorFactory>();
|
||||||
Add<IValueProviderFactory, RouteValueValueProviderFactory>();
|
|
||||||
Add<IValueProviderFactory, QueryStringValueProviderFactory>();
|
|
||||||
Add<IControllerAssemblyProvider, AppDomainControllerAssemblyProvider>();
|
Add<IControllerAssemblyProvider, AppDomainControllerAssemblyProvider>();
|
||||||
Add<IActionDiscoveryConventions, DefaultActionDiscoveryConventions>();
|
Add<IActionDiscoveryConventions, DefaultActionDiscoveryConventions>();
|
||||||
AddInstance<IFileSystem>(new PhysicalFileSystem(appRoot));
|
AddInstance<IFileSystem>(new PhysicalFileSystem(appRoot));
|
||||||
|
|
@ -48,11 +45,25 @@ namespace Microsoft.AspNet.Mvc
|
||||||
Add<IVirtualPathViewFactory, VirtualPathViewFactory>();
|
Add<IVirtualPathViewFactory, VirtualPathViewFactory>();
|
||||||
Add<IViewEngine, RazorViewEngine>();
|
Add<IViewEngine, RazorViewEngine>();
|
||||||
|
|
||||||
|
Add<IModelMetadataProvider, DataAnnotationsModelMetadataProvider>();
|
||||||
|
Add<IActionBindingContextProvider, DefaultActionBindingContextProvider>();
|
||||||
|
|
||||||
// This is temporary until DI has some magic for it
|
// This is temporary until DI has some magic for it
|
||||||
Add<INestedProviderManager<ActionDescriptorProviderContext>, NestedProviderManager<ActionDescriptorProviderContext>>();
|
Add<INestedProviderManager<ActionDescriptorProviderContext>, NestedProviderManager<ActionDescriptorProviderContext>>();
|
||||||
Add<INestedProviderManager<ActionInvokerProviderContext>, NestedProviderManager<ActionInvokerProviderContext>>();
|
Add<INestedProviderManager<ActionInvokerProviderContext>, NestedProviderManager<ActionInvokerProviderContext>>();
|
||||||
Add<INestedProvider<ActionDescriptorProviderContext>, ReflectedActionDescriptorProvider>();
|
Add<INestedProvider<ActionDescriptorProviderContext>, ReflectedActionDescriptorProvider>();
|
||||||
Add<INestedProvider<ActionInvokerProviderContext>, ActionInvokerProvider>();
|
Add<INestedProvider<ActionInvokerProviderContext>, ActionInvokerProvider>();
|
||||||
|
|
||||||
|
Add<IValueProviderFactory, RouteValueValueProviderFactory>();
|
||||||
|
Add<IValueProviderFactory, QueryStringValueProviderFactory>();
|
||||||
|
|
||||||
|
Add<IModelBinder, TypeConverterModelBinder>();
|
||||||
|
Add<IModelBinder, TypeMatchModelBinder>();
|
||||||
|
Add<IModelBinder, GenericModelBinder>();
|
||||||
|
Add<IModelBinder, MutableObjectModelBinder>();
|
||||||
|
Add<IModelBinder, ComplexModelDtoModelBinder>();
|
||||||
|
|
||||||
|
Add<IInputFormatter, JsonInputFormatter>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Add<T, TU>() where TU : T
|
private void Add<T, TU>() where TU : T
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue