Re-plumb ModelState.
Modified ModelState to only ever be created on the ActionContext and then plumbed/exposed it on ViewData and Controller. This will enable: ActionFilterContext's will have access to ModelState via its ActionContext member, allow HTMLHelpers to access ModelState via ViewData, and unify the locations of "source" model state. In the old world we used to copy/replace/instantiate new model state all over unnecessarily.
This commit is contained in:
parent
32d031c6eb
commit
5b6eb307ae
|
|
@ -15,7 +15,15 @@ namespace MvcSample.Web.RandomNameSpace
|
|||
|
||||
public IActionResultHelper Result { get; private set; }
|
||||
|
||||
public HttpContext Context { get; set; }
|
||||
public HttpContext Context
|
||||
{
|
||||
get
|
||||
{
|
||||
return ActionContext.HttpContext;
|
||||
}
|
||||
}
|
||||
|
||||
public ActionContext ActionContext { get; set; }
|
||||
|
||||
public string Index()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Routing;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
|
|
@ -12,6 +13,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
Router = router;
|
||||
RouteValues = routeValues;
|
||||
ActionDescriptor = actionDescriptor;
|
||||
ModelState = new ModelStateDictionary();
|
||||
}
|
||||
|
||||
public HttpContext HttpContext { get; private set; }
|
||||
|
|
@ -20,6 +22,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
public IDictionary<string, object> RouteValues { get; private set; }
|
||||
|
||||
public ModelStateDictionary ModelState { get; private set; }
|
||||
|
||||
public ActionDescriptor ActionDescriptor { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,30 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public class Controller
|
||||
{
|
||||
public void Initialize(IActionResultHelper actionResultHelper, IModelMetadataProvider metadataProvider)
|
||||
public void Initialize(IActionResultHelper actionResultHelper)
|
||||
{
|
||||
Result = actionResultHelper;
|
||||
ViewData = new ViewData<object>(metadataProvider);
|
||||
}
|
||||
|
||||
public IActionResultHelper Result { get; private set; }
|
||||
public HttpContext Context
|
||||
{
|
||||
get
|
||||
{
|
||||
return ActionContext.HttpContext;
|
||||
}
|
||||
}
|
||||
|
||||
public HttpContext Context { get; set; }
|
||||
public ModelStateDictionary ModelState
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewData.ModelState;
|
||||
}
|
||||
}
|
||||
|
||||
public ActionContext ActionContext { get; set; }
|
||||
|
||||
public IActionResultHelper Result { get; private set; }
|
||||
|
||||
public IUrlHelper Url { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
_activator = activator;
|
||||
}
|
||||
|
||||
public object CreateController(ActionContext actionContext, ModelStateDictionary modelState)
|
||||
public object CreateController(ActionContext actionContext)
|
||||
{
|
||||
var actionDescriptor = actionContext.ActionDescriptor as ReflectedActionDescriptor;
|
||||
if (actionDescriptor == null)
|
||||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var controller = _activator.CreateInstance(actionDescriptor.ControllerDescriptor.ControllerTypeInfo.AsType());
|
||||
|
||||
// TODO: How do we feed the controller with context (need DI improvements)
|
||||
InitializeController(controller, actionContext, modelState);
|
||||
InitializeController(controller, actionContext);
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
|
@ -47,21 +47,21 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
}
|
||||
|
||||
private void InitializeController(object controller, ActionContext actionContext, ModelStateDictionary modelState)
|
||||
private void InitializeController(object controller, ActionContext actionContext)
|
||||
{
|
||||
var controllerType = controller.GetType();
|
||||
|
||||
foreach (var prop in controllerType.GetRuntimeProperties())
|
||||
{
|
||||
if (prop.Name == "Context" && prop.PropertyType == typeof(HttpContext))
|
||||
if(prop.Name == "ActionContext" && prop.PropertyType.GetTypeInfo().IsAssignableFrom(typeof(ActionContext).GetTypeInfo()))
|
||||
{
|
||||
prop.SetValue(controller, actionContext.HttpContext);
|
||||
prop.SetValue(controller, actionContext);
|
||||
}
|
||||
else if (prop.Name == "ModelState" && prop.PropertyType == typeof(ModelStateDictionary))
|
||||
else if (prop.Name == "ViewData" && prop.PropertyType.GetTypeInfo().IsAssignableFrom(typeof(ViewData<object>).GetTypeInfo()))
|
||||
{
|
||||
prop.SetValue(controller, modelState);
|
||||
prop.SetValue(controller, new ViewData<object>(_serviceProvider.GetService<IModelMetadataProvider>(), actionContext.ModelState));
|
||||
}
|
||||
else if (prop.Name == "Url" && prop.PropertyType == typeof(IUrlHelper))
|
||||
else if (prop.Name == "Url" && prop.PropertyType.GetTypeInfo().IsAssignableFrom(typeof(IUrlHelper).GetTypeInfo()))
|
||||
{
|
||||
var urlHelper = new UrlHelper(
|
||||
actionContext.HttpContext,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IControllerFactory
|
||||
{
|
||||
object CreateController(ActionContext actionContext, ModelStateDictionary modelState);
|
||||
object CreateController(ActionContext actionContext);
|
||||
|
||||
void ReleaseController(object controller);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
PreArrangeFiltersInPipeline(filterProviderContext);
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
object controller = _controllerFactory.CreateController(_actionContext, modelState);
|
||||
var controller = _controllerFactory.CreateController(_actionContext);
|
||||
|
||||
if (controller == null)
|
||||
{
|
||||
|
|
@ -96,7 +95,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
if (actionResult == null)
|
||||
{
|
||||
var parameterValues = await GetParameterValues(modelState);
|
||||
var parameterValues = await GetParameterValues(_actionContext.ModelState);
|
||||
|
||||
var actionFilterContext = new ActionFilterContext(_actionContext,
|
||||
filterMetaItems,
|
||||
|
|
|
|||
|
|
@ -13,16 +13,32 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
private IModelMetadataProvider _metadataProvider;
|
||||
|
||||
public ViewData([NotNull] IModelMetadataProvider metadataProvider)
|
||||
: this(metadataProvider, new ModelStateDictionary())
|
||||
{
|
||||
}
|
||||
|
||||
public ViewData([NotNull] IModelMetadataProvider metadataProvider, [NotNull] ModelStateDictionary modelState)
|
||||
{
|
||||
ModelState = modelState;
|
||||
_data = new Dictionary<object, dynamic>();
|
||||
_metadataProvider = metadataProvider;
|
||||
}
|
||||
|
||||
public ViewData([NotNull] ViewData source)
|
||||
: this(source.MetadataProvider)
|
||||
{
|
||||
_data = source._data;
|
||||
_modelMetadata = source.ModelMetadata;
|
||||
_metadataProvider = source.MetadataProvider;
|
||||
|
||||
foreach (var entry in source.ModelState)
|
||||
{
|
||||
ModelState.Add(entry.Key, entry.Value);
|
||||
}
|
||||
|
||||
foreach (var entry in source)
|
||||
{
|
||||
_data.Add(entry.Key, entry.Value);
|
||||
}
|
||||
|
||||
SetModel(source.Model);
|
||||
}
|
||||
|
||||
|
|
@ -32,19 +48,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
set { SetModel(value); }
|
||||
}
|
||||
|
||||
public ModelStateDictionary ModelState { get; private set; }
|
||||
|
||||
public dynamic this[string index]
|
||||
{
|
||||
get
|
||||
{
|
||||
dynamic result;
|
||||
if (_data.TryGetValue(index, out result))
|
||||
{
|
||||
result = _data[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
|
||||
_data.TryGetValue(index, out result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -73,6 +85,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
get { return _metadataProvider; }
|
||||
}
|
||||
|
||||
public Dictionary<object, dynamic>.Enumerator GetEnumerator()
|
||||
{
|
||||
return _data.GetEnumerator();
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
_defaultModelMetadata = MetadataProvider.GetMetadataForType(null, typeof(TModel));
|
||||
}
|
||||
|
||||
public ViewData([NotNull] IModelMetadataProvider metadataProvider, [NotNull] ModelStateDictionary modelState)
|
||||
: base(metadataProvider, modelState)
|
||||
{
|
||||
}
|
||||
|
||||
public ViewData(ViewData source)
|
||||
: base(source)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
"net45": {},
|
||||
"k10": {
|
||||
"dependencies": {
|
||||
"Microsoft.CSharp": "4.0.0.0",
|
||||
"System.Collections": "4.0.0.0",
|
||||
"System.ComponentModel": "4.0.0.0",
|
||||
"System.Diagnostics.Contracts": "4.0.0.0",
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
"System.Globalization": "4.0.10.0",
|
||||
"System.IO": "4.0.0.0",
|
||||
"System.Linq": "4.0.0.0",
|
||||
"System.Linq.Expressions": "4.0.0.0",
|
||||
"System.Reflection": "4.0.10.0",
|
||||
"System.Reflection.Extensions": "4.0.0.0",
|
||||
"System.Resources.ResourceManager": "4.0.0.0",
|
||||
|
|
|
|||
Loading…
Reference in New Issue