Removing ModelMetadata.Model
This commit is contained in:
parent
ed8e5716ea
commit
9d5364cf9b
|
|
@ -4,8 +4,8 @@
|
|||
@functions {
|
||||
private object FormattedValue {
|
||||
get {
|
||||
if (ViewData.TemplateInfo.FormattedModelValue == ViewData.ModelMetadata.Model) {
|
||||
return String.Format(CultureInfo.CurrentCulture, "{0:0.00}", ViewData.ModelMetadata.Model);
|
||||
if (ViewData.TemplateInfo.FormattedModelValue == ViewData.ModelExplorer.Model) {
|
||||
return String.Format(CultureInfo.CurrentCulture, "{0:0.00}", ViewData.ModelExplorer.Model);
|
||||
}
|
||||
return ViewData.TemplateInfo.FormattedModelValue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
@functions {
|
||||
private object FormattedValue {
|
||||
get {
|
||||
if (ViewData.TemplateInfo.FormattedModelValue == ViewData.ModelMetadata.Model) {
|
||||
return string.Format(CultureInfo.CurrentCulture, "{0:0.00}", ViewData.ModelMetadata.Model);
|
||||
if (ViewData.TemplateInfo.FormattedModelValue == ViewData.ModelExplorer.Model) {
|
||||
return string.Format(CultureInfo.CurrentCulture, "{0:0.00}", ViewData.ModelExplorer.Model);
|
||||
}
|
||||
return ViewData.TemplateInfo.FormattedModelValue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1209,17 +1209,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
var modelMetadata = MetadataProvider.GetMetadataForType(
|
||||
modelAccessor: () => model,
|
||||
modelType: model.GetType());
|
||||
var modelExplorer = MetadataProvider.GetModelExplorerForType(model.GetType(), model);
|
||||
|
||||
var modelName = prefix ?? string.Empty;
|
||||
var validationContext = new ModelValidationContext(
|
||||
modelName,
|
||||
BindingContext.ValidatorProvider,
|
||||
ModelState,
|
||||
modelMetadata,
|
||||
containerMetadata: null);
|
||||
modelExplorer);
|
||||
|
||||
ObjectValidator.Validate(validationContext);
|
||||
return ModelState.IsValid;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
foreach (var parameter in actionDescriptor.Parameters)
|
||||
{
|
||||
var metadata = _modelMetadataProvider.GetMetadataForParameter(
|
||||
modelAccessor: null,
|
||||
methodInfo: actionDescriptor.MethodInfo,
|
||||
parameterName: parameter.Name);
|
||||
|
||||
|
|
@ -97,17 +96,19 @@ namespace Microsoft.AspNet.Mvc
|
|||
foreach (var parameter in parameterMetadata)
|
||||
{
|
||||
var parameterType = parameter.ModelType;
|
||||
|
||||
var modelBindingContext = GetModelBindingContext(parameter, modelState, operationBindingContext);
|
||||
var modelBindingResult = await bindingContext.ModelBinder.BindModelAsync(modelBindingContext);
|
||||
if (modelBindingResult != null && modelBindingResult.IsModelSet)
|
||||
{
|
||||
var modelExplorer = new ModelExplorer(_modelMetadataProvider, parameter, modelBindingResult.Model);
|
||||
|
||||
arguments[parameter.PropertyName] = modelBindingResult.Model;
|
||||
var validationContext = new ModelValidationContext(
|
||||
modelBindingResult.Key,
|
||||
bindingContext.ValidatorProvider,
|
||||
actionContext.ModelState,
|
||||
parameter,
|
||||
containerMetadata: null);
|
||||
modelBindingResult.Key,
|
||||
bindingContext.ValidatorProvider,
|
||||
actionContext.ModelState,
|
||||
modelExplorer);
|
||||
_validator.Validate(validationContext);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,9 +111,7 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
{
|
||||
apiDescription.ResponseType = runtimeReturnType;
|
||||
|
||||
apiDescription.ResponseModelMetadata = _modelMetadataProvider.GetMetadataForType(
|
||||
modelAccessor: null,
|
||||
modelType: runtimeReturnType);
|
||||
apiDescription.ResponseModelMetadata = _modelMetadataProvider.GetMetadataForType(runtimeReturnType);
|
||||
|
||||
var formats = GetResponseFormats(
|
||||
action,
|
||||
|
|
@ -436,7 +434,6 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
public void WalkParameter()
|
||||
{
|
||||
var modelMetadata = Context.MetadataProvider.GetMetadataForParameter(
|
||||
modelAccessor: null,
|
||||
methodInfo: Context.ActionDescriptor.MethodInfo,
|
||||
parameterName: Parameter.Name);
|
||||
|
||||
|
|
|
|||
|
|
@ -252,9 +252,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
throw new ArgumentException(message, nameof(modelType));
|
||||
}
|
||||
|
||||
var modelMetadata = metadataProvider.GetMetadataForType(
|
||||
modelAccessor: () => model,
|
||||
modelType: modelType);
|
||||
var modelMetadata = metadataProvider.GetMetadataForType(modelType);
|
||||
|
||||
var operationBindingContext = new OperationBindingContext
|
||||
{
|
||||
|
|
@ -266,6 +264,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
var modelBindingContext = new ModelBindingContext
|
||||
{
|
||||
Model = model,
|
||||
ModelMetadata = modelMetadata,
|
||||
ModelName = prefix,
|
||||
ModelState = modelState,
|
||||
|
|
@ -278,7 +277,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
var modelBindingResult = await modelBinder.BindModelAsync(modelBindingContext);
|
||||
if (modelBindingResult != null)
|
||||
{
|
||||
var modelValidationContext = new ModelValidationContext(modelBindingContext, modelMetadata);
|
||||
var modelExplorer = new ModelExplorer(metadataProvider, modelMetadata, modelBindingResult.Model);
|
||||
var modelValidationContext = new ModelValidationContext(modelBindingContext, modelExplorer);
|
||||
modelValidationContext.RootPrefix = prefix;
|
||||
objectModelValidator.Validate(modelValidationContext);
|
||||
return modelState.IsValid;
|
||||
|
|
@ -382,4 +382,4 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
|
|
@ -12,7 +13,7 @@ namespace Microsoft.AspNet.Mvc.Rendering.Expressions
|
|||
{
|
||||
public static class ExpressionMetadataProvider
|
||||
{
|
||||
public static ModelMetadata FromLambdaExpression<TModel, TResult>(
|
||||
public static ModelExplorer FromLambdaExpression<TModel, TResult>(
|
||||
[NotNull] Expression<Func<TModel, TResult>> expression,
|
||||
[NotNull] ViewDataDictionary<TModel> viewData,
|
||||
IModelMetadataProvider metadataProvider)
|
||||
|
|
@ -55,12 +56,11 @@ namespace Microsoft.AspNet.Mvc.Rendering.Expressions
|
|||
throw new InvalidOperationException(Resources.TemplateHelpers_TemplateLimitations);
|
||||
}
|
||||
|
||||
var container = viewData.Model;
|
||||
Func<object> modelAccessor = () =>
|
||||
Func<object, object> modelAccessor = (container) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return CachedExpressionCompiler.Process(expression)(container);
|
||||
return CachedExpressionCompiler.Process(expression)((TModel)container);
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
|
|
@ -68,18 +68,31 @@ namespace Microsoft.AspNet.Mvc.Rendering.Expressions
|
|||
}
|
||||
};
|
||||
|
||||
return GetMetadataFromProvider(
|
||||
modelAccessor,
|
||||
typeof(TResult),
|
||||
propertyName,
|
||||
container,
|
||||
containerType,
|
||||
metadataProvider);
|
||||
ModelMetadata metadata;
|
||||
if (propertyName == null)
|
||||
{
|
||||
// Ex:
|
||||
// m => 5 (arbitrary expression)
|
||||
// m => foo (arbitrary expression)
|
||||
// m => m.Widgets[0] (expression ending with non-property-access)
|
||||
metadata = metadataProvider.GetMetadataForType(typeof(TResult));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ex:
|
||||
// m => m.Color (simple property access)
|
||||
// m => m.Color.Red (nested property access)
|
||||
// m => m.Widgets[0].Size (expression ending with property-access)
|
||||
metadata = metadataProvider.GetMetadataForType(containerType).Properties[propertyName];
|
||||
}
|
||||
|
||||
return viewData.ModelExplorer.GetExplorerForExpression(metadata, modelAccessor);
|
||||
}
|
||||
|
||||
public static ModelMetadata FromStringExpression(string expression,
|
||||
[NotNull] ViewDataDictionary viewData,
|
||||
IModelMetadataProvider metadataProvider)
|
||||
public static ModelExplorer FromStringExpression(
|
||||
string expression,
|
||||
[NotNull] ViewDataDictionary viewData,
|
||||
IModelMetadataProvider metadataProvider)
|
||||
{
|
||||
if (string.IsNullOrEmpty(expression))
|
||||
{
|
||||
|
|
@ -88,93 +101,64 @@ namespace Microsoft.AspNet.Mvc.Rendering.Expressions
|
|||
}
|
||||
|
||||
var viewDataInfo = ViewDataEvaluator.Eval(viewData, expression);
|
||||
Type containerType = null;
|
||||
Type modelType = null;
|
||||
Func<object> modelAccessor = null;
|
||||
string propertyName = null;
|
||||
object container = null;
|
||||
|
||||
if (viewDataInfo == null)
|
||||
{
|
||||
// Try getting a property from ModelMetadata if we couldn't find an answer in ViewData
|
||||
var propertyExplorer = viewData.ModelExplorer.GetExplorerForProperty(expression);
|
||||
if (propertyExplorer != null)
|
||||
{
|
||||
return propertyExplorer;
|
||||
}
|
||||
}
|
||||
|
||||
if (viewDataInfo != null)
|
||||
{
|
||||
ModelExplorer containerExplorer = viewData.ModelExplorer;
|
||||
if (viewDataInfo.Container != null)
|
||||
{
|
||||
containerType = viewDataInfo.Container.GetType();
|
||||
container = viewDataInfo.Container;
|
||||
containerExplorer = metadataProvider.GetModelExplorerForType(
|
||||
viewDataInfo.Container.GetType(),
|
||||
viewDataInfo.Container);
|
||||
}
|
||||
|
||||
modelAccessor = () => viewDataInfo.Value;
|
||||
|
||||
if (viewDataInfo.PropertyInfo != null)
|
||||
{
|
||||
propertyName = viewDataInfo.PropertyInfo.Name;
|
||||
modelType = viewDataInfo.PropertyInfo.PropertyType;
|
||||
// We've identified a property access, which provides us with accurate metadata.
|
||||
var containerType = viewDataInfo.Container?.GetType() ?? viewDataInfo.PropertyInfo.DeclaringType;
|
||||
var containerMetadata = metadataProvider.GetMetadataForType(viewDataInfo.Container.GetType());
|
||||
var propertyMetadata = containerMetadata.Properties[viewDataInfo.PropertyInfo.Name];
|
||||
|
||||
Func<object, object> modelAccessor = (ignore) => viewDataInfo.Value;
|
||||
return containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor);
|
||||
}
|
||||
else if (viewDataInfo.Value != null)
|
||||
{
|
||||
// We only need to delay accessing properties (for LINQ to SQL)
|
||||
modelType = viewDataInfo.Value.GetType();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try getting a property from ModelMetadata if we couldn't find an answer in ViewData
|
||||
var propertyMetadata = viewData.ModelMetadata.Properties[expression];
|
||||
if (propertyMetadata != null)
|
||||
{
|
||||
return propertyMetadata;
|
||||
// We have a value, even though we may not know where it came from.
|
||||
var valueMetadata = metadataProvider.GetMetadataForType(viewDataInfo.Value.GetType());
|
||||
return containerExplorer.GetExplorerForExpression(valueMetadata, viewDataInfo.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return GetMetadataFromProvider(modelAccessor,
|
||||
modelType ?? typeof(string),
|
||||
propertyName,
|
||||
container,
|
||||
containerType,
|
||||
metadataProvider);
|
||||
// Treat the expression as string if we don't find anything better.
|
||||
var stringMetadata = metadataProvider.GetMetadataForType(typeof(string));
|
||||
return viewData.ModelExplorer.GetExplorerForExpression(stringMetadata, modelAccessor: null);
|
||||
}
|
||||
|
||||
private static ModelMetadata FromModel([NotNull] ViewDataDictionary viewData,
|
||||
IModelMetadataProvider metadataProvider)
|
||||
private static ModelExplorer FromModel(
|
||||
[NotNull] ViewDataDictionary viewData,
|
||||
IModelMetadataProvider metadataProvider)
|
||||
{
|
||||
if (viewData.ModelMetadata.ModelType == typeof(object))
|
||||
{
|
||||
// Use common simple type rather than object so e.g. Editor() at least generates a TextBox.
|
||||
return GetMetadataFromProvider(
|
||||
modelAccessor: null,
|
||||
modelType: typeof(string),
|
||||
propertyName: null,
|
||||
container: null,
|
||||
containerType: null,
|
||||
metadataProvider: metadataProvider);
|
||||
var model = viewData.Model == null ? null : Convert.ToString(viewData.Model, CultureInfo.CurrentCulture);
|
||||
return metadataProvider.GetModelExplorerForType(typeof(string), model);
|
||||
}
|
||||
else
|
||||
{
|
||||
return viewData.ModelMetadata;
|
||||
return viewData.ModelExplorer;
|
||||
}
|
||||
}
|
||||
|
||||
// An IModelMetadataProvider is not required unless this method is called. Therefore other methods in this
|
||||
// class lack [NotNull] attributes for their corresponding parameter.
|
||||
private static ModelMetadata GetMetadataFromProvider(Func<object> modelAccessor,
|
||||
Type modelType,
|
||||
string propertyName,
|
||||
object container,
|
||||
Type containerType,
|
||||
[NotNull] IModelMetadataProvider metadataProvider)
|
||||
{
|
||||
if (containerType != null && !string.IsNullOrEmpty(propertyName))
|
||||
{
|
||||
var metadata =
|
||||
metadataProvider.GetMetadataForProperty(modelAccessor, containerType, propertyName);
|
||||
if (metadata != null)
|
||||
{
|
||||
metadata.Container = container;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
return metadataProvider.GetMetadataForType(modelAccessor, modelType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
public static string CollectionTemplate(IHtmlHelper htmlHelper)
|
||||
{
|
||||
var model = htmlHelper.ViewData.ModelMetadata.Model;
|
||||
var model = htmlHelper.ViewData.Model;
|
||||
if (model == null)
|
||||
{
|
||||
return string.Empty;
|
||||
|
|
@ -136,14 +136,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
itemType = item.GetType();
|
||||
}
|
||||
|
||||
var metadata = metadataProvider.GetMetadataForType(() => item, itemType);
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(itemType, item);
|
||||
var fieldName = string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", fieldNameBase, index++);
|
||||
|
||||
var templateBuilder = new TemplateBuilder(
|
||||
viewEngine,
|
||||
htmlHelper.ViewContext,
|
||||
htmlHelper.ViewData,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
htmlFieldName: fieldName,
|
||||
templateName: null,
|
||||
readOnly: true,
|
||||
|
|
@ -163,10 +163,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
public static string DecimalTemplate(IHtmlHelper htmlHelper)
|
||||
{
|
||||
if (htmlHelper.ViewData.TemplateInfo.FormattedModelValue == htmlHelper.ViewData.ModelMetadata.Model)
|
||||
if (htmlHelper.ViewData.TemplateInfo.FormattedModelValue == htmlHelper.ViewData.Model)
|
||||
{
|
||||
htmlHelper.ViewData.TemplateInfo.FormattedModelValue =
|
||||
string.Format(CultureInfo.CurrentCulture, "{0:0.00}", htmlHelper.ViewData.ModelMetadata.Model);
|
||||
string.Format(CultureInfo.CurrentCulture, "{0:0.00}", htmlHelper.ViewData.Model);
|
||||
}
|
||||
|
||||
return StringTemplate(htmlHelper);
|
||||
|
|
@ -203,18 +203,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
var viewData = htmlHelper.ViewData;
|
||||
var templateInfo = viewData.TemplateInfo;
|
||||
var modelMetadata = viewData.ModelMetadata;
|
||||
var modelExplorer = viewData.ModelExplorer;
|
||||
var builder = new StringBuilder();
|
||||
|
||||
if (modelMetadata.Model == null)
|
||||
if (modelExplorer.Model == null)
|
||||
{
|
||||
return modelMetadata.NullDisplayText;
|
||||
return modelExplorer.Metadata.NullDisplayText;
|
||||
}
|
||||
|
||||
if (templateInfo.TemplateDepth > 1)
|
||||
{
|
||||
var text = modelMetadata.SimpleDisplayText;
|
||||
if (modelMetadata.HtmlEncode)
|
||||
var text = modelExplorer.GetSimpleDisplayText();
|
||||
if (modelExplorer.Metadata.HtmlEncode)
|
||||
{
|
||||
text = htmlHelper.Encode(text);
|
||||
}
|
||||
|
|
@ -224,9 +224,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
var serviceProvider = htmlHelper.ViewContext.HttpContext.RequestServices;
|
||||
var viewEngine = serviceProvider.GetRequiredService<ICompositeViewEngine>();
|
||||
var properties = modelMetadata.Properties.Where(metadata => ShouldShow(metadata, templateInfo));
|
||||
foreach (var propertyMetadata in properties)
|
||||
|
||||
foreach (var propertyExplorer in modelExplorer.Properties)
|
||||
{
|
||||
var propertyMetadata = propertyExplorer.Metadata;
|
||||
if (!ShouldShow(propertyExplorer, templateInfo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var divTag = new TagBuilder("div");
|
||||
|
||||
if (!propertyMetadata.HideSurroundingHtml)
|
||||
|
|
@ -250,7 +256,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
viewEngine,
|
||||
htmlHelper.ViewContext,
|
||||
htmlHelper.ViewData,
|
||||
propertyMetadata,
|
||||
propertyExplorer,
|
||||
htmlFieldName: propertyMetadata.PropertyName,
|
||||
templateName: null,
|
||||
readOnly: true,
|
||||
|
|
@ -267,12 +273,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static bool ShouldShow(ModelMetadata metadata, TemplateInfo templateInfo)
|
||||
private static bool ShouldShow(ModelExplorer modelExplorer, TemplateInfo templateInfo)
|
||||
{
|
||||
return
|
||||
metadata.ShowForDisplay &&
|
||||
!metadata.IsComplexType &&
|
||||
!templateInfo.Visited(metadata);
|
||||
modelExplorer.Metadata.ShowForDisplay &&
|
||||
!modelExplorer.Metadata.IsComplexType &&
|
||||
!templateInfo.Visited(modelExplorer);
|
||||
}
|
||||
|
||||
public static string StringTemplate(IHtmlHelper htmlHelper)
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public static string CollectionTemplate(IHtmlHelper htmlHelper)
|
||||
{
|
||||
var viewData = htmlHelper.ViewData;
|
||||
var model = viewData.ModelMetadata.Model;
|
||||
var model = viewData.Model;
|
||||
if (model == null)
|
||||
{
|
||||
return string.Empty;
|
||||
|
|
@ -96,14 +96,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
itemType = item.GetType();
|
||||
}
|
||||
|
||||
var metadata = metadataProvider.GetMetadataForType(() => item, itemType);
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(itemType, item);
|
||||
var fieldName = string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", fieldNameBase, index++);
|
||||
|
||||
var templateBuilder = new TemplateBuilder(
|
||||
viewEngine,
|
||||
htmlHelper.ViewContext,
|
||||
htmlHelper.ViewData,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
htmlFieldName: fieldName,
|
||||
templateName: null,
|
||||
readOnly: false,
|
||||
|
|
@ -123,10 +123,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
public static string DecimalTemplate(IHtmlHelper htmlHelper)
|
||||
{
|
||||
if (htmlHelper.ViewData.TemplateInfo.FormattedModelValue == htmlHelper.ViewData.ModelMetadata.Model)
|
||||
if (htmlHelper.ViewData.TemplateInfo.FormattedModelValue == htmlHelper.ViewData.Model)
|
||||
{
|
||||
htmlHelper.ViewData.TemplateInfo.FormattedModelValue =
|
||||
string.Format(CultureInfo.CurrentCulture, "{0:0.00}", htmlHelper.ViewData.ModelMetadata.Model);
|
||||
string.Format(CultureInfo.CurrentCulture, "{0:0.00}", htmlHelper.ViewData.Model);
|
||||
}
|
||||
|
||||
return StringTemplate(htmlHelper);
|
||||
|
|
@ -227,18 +227,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
var viewData = htmlHelper.ViewData;
|
||||
var templateInfo = viewData.TemplateInfo;
|
||||
var modelMetadata = viewData.ModelMetadata;
|
||||
var modelExplorer = viewData.ModelExplorer;
|
||||
var builder = new StringBuilder();
|
||||
|
||||
if (templateInfo.TemplateDepth > 1)
|
||||
{
|
||||
if (modelMetadata.Model == null)
|
||||
if (modelExplorer.Model == null)
|
||||
{
|
||||
return modelMetadata.NullDisplayText;
|
||||
return modelExplorer.Metadata.NullDisplayText;
|
||||
}
|
||||
|
||||
var text = modelMetadata.SimpleDisplayText;
|
||||
if (modelMetadata.HtmlEncode)
|
||||
var text = modelExplorer.GetSimpleDisplayText();
|
||||
if (modelExplorer.Metadata.HtmlEncode)
|
||||
{
|
||||
text = htmlHelper.Encode(text);
|
||||
}
|
||||
|
|
@ -248,9 +248,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
var serviceProvider = htmlHelper.ViewContext.HttpContext.RequestServices;
|
||||
var viewEngine = serviceProvider.GetRequiredService<ICompositeViewEngine>();
|
||||
var properties = modelMetadata.Properties.Where(metadata => ShouldShow(metadata, templateInfo));
|
||||
foreach (var propertyMetadata in properties)
|
||||
|
||||
foreach (var propertyExplorer in modelExplorer.Properties)
|
||||
{
|
||||
var propertyMetadata = propertyExplorer.Metadata;
|
||||
if (!ShouldShow(propertyExplorer, templateInfo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var divTag = new TagBuilder("div");
|
||||
|
||||
if (!propertyMetadata.HideSurroundingHtml)
|
||||
|
|
@ -278,7 +284,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
viewEngine,
|
||||
htmlHelper.ViewContext,
|
||||
htmlHelper.ViewData,
|
||||
propertyMetadata,
|
||||
propertyExplorer,
|
||||
htmlFieldName: propertyMetadata.PropertyName,
|
||||
templateName: null,
|
||||
readOnly: false,
|
||||
|
|
@ -311,12 +317,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
.ToString();
|
||||
}
|
||||
|
||||
private static bool ShouldShow(ModelMetadata metadata, TemplateInfo templateInfo)
|
||||
private static bool ShouldShow(ModelExplorer modelExplorer, TemplateInfo templateInfo)
|
||||
{
|
||||
return
|
||||
metadata.ShowForEdit &&
|
||||
!metadata.IsComplexType &&
|
||||
!templateInfo.Visited(metadata);
|
||||
modelExplorer.Metadata.ShowForEdit &&
|
||||
!modelExplorer.Metadata.IsComplexType &&
|
||||
!templateInfo.Visited(modelExplorer);
|
||||
}
|
||||
|
||||
public static string StringTemplate(IHtmlHelper htmlHelper)
|
||||
|
|
@ -376,7 +382,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
var metadata = htmlHelper.ViewData.ModelMetadata;
|
||||
var value = metadata.Model;
|
||||
var value = htmlHelper.ViewData.Model;
|
||||
if (htmlHelper.ViewData.TemplateInfo.FormattedModelValue != value && metadata.HasNonDefaultEditFormat)
|
||||
{
|
||||
return;
|
||||
|
|
@ -407,4 +413,4 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,20 +90,20 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public virtual TagBuilder GenerateCheckBox(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
bool? isChecked,
|
||||
object htmlAttributes)
|
||||
{
|
||||
if (metadata != null)
|
||||
if (modelExplorer != null)
|
||||
{
|
||||
// CheckBoxFor() case. That API does not support passing isChecked directly.
|
||||
Debug.Assert(!isChecked.HasValue);
|
||||
|
||||
if (metadata.Model != null)
|
||||
if (modelExplorer.Model != null)
|
||||
{
|
||||
bool modelChecked;
|
||||
if (Boolean.TryParse(metadata.Model.ToString(), out modelChecked))
|
||||
if (Boolean.TryParse(modelExplorer.Model.ToString(), out modelChecked))
|
||||
{
|
||||
isChecked = modelChecked;
|
||||
}
|
||||
|
|
@ -121,10 +121,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return GenerateInput(
|
||||
viewContext,
|
||||
InputType.CheckBox,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
value: "true",
|
||||
useViewData: (metadata == null && !isChecked.HasValue),
|
||||
useViewData: (modelExplorer == null && !isChecked.HasValue),
|
||||
isChecked: isChecked ?? false,
|
||||
setId: true,
|
||||
isExplicitValue: false,
|
||||
|
|
@ -135,7 +135,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public virtual TagBuilder GenerateHiddenForCheckbox(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression)
|
||||
{
|
||||
var tagBuilder = new TagBuilder("input");
|
||||
|
|
@ -202,7 +202,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public virtual TagBuilder GenerateHidden(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
bool useViewData,
|
||||
|
|
@ -219,7 +219,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return GenerateInput(
|
||||
viewContext,
|
||||
InputType.Hidden,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
value,
|
||||
useViewData,
|
||||
|
|
@ -233,12 +233,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public virtual TagBuilder GenerateLabel(
|
||||
[NotNull] ViewContext viewContext,
|
||||
[NotNull] ModelMetadata metadata,
|
||||
[NotNull] ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
string labelText,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var resolvedLabelText = labelText ?? metadata.DisplayName ?? metadata.PropertyName;
|
||||
var resolvedLabelText = labelText ??
|
||||
modelExplorer.Metadata.DisplayName ??
|
||||
modelExplorer.Metadata.PropertyName;
|
||||
if (resolvedLabelText == null)
|
||||
{
|
||||
resolvedLabelText =
|
||||
|
|
@ -263,7 +265,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public virtual TagBuilder GeneratePassword(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
object htmlAttributes)
|
||||
|
|
@ -272,7 +274,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return GenerateInput(
|
||||
viewContext,
|
||||
InputType.Password,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
value,
|
||||
useViewData: false,
|
||||
|
|
@ -286,14 +288,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public virtual TagBuilder GenerateRadioButton(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
bool? isChecked,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
|
||||
if (metadata == null)
|
||||
if (modelExplorer == null)
|
||||
{
|
||||
// RadioButton() case. Do not override checked attribute if isChecked is implicit.
|
||||
if (!isChecked.HasValue &&
|
||||
|
|
@ -322,7 +324,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
// Need a value to determine isChecked.
|
||||
Debug.Assert(value != null);
|
||||
|
||||
var model = metadata.Model;
|
||||
var model = modelExplorer.Model;
|
||||
var valueString = Convert.ToString(value, CultureInfo.CurrentCulture);
|
||||
isChecked = model != null &&
|
||||
string.Equals(model.ToString(), valueString, StringComparison.OrdinalIgnoreCase);
|
||||
|
|
@ -337,7 +339,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return GenerateInput(
|
||||
viewContext,
|
||||
InputType.Radio,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
value,
|
||||
useViewData: false,
|
||||
|
|
@ -365,7 +367,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public TagBuilder GenerateSelect(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string optionLabel,
|
||||
string expression,
|
||||
IEnumerable<SelectListItem> selectList,
|
||||
|
|
@ -375,7 +377,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
ICollection<string> ignored;
|
||||
return GenerateSelect(
|
||||
viewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
optionLabel,
|
||||
expression,
|
||||
selectList,
|
||||
|
|
@ -387,7 +389,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public virtual TagBuilder GenerateSelect(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string optionLabel,
|
||||
string expression,
|
||||
IEnumerable<SelectListItem> selectList,
|
||||
|
|
@ -428,9 +430,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
defaultValue = viewContext.ViewData.Eval(expression);
|
||||
}
|
||||
else if (metadata != null)
|
||||
else if (modelExplorer != null)
|
||||
{
|
||||
defaultValue = metadata.Model;
|
||||
defaultValue = modelExplorer.Model;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -469,7 +471,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
}
|
||||
|
||||
tagBuilder.MergeAttributes(GetValidationAttributes(viewContext, metadata, expression));
|
||||
tagBuilder.MergeAttributes(GetValidationAttributes(viewContext, modelExplorer, expression));
|
||||
|
||||
return tagBuilder;
|
||||
}
|
||||
|
|
@ -477,7 +479,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public virtual TagBuilder GenerateTextArea(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
int rows,
|
||||
int columns,
|
||||
|
|
@ -509,9 +511,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
value = modelState.Value.AttemptedValue;
|
||||
}
|
||||
else if (metadata.Model != null)
|
||||
else if (modelExplorer.Model != null)
|
||||
{
|
||||
value = metadata.Model.ToString();
|
||||
value = modelExplorer.Model.ToString();
|
||||
}
|
||||
|
||||
var tagBuilder = new TagBuilder("textarea");
|
||||
|
|
@ -528,7 +530,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
tagBuilder.MergeAttribute("name", fullName, true);
|
||||
tagBuilder.MergeAttributes(GetValidationAttributes(viewContext, metadata, expression));
|
||||
tagBuilder.MergeAttributes(GetValidationAttributes(viewContext, modelExplorer, expression));
|
||||
|
||||
// If there are any errors for a named field, we add this CSS attribute.
|
||||
if (modelState != null && modelState.Errors.Count > 0)
|
||||
|
|
@ -546,7 +548,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public virtual TagBuilder GenerateTextBox(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
string format,
|
||||
|
|
@ -556,10 +558,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return GenerateInput(
|
||||
viewContext,
|
||||
InputType.Text,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
value,
|
||||
useViewData: (metadata == null && value == null),
|
||||
useViewData: (modelExplorer == null && value == null),
|
||||
isChecked: false,
|
||||
setId: true,
|
||||
isExplicitValue: true,
|
||||
|
|
@ -726,17 +728,19 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression)
|
||||
{
|
||||
var validatorProvider = _bindingContextAccessor.Value.ValidatorProvider;
|
||||
metadata = metadata ??
|
||||
modelExplorer = modelExplorer ??
|
||||
ExpressionMetadataProvider.FromStringExpression(expression, viewContext.ViewData, _metadataProvider);
|
||||
var validationContext =
|
||||
new ClientModelValidationContext(metadata, _metadataProvider, viewContext.HttpContext.RequestServices);
|
||||
var validationContext = new ClientModelValidationContext(
|
||||
modelExplorer.Metadata,
|
||||
_metadataProvider,
|
||||
viewContext.HttpContext.RequestServices);
|
||||
|
||||
return validatorProvider
|
||||
.GetValidators(metadata)
|
||||
.GetValidators(modelExplorer.Metadata)
|
||||
.OfType<IClientModelValidator>()
|
||||
.SelectMany(v => v.GetClientValidationRules(validationContext));
|
||||
}
|
||||
|
|
@ -832,7 +836,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
protected virtual TagBuilder GenerateInput(
|
||||
[NotNull] ViewContext viewContext,
|
||||
InputType inputType,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
bool useViewData,
|
||||
|
|
@ -926,7 +930,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
|
||||
}
|
||||
|
||||
tagBuilder.MergeAttributes(GetValidationAttributes(viewContext, metadata, expression));
|
||||
tagBuilder.MergeAttributes(GetValidationAttributes(viewContext, modelExplorer, expression));
|
||||
|
||||
return tagBuilder;
|
||||
}
|
||||
|
|
@ -951,7 +955,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
// never rendered validation for a field with this name in this form.
|
||||
protected virtual IDictionary<string, object> GetValidationAttributes(
|
||||
ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression)
|
||||
{
|
||||
var formContext = viewContext.ClientValidationEnabled ? viewContext.FormContext : null;
|
||||
|
|
@ -967,7 +971,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
formContext.RenderedField(fullName, true);
|
||||
var clientRules = GetClientValidationRules(viewContext, metadata, expression);
|
||||
|
||||
var clientRules = GetClientValidationRules(viewContext, modelExplorer, expression);
|
||||
|
||||
return UnobtrusiveValidationAttributesGenerator.GetValidationAttributes(clientRules);
|
||||
}
|
||||
|
|
@ -1153,4 +1158,4 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return tagBuilder.ToString(TagRenderMode.Normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public HtmlString CheckBox(string expression, bool? isChecked, object htmlAttributes)
|
||||
{
|
||||
return GenerateCheckBox(
|
||||
metadata: null,
|
||||
modelExplorer: null,
|
||||
expression: expression,
|
||||
isChecked: isChecked,
|
||||
htmlAttributes: htmlAttributes);
|
||||
|
|
@ -282,15 +282,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public string DisplayName(string expression)
|
||||
{
|
||||
var metadata = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
return GenerateDisplayName(metadata, expression);
|
||||
var modelExplorer = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
return GenerateDisplayName(modelExplorer, expression);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DisplayText(string expression)
|
||||
{
|
||||
var metadata = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
return GenerateDisplayText(metadata);
|
||||
var modelExplorer = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
return GenerateDisplayText(modelExplorer);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -301,7 +301,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
object htmlAttributes)
|
||||
{
|
||||
return GenerateDropDown(
|
||||
metadata: null,
|
||||
modelExplorer: null,
|
||||
expression: expression,
|
||||
selectList: selectList,
|
||||
optionLabel: optionLabel,
|
||||
|
|
@ -315,10 +315,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
string htmlFieldName,
|
||||
object additionalViewData)
|
||||
{
|
||||
var metadata = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
var modelExplorer = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
|
||||
return GenerateEditor(
|
||||
metadata,
|
||||
modelExplorer,
|
||||
htmlFieldName ?? ExpressionHelper.GetExpressionText(expression),
|
||||
templateName,
|
||||
additionalViewData);
|
||||
|
|
@ -328,7 +328,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public HtmlString Hidden(string expression, object value, object htmlAttributes)
|
||||
{
|
||||
return GenerateHidden(
|
||||
metadata: null,
|
||||
modelExplorer: null,
|
||||
expression: expression,
|
||||
value: value,
|
||||
useViewData: (value == null),
|
||||
|
|
@ -344,9 +344,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public HtmlString Label(string expression, string labelText, object htmlAttributes)
|
||||
{
|
||||
var metadata = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
var modelExplorer = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
return GenerateLabel(
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
labelText,
|
||||
htmlAttributes);
|
||||
|
|
@ -356,7 +356,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public HtmlString ListBox(string expression, IEnumerable<SelectListItem> selectList, object htmlAttributes)
|
||||
{
|
||||
return GenerateListBox(
|
||||
metadata: null,
|
||||
modelExplorer: null,
|
||||
expression: expression,
|
||||
selectList: selectList,
|
||||
htmlAttributes: htmlAttributes);
|
||||
|
|
@ -388,7 +388,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return RenderPartialCoreAsync(partialViewName, model, viewData, ViewContext.Writer);
|
||||
}
|
||||
|
||||
protected virtual HtmlString GenerateDisplay(ModelMetadata metadata,
|
||||
protected virtual HtmlString GenerateDisplay(ModelExplorer modelExplorer,
|
||||
string htmlFieldName,
|
||||
string templateName,
|
||||
object additionalViewData)
|
||||
|
|
@ -396,7 +396,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
var templateBuilder = new TemplateBuilder(_viewEngine,
|
||||
ViewContext,
|
||||
ViewData,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
htmlFieldName,
|
||||
templateName,
|
||||
readOnly: true,
|
||||
|
|
@ -443,7 +443,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public HtmlString Password(string expression, object value, object htmlAttributes)
|
||||
{
|
||||
return GeneratePassword(
|
||||
metadata: null,
|
||||
modelExplorer: null,
|
||||
expression: expression,
|
||||
value: value,
|
||||
htmlAttributes: htmlAttributes);
|
||||
|
|
@ -453,7 +453,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public HtmlString RadioButton(string expression, object value, bool? isChecked, object htmlAttributes)
|
||||
{
|
||||
return GenerateRadioButton(
|
||||
metadata: null,
|
||||
modelExplorer: null,
|
||||
expression: expression,
|
||||
value: value,
|
||||
isChecked: isChecked,
|
||||
|
|
@ -535,19 +535,29 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public HtmlString TextArea(string expression, string value, int rows, int columns, object htmlAttributes)
|
||||
{
|
||||
var metadata = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
var modelExplorer = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
|
||||
if (value != null)
|
||||
{
|
||||
metadata.Model = value;
|
||||
// As a special case we allow treating a string value as a model of arbitrary type.
|
||||
// So pass through the string representation, even though the ModelMetadata might
|
||||
// be for some other type.
|
||||
//
|
||||
// We do this because thought we're displaying something as a string, we want to have
|
||||
// the right set of validation attributes.
|
||||
modelExplorer = new ModelExplorer(
|
||||
MetadataProvider,
|
||||
modelExplorer.Container,
|
||||
modelExplorer.Metadata,
|
||||
value);
|
||||
}
|
||||
|
||||
return GenerateTextArea(metadata, expression, rows, columns, htmlAttributes);
|
||||
return GenerateTextArea(modelExplorer, expression, rows, columns, htmlAttributes);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public HtmlString TextBox(string expression, object value, string format, object htmlAttributes)
|
||||
{
|
||||
return GenerateTextBox(metadata: null, expression: expression, value: value, format: format,
|
||||
return GenerateTextBox(modelExplorer: null, expression: expression, value: value, format: format,
|
||||
htmlAttributes: htmlAttributes);
|
||||
}
|
||||
|
||||
|
|
@ -568,18 +578,19 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
protected virtual HtmlString GenerateCheckBox(
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
bool? isChecked,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var checkbox = _htmlGenerator.GenerateCheckBox(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
isChecked,
|
||||
htmlAttributes);
|
||||
var hidden = _htmlGenerator.GenerateHiddenForCheckbox(ViewContext, metadata, expression);
|
||||
|
||||
var hidden = _htmlGenerator.GenerateHiddenForCheckbox(ViewContext, modelExplorer, expression);
|
||||
if (checkbox == null || hidden == null)
|
||||
{
|
||||
return HtmlString.Empty;
|
||||
|
|
@ -590,12 +601,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return new HtmlString(elements);
|
||||
}
|
||||
|
||||
protected virtual string GenerateDisplayName([NotNull] ModelMetadata metadata, string expression)
|
||||
protected virtual string GenerateDisplayName([NotNull] ModelExplorer modelExplorer, string expression)
|
||||
{
|
||||
// We don't call ModelMetadata.GetDisplayName here because
|
||||
// we want to fall back to the field name rather than the ModelType.
|
||||
// This is similar to how the GenerateLabel get the text of a label.
|
||||
var resolvedDisplayName = metadata.DisplayName ?? metadata.PropertyName;
|
||||
var resolvedDisplayName = modelExplorer.Metadata.DisplayName ?? modelExplorer.Metadata.PropertyName;
|
||||
if (resolvedDisplayName == null)
|
||||
{
|
||||
resolvedDisplayName =
|
||||
|
|
@ -605,13 +616,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return resolvedDisplayName;
|
||||
}
|
||||
|
||||
protected virtual string GenerateDisplayText(ModelMetadata metadata)
|
||||
protected virtual string GenerateDisplayText(ModelExplorer modelExplorer)
|
||||
{
|
||||
return metadata.SimpleDisplayText ?? string.Empty;
|
||||
return modelExplorer.GetSimpleDisplayText() ?? string.Empty;
|
||||
}
|
||||
|
||||
protected HtmlString GenerateDropDown(
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
IEnumerable<SelectListItem> selectList,
|
||||
string optionLabel,
|
||||
|
|
@ -619,7 +630,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
var tagBuilder = _htmlGenerator.GenerateSelect(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
optionLabel,
|
||||
expression: expression,
|
||||
selectList: selectList,
|
||||
|
|
@ -634,7 +645,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
protected virtual HtmlString GenerateEditor(
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string htmlFieldName,
|
||||
string templateName,
|
||||
object additionalViewData)
|
||||
|
|
@ -643,7 +654,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
_viewEngine,
|
||||
ViewContext,
|
||||
ViewData,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
htmlFieldName,
|
||||
templateName,
|
||||
readOnly: false,
|
||||
|
|
@ -742,7 +753,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
protected virtual HtmlString GenerateHidden(
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
bool useViewData,
|
||||
|
|
@ -751,7 +762,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
var tagBuilder =
|
||||
_htmlGenerator.GenerateHidden(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
value,
|
||||
useViewData,
|
||||
|
|
@ -773,14 +784,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
protected virtual HtmlString GenerateLabel(
|
||||
[NotNull] ModelMetadata metadata,
|
||||
[NotNull] ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
string labelText,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var tagBuilder = _htmlGenerator.GenerateLabel(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression: expression,
|
||||
labelText: labelText,
|
||||
htmlAttributes: htmlAttributes);
|
||||
|
|
@ -793,14 +804,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
protected HtmlString GenerateListBox(
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
IEnumerable<SelectListItem> selectList,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var tagBuilder = _htmlGenerator.GenerateSelect(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
optionLabel: null,
|
||||
expression: expression,
|
||||
selectList: selectList,
|
||||
|
|
@ -821,14 +832,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
protected virtual HtmlString GeneratePassword(
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var tagBuilder = _htmlGenerator.GeneratePassword(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
value,
|
||||
htmlAttributes);
|
||||
|
|
@ -841,7 +852,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
protected virtual HtmlString GenerateRadioButton(
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
bool? isChecked,
|
||||
|
|
@ -849,7 +860,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
var tagBuilder = _htmlGenerator.GenerateRadioButton(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
value,
|
||||
isChecked,
|
||||
|
|
@ -863,7 +874,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
protected virtual HtmlString GenerateTextArea(
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
int rows,
|
||||
int columns,
|
||||
|
|
@ -871,7 +882,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
var tagBuilder = _htmlGenerator.GenerateTextArea(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
rows,
|
||||
columns,
|
||||
|
|
@ -885,7 +896,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
protected virtual HtmlString GenerateTextBox(
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
string format,
|
||||
|
|
@ -893,7 +904,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
var tagBuilder = _htmlGenerator.GenerateTextBox(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
expression,
|
||||
value,
|
||||
format,
|
||||
|
|
@ -962,9 +973,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
{
|
||||
if (string.IsNullOrEmpty(expression))
|
||||
{
|
||||
// case 2(a): format the value from ModelMetadata for the current model
|
||||
var metadata = ViewData.ModelMetadata;
|
||||
resolvedValue = FormatValue(metadata.Model, format);
|
||||
// case 2(a): format the value from ViewData for the current model
|
||||
resolvedValue = FormatValue(ViewData.Model, format);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -983,10 +993,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression)
|
||||
{
|
||||
return _htmlGenerator.GetClientValidationRules(ViewContext, metadata, expression);
|
||||
return _htmlGenerator.GetClientValidationRules(ViewContext, modelExplorer, expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,8 +56,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
[NotNull] Expression<Func<TModel, bool>> expression,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var metadata = GetModelMetadata(expression);
|
||||
return GenerateCheckBox(metadata, GetExpressionName(expression), isChecked: null,
|
||||
var modelExplorer = GetModelExplorer(expression);
|
||||
return GenerateCheckBox(modelExplorer, GetExpressionName(expression), isChecked: null,
|
||||
htmlAttributes: htmlAttributes);
|
||||
}
|
||||
|
||||
|
|
@ -68,9 +68,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
string optionLabel,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression, ViewData, MetadataProvider);
|
||||
var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression(expression, ViewData, MetadataProvider);
|
||||
|
||||
return GenerateDropDown(metadata, ExpressionHelper.GetExpressionText(expression), selectList,
|
||||
return GenerateDropDown(modelExplorer, ExpressionHelper.GetExpressionText(expression), selectList,
|
||||
optionLabel, htmlAttributes);
|
||||
}
|
||||
|
||||
|
|
@ -81,11 +81,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
string htmlFieldName,
|
||||
object additionalViewData)
|
||||
{
|
||||
var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression,
|
||||
var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression(expression,
|
||||
ViewData,
|
||||
MetadataProvider);
|
||||
|
||||
return GenerateDisplay(metadata,
|
||||
return GenerateDisplay(modelExplorer,
|
||||
htmlFieldName ?? ExpressionHelper.GetExpressionText(expression),
|
||||
templateName,
|
||||
additionalViewData);
|
||||
|
|
@ -94,32 +94,32 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public string DisplayNameFor<TResult>([NotNull] Expression<Func<TModel, TResult>> expression)
|
||||
{
|
||||
var metadata = GetModelMetadata(expression);
|
||||
return GenerateDisplayName(metadata, ExpressionHelper.GetExpressionText(expression));
|
||||
var modelExplorer = GetModelExplorer(expression);
|
||||
return GenerateDisplayName(modelExplorer, ExpressionHelper.GetExpressionText(expression));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DisplayNameForInnerType<TModelItem, TResult>(
|
||||
[NotNull] Expression<Func<TModelItem, TResult>> expression)
|
||||
{
|
||||
var metadata = ExpressionMetadataProvider.FromLambdaExpression<TModelItem, TResult>(
|
||||
var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression<TModelItem, TResult>(
|
||||
expression,
|
||||
new ViewDataDictionary<TModelItem>(ViewData, model: null),
|
||||
MetadataProvider);
|
||||
|
||||
var expressionText = ExpressionHelper.GetExpressionText(expression);
|
||||
if (metadata == null)
|
||||
if (modelExplorer == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatHtmlHelper_NullModelMetadata(expressionText));
|
||||
}
|
||||
|
||||
return GenerateDisplayName(metadata, expressionText);
|
||||
return GenerateDisplayName(modelExplorer, expressionText);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string DisplayTextFor<TResult>([NotNull] Expression<Func<TModel, TResult>> expression)
|
||||
{
|
||||
return GenerateDisplayText(GetModelMetadata(expression));
|
||||
return GenerateDisplayText(GetModelExplorer(expression));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -129,10 +129,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
string htmlFieldName,
|
||||
object additionalViewData)
|
||||
{
|
||||
var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression, ViewData, MetadataProvider);
|
||||
var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression(expression, ViewData, MetadataProvider);
|
||||
|
||||
return GenerateEditor(
|
||||
metadata,
|
||||
modelExplorer,
|
||||
htmlFieldName ?? ExpressionHelper.GetExpressionText(expression),
|
||||
templateName,
|
||||
additionalViewData);
|
||||
|
|
@ -143,7 +143,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
[NotNull] Expression<Func<TModel, TResult>> expression,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var metadata = GetModelMetadata(expression);
|
||||
var metadata = GetModelExplorer(expression);
|
||||
return GenerateHidden(metadata, GetExpressionName(expression), metadata.Model, useViewData: false,
|
||||
htmlAttributes: htmlAttributes);
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
string labelText,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var metadata = GetModelMetadata(expression);
|
||||
var metadata = GetModelExplorer(expression);
|
||||
return GenerateLabel(metadata, ExpressionHelper.GetExpressionText(expression), labelText, htmlAttributes);
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +170,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
IEnumerable<SelectListItem> selectList,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var metadata = GetModelMetadata(expression);
|
||||
var metadata = GetModelExplorer(expression);
|
||||
var name = ExpressionHelper.GetExpressionText(expression);
|
||||
|
||||
return GenerateListBox(metadata, name, selectList, htmlAttributes);
|
||||
|
|
@ -188,7 +188,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
[NotNull] Expression<Func<TModel, TResult>> expression,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var metadata = GetModelMetadata(expression);
|
||||
var metadata = GetModelExplorer(expression);
|
||||
return GeneratePassword(metadata, GetExpressionName(expression), value: null,
|
||||
htmlAttributes: htmlAttributes);
|
||||
}
|
||||
|
|
@ -199,7 +199,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
[NotNull] object value,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var metadata = GetModelMetadata(expression);
|
||||
var metadata = GetModelExplorer(expression);
|
||||
return GenerateRadioButton(metadata, GetExpressionName(expression), value, isChecked: null,
|
||||
htmlAttributes: htmlAttributes);
|
||||
}
|
||||
|
|
@ -211,7 +211,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
int columns,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var metadata = GetModelMetadata(expression);
|
||||
var metadata = GetModelExplorer(expression);
|
||||
return GenerateTextArea(metadata, GetExpressionName(expression), rows, columns, htmlAttributes);
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
string format,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var metadata = GetModelMetadata(expression);
|
||||
var metadata = GetModelExplorer(expression);
|
||||
return GenerateTextBox(metadata, GetExpressionName(expression), metadata.Model, format, htmlAttributes);
|
||||
}
|
||||
|
||||
|
|
@ -230,16 +230,16 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return ExpressionHelper.GetExpressionText(expression);
|
||||
}
|
||||
|
||||
protected ModelMetadata GetModelMetadata<TResult>([NotNull] Expression<Func<TModel, TResult>> expression)
|
||||
protected ModelExplorer GetModelExplorer<TResult>([NotNull] Expression<Func<TModel, TResult>> expression)
|
||||
{
|
||||
var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression, ViewData, MetadataProvider);
|
||||
if (metadata == null)
|
||||
var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression(expression, ViewData, MetadataProvider);
|
||||
if (modelExplorer == null)
|
||||
{
|
||||
var expressionName = GetExpressionName(expression);
|
||||
throw new InvalidOperationException(Resources.FormatHtmlHelper_NullModelMetadata(expressionName));
|
||||
}
|
||||
|
||||
return metadata;
|
||||
return modelExplorer;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -258,7 +258,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <inheritdoc />
|
||||
public string ValueFor<TResult>([NotNull] Expression<Func<TModel, TResult>> expression, string format)
|
||||
{
|
||||
var metadata = GetModelMetadata(expression);
|
||||
var metadata = GetModelExplorer(expression);
|
||||
return GenerateValue(ExpressionHelper.GetExpressionText(expression), metadata.Model, format,
|
||||
useViewData: false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,23 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
TagBuilder GenerateAntiForgery([NotNull] ViewContext viewContext);
|
||||
|
||||
/// <summary>
|
||||
/// Generate a <input type="checkbox".../> element.
|
||||
/// </summary>
|
||||
/// <param name="viewContext">The <see cref="ViewContext"/> instance for the current scope.</param>
|
||||
/// <param name="modelExplorer">The <see cref="ModelExplorer"/> for the model.</param>
|
||||
/// <param name="expression">The model expression.</param>
|
||||
/// <param name="isChecked">The initial state of the checkbox element.</param>
|
||||
/// <param name="htmlAttributes">
|
||||
/// An <see cref="object"/> that contains the HTML attributes for the element. Alternatively, an
|
||||
/// <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A <see cref="TagBuilder"/> instance for the <input type="checkbox".../> element.
|
||||
/// </returns>
|
||||
TagBuilder GenerateCheckBox(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
bool? isChecked,
|
||||
object htmlAttributes);
|
||||
|
|
@ -46,7 +60,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// </summary>
|
||||
TagBuilder GenerateHiddenForCheckbox(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression);
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -107,7 +121,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
TagBuilder GenerateHidden(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
bool useViewData,
|
||||
|
|
@ -115,21 +129,21 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
TagBuilder GenerateLabel(
|
||||
[NotNull] ViewContext viewContext,
|
||||
[NotNull] ModelMetadata metadata,
|
||||
[NotNull] ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
string labelText,
|
||||
object htmlAttributes);
|
||||
|
||||
TagBuilder GeneratePassword(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
object htmlAttributes);
|
||||
|
||||
TagBuilder GenerateRadioButton(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
bool? isChecked,
|
||||
|
|
@ -146,7 +160,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
TagBuilder GenerateSelect(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string optionLabel,
|
||||
string expression,
|
||||
IEnumerable<SelectListItem> selectList,
|
||||
|
|
@ -155,7 +169,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
TagBuilder GenerateSelect(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string optionLabel,
|
||||
string expression,
|
||||
IEnumerable<SelectListItem> selectList,
|
||||
|
|
@ -165,7 +179,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
TagBuilder GenerateTextArea(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
int rows,
|
||||
int columns,
|
||||
|
|
@ -173,7 +187,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
TagBuilder GenerateTextBox(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression,
|
||||
object value,
|
||||
string format,
|
||||
|
|
@ -199,7 +213,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// </remarks>
|
||||
IEnumerable<ModelClientValidationRule> GetClientValidationRules(
|
||||
[NotNull] ViewContext viewContext,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
string expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
private IViewEngine _viewEngine;
|
||||
private ViewContext _viewContext;
|
||||
private ViewDataDictionary _viewData;
|
||||
private ModelExplorer _modelExplorer;
|
||||
private object _model;
|
||||
private ModelMetadata _metadata;
|
||||
private string _htmlFieldName;
|
||||
private string _templateName;
|
||||
|
|
@ -21,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public TemplateBuilder([NotNull] IViewEngine viewEngine,
|
||||
[NotNull] ViewContext viewContext,
|
||||
[NotNull] ViewDataDictionary viewData,
|
||||
[NotNull] ModelMetadata metadata,
|
||||
[NotNull] ModelExplorer modelExplorer,
|
||||
string htmlFieldName,
|
||||
string templateName,
|
||||
bool readOnly,
|
||||
|
|
@ -30,45 +32,51 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
_viewEngine = viewEngine;
|
||||
_viewContext = viewContext;
|
||||
_viewData = viewData;
|
||||
_metadata = metadata;
|
||||
_modelExplorer = modelExplorer;
|
||||
_htmlFieldName = htmlFieldName;
|
||||
_templateName = templateName;
|
||||
_readOnly = readOnly;
|
||||
_additionalViewData = additionalViewData;
|
||||
|
||||
_model = modelExplorer.Model;
|
||||
_metadata = modelExplorer.Metadata;
|
||||
}
|
||||
|
||||
public string Build()
|
||||
{
|
||||
if (_metadata.ConvertEmptyStringToNull && string.Empty.Equals(_metadata.Model))
|
||||
if (_metadata.ConvertEmptyStringToNull && string.Empty.Equals(_model))
|
||||
{
|
||||
_metadata.Model = null;
|
||||
_model = null;
|
||||
}
|
||||
|
||||
var formattedModelValue = _metadata.Model;
|
||||
if (_metadata.Model == null && _readOnly)
|
||||
var formattedModelValue = _model;
|
||||
if (_model == null && _readOnly)
|
||||
{
|
||||
formattedModelValue = _metadata.NullDisplayText;
|
||||
}
|
||||
|
||||
var formatString = _readOnly ? _metadata.DisplayFormatString : _metadata.EditFormatString;
|
||||
|
||||
if (_metadata.Model != null && !string.IsNullOrEmpty(formatString))
|
||||
if (_model != null && !string.IsNullOrEmpty(formatString))
|
||||
{
|
||||
formattedModelValue = string.Format(CultureInfo.CurrentCulture, formatString, _metadata.Model);
|
||||
formattedModelValue = string.Format(CultureInfo.CurrentCulture, formatString, _model);
|
||||
}
|
||||
|
||||
// Normally this shouldn't happen, unless someone writes their own custom Object templates which
|
||||
// don't check to make sure that the object hasn't already been displayed
|
||||
if (_viewData.TemplateInfo.Visited(_metadata))
|
||||
if (_viewData.TemplateInfo.Visited(_modelExplorer))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var viewData = new ViewDataDictionary(_viewData, model: null)
|
||||
{
|
||||
Model = _metadata.Model,
|
||||
ModelMetadata = _metadata
|
||||
};
|
||||
// We need to copy the ModelExplorer to copy the model metadata. Otherwise we might
|
||||
// lose track of the model type/property. Passing null here explicitly, because
|
||||
// this might be a typed VDD, and the model value might not be compatible.
|
||||
var viewData = new ViewDataDictionary(_viewData, model: null);
|
||||
|
||||
// We're setting ModelExplorer in order to preserve the model metadata of the original
|
||||
// _viewData even though _model may be null.
|
||||
viewData.ModelExplorer = _modelExplorer.GetExplorerForModel(_model);
|
||||
|
||||
viewData.TemplateInfo.FormattedModelValue = formattedModelValue;
|
||||
viewData.TemplateInfo.HtmlFieldPrefix = _viewData.TemplateInfo.GetFullHtmlFieldName(_htmlFieldName);
|
||||
|
|
@ -81,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
}
|
||||
|
||||
var visitedObjectsKey = _metadata.Model ?? _metadata.RealModelType;
|
||||
var visitedObjectsKey = _model ?? _modelExplorer.ModelType;
|
||||
viewData.TemplateInfo.AddVisited(visitedObjectsKey);
|
||||
|
||||
var templateRenderer = new TemplateRenderer(_viewEngine, _viewContext, viewData, _templateName, _readOnly);
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatTemplateHelpers_NoTemplate(_viewData.ModelMetadata.RealModelType.FullName));
|
||||
Resources.FormatTemplateHelpers_NoTemplate(_viewData.ModelExplorer.ModelType.FullName));
|
||||
}
|
||||
|
||||
private Dictionary<string, Func<IHtmlHelper, string>> GetDefaultActions()
|
||||
|
|
@ -139,7 +139,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
// We don't want to search for Nullable<T>, we want to search for T (which should handle both T and
|
||||
// Nullable<T>).
|
||||
var fieldType = Nullable.GetUnderlyingType(metadata.RealModelType) ?? metadata.RealModelType;
|
||||
var modelType = _viewData.ModelExplorer.ModelType;
|
||||
var fieldType = Nullable.GetUnderlyingType(modelType) ?? modelType;
|
||||
|
||||
yield return fieldType.Name;
|
||||
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <paramref name="metadata"/> is <c>null</c>; ignored otherwise.
|
||||
/// </param>
|
||||
/// <returns>An <see cref="IEnumerable{ModelClientValidationRule}"/> containing the relevant rules.</returns>
|
||||
IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, string expression);
|
||||
IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelExplorer modelExplorer, string expression);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an <input> element of type "hidden" for the specified <paramref name="expression"/>.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
|
|
@ -19,13 +17,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <param name="name">
|
||||
/// String representation of the <see cref="System.Linq.Expressions.Expression"/> of interest.
|
||||
/// </param>
|
||||
/// <param name="metadata">
|
||||
/// Metadata about the <see cref="System.Linq.Expressions.Expression"/> of interest.
|
||||
/// <param name="modelExplorer">
|
||||
/// Includes the model and metadata about the <see cref="System.Linq.Expressions.Expression"/> of interest.
|
||||
/// </param>
|
||||
public ModelExpression([NotNull] string name, [NotNull] ModelMetadata metadata)
|
||||
public ModelExpression([NotNull] string name, [NotNull] ModelExplorer modelExplorer)
|
||||
{
|
||||
Name = name;
|
||||
Metadata = metadata;
|
||||
ModelExplorer = modelExplorer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -36,10 +34,36 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
/// <summary>
|
||||
/// Metadata about the <see cref="System.Linq.Expressions.Expression"/> of interest.
|
||||
/// </summary>
|
||||
public ModelMetadata Metadata
|
||||
{
|
||||
get
|
||||
{
|
||||
return ModelExplorer.Metadata;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model object for the <see cref="System.Linq.Expressions.Expression"/> of interest.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Getting <see cref="ModelMetadata.Model"/> will evaluate a compiled version of the original
|
||||
/// Getting <see cref="Model"/> will evaluate a compiled version of the original
|
||||
/// <see cref="System.Linq.Expressions.Expression"/>.
|
||||
/// </remarks>
|
||||
public ModelMetadata Metadata { get; private set; }
|
||||
public object Model
|
||||
{
|
||||
get
|
||||
{
|
||||
return ModelExplorer.Model;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model explorer for the <see cref="System.Linq.Expressions.Expression"/> of interest.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Getting <see cref="ModelExplorer.Model"/> will evaluate a compiled version of the original
|
||||
/// <see cref="System.Linq.Expressions.Expression"/>.
|
||||
/// </remarks>
|
||||
public ModelExplorer ModelExplorer { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -88,9 +88,9 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
public bool Visited(ModelMetadata metadata)
|
||||
public bool Visited(ModelExplorer modelExplorer)
|
||||
{
|
||||
return _visitedObjects.Contains(metadata.Model ?? metadata.ModelType);
|
||||
return _visitedObjects.Contains(modelExplorer.Model ?? modelExplorer.Metadata.ModelType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
private readonly Type _declaredModelType;
|
||||
private readonly IModelMetadataProvider _metadataProvider;
|
||||
|
||||
private object _model;
|
||||
private ModelMetadata _modelMetadata;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ViewDataDictionary"/> class.
|
||||
/// </summary>
|
||||
|
|
@ -128,7 +125,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
templateInfo: new TemplateInfo())
|
||||
{
|
||||
// This is the core constructor called when Model is unknown. Base ModelMetadata on the declared type.
|
||||
ModelMetadata = _metadataProvider.GetMetadataForType(() => null, _declaredModelType);
|
||||
ModelExplorer = _metadataProvider.GetModelExplorerForType(declaredModelType, model: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -188,16 +185,16 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
// This is the core constructor called when Model is known.
|
||||
var modelType = GetModelType(model);
|
||||
if (modelType == source.ModelMetadata.ModelType && model == source.ModelMetadata.Model)
|
||||
if (modelType == source.ModelMetadata.ModelType && model == source.ModelExplorer.Model)
|
||||
{
|
||||
// Preserve any customizations made to source.ModelMetadata if the Type that will be calculated in
|
||||
// SetModel() and source.Model match new instance's values.
|
||||
ModelMetadata = source.ModelMetadata;
|
||||
// Preserve any customizations made to source.ModelExplorer.ModelMetadata if the Type
|
||||
// that will be calculated in SetModel() and source.Model match new instance's values.
|
||||
ModelExplorer = source.ModelExplorer;
|
||||
}
|
||||
else if (model == null)
|
||||
{
|
||||
// Ensure ModelMetadata is never null though SetModel() isn't called.
|
||||
ModelMetadata = _metadataProvider.GetMetadataForType(() => null, _declaredModelType);
|
||||
// Ensure ModelMetadata is never null though SetModel() isn't called below.
|
||||
ModelExplorer = _metadataProvider.GetModelExplorerForType(_declaredModelType, model: null);
|
||||
}
|
||||
|
||||
// If we're constructing a ViewDataDictionary<TModel> where TModel is a non-Nullable value type,
|
||||
|
|
@ -226,12 +223,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
get
|
||||
{
|
||||
return _model;
|
||||
return ModelExplorer.Model;
|
||||
}
|
||||
set
|
||||
{
|
||||
// Reset ModelMetadata to ensure Model and ModelMetadata.Model remain equal.
|
||||
_modelMetadata = null;
|
||||
// Reset ModelExplorer to ensure Model and ModelMetadata.Model remain equal.
|
||||
SetModel(value);
|
||||
}
|
||||
}
|
||||
|
|
@ -250,21 +246,15 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
get
|
||||
{
|
||||
return _modelMetadata;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(Resources.FormatPropertyOfTypeCannotBeNull(
|
||||
nameof(ViewDataDictionary.ModelMetadata),
|
||||
nameof(ViewDataDictionary)));
|
||||
}
|
||||
|
||||
_modelMetadata = value;
|
||||
return ModelExplorer.Metadata;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ModelExplorer"/> for the <see cref="Model"/>.
|
||||
/// </summary>
|
||||
public ModelExplorer ModelExplorer { get; set; }
|
||||
|
||||
public TemplateInfo TemplateInfo { get; }
|
||||
|
||||
#region IDictionary properties
|
||||
|
|
@ -355,15 +345,24 @@ namespace Microsoft.AspNet.Mvc
|
|||
protected virtual void SetModel(object value)
|
||||
{
|
||||
EnsureCompatible(value);
|
||||
_model = value;
|
||||
|
||||
// Reset or override ModelMetadata based on runtime value type. Fall back to declared type if value is
|
||||
// null. When called from the Model setter, ModelMetadata will (temporarily) be null. When called from
|
||||
// a constructor, current ModelMetadata may already be set to preserve customizations made in parent scope.
|
||||
var modelType = GetModelType(value);
|
||||
if (ModelMetadata == null || ModelMetadata.ModelType != modelType)
|
||||
if (ModelExplorer?.Metadata.ModelType != modelType)
|
||||
{
|
||||
ModelMetadata = _metadataProvider.GetMetadataForType(() => value, modelType);
|
||||
ModelExplorer = _metadataProvider.GetModelExplorerForType(modelType, value);
|
||||
}
|
||||
else if (object.ReferenceEquals(value, Model))
|
||||
{
|
||||
// The metadata already matches, and the model is literally the same, nothing
|
||||
// to do here. This will likely occur when using one of the copy constructors.
|
||||
}
|
||||
else
|
||||
{
|
||||
// The metadata matches, but it's a new value.
|
||||
ModelExplorer = new ModelExplorer(_metadataProvider, ModelExplorer.Container, ModelMetadata, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,14 +44,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
var boundCollection = new List<TElement>();
|
||||
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var elementMetadata = metadataProvider.GetMetadataForType(typeof(TElement));
|
||||
|
||||
var rawValueArray = RawValueToObjectArray(rawValue);
|
||||
foreach (var rawValueElement in rawValueArray)
|
||||
{
|
||||
var innerModelMetadata =
|
||||
bindingContext.OperationBindingContext.MetadataProvider.GetMetadataForType(null, typeof(TElement));
|
||||
var innerBindingContext = new ModelBindingContext(bindingContext,
|
||||
bindingContext.ModelName,
|
||||
innerModelMetadata)
|
||||
elementMetadata)
|
||||
{
|
||||
ValueProvider = new CompositeValueProvider
|
||||
{
|
||||
|
|
@ -97,13 +98,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
.Select(i => i.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var elementMetadata = metadataProvider.GetMetadataForType(typeof(TElement));
|
||||
|
||||
var boundCollection = new List<TElement>();
|
||||
foreach (var indexName in indexNames)
|
||||
{
|
||||
var fullChildName = ModelBindingHelper.CreateIndexModelName(bindingContext.ModelName, indexName);
|
||||
var childModelMetadata =
|
||||
bindingContext.OperationBindingContext.MetadataProvider.GetMetadataForType(null, typeof(TElement));
|
||||
var childBindingContext = new ModelBindingContext(bindingContext, fullChildName, childModelMetadata);
|
||||
var childBindingContext = new ModelBindingContext(bindingContext, fullChildName, elementMetadata);
|
||||
|
||||
var didBind = false;
|
||||
object boundValue = null;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
typeof(ComplexModelDto),
|
||||
allowNullModel: false);
|
||||
|
||||
var dto = (ComplexModelDto)bindingContext.ModelMetadata.Model;
|
||||
var dto = (ComplexModelDto)bindingContext.Model;
|
||||
foreach (var propertyMetadata in dto.PropertyMetadata)
|
||||
{
|
||||
var propertyModelName = ModelBindingHelper.CreatePropertyModelName(
|
||||
|
|
|
|||
|
|
@ -57,8 +57,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
if (modelBindingResult.IsModelSet)
|
||||
{
|
||||
bindingContext.ModelMetadata.Model = modelBindingResult.Model;
|
||||
|
||||
// Update the model state key if we are bound using an empty prefix and it is a complex type.
|
||||
// This is needed as validation uses the model state key to log errors. The client validation expects
|
||||
// the errors with property names rather than the full name.
|
||||
|
|
@ -112,6 +110,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
var newBindingContext = new ModelBindingContext
|
||||
{
|
||||
Model = oldBindingContext.Model,
|
||||
ModelMetadata = oldBindingContext.ModelMetadata,
|
||||
ModelName = modelName,
|
||||
ModelState = oldBindingContext.ModelState,
|
||||
|
|
|
|||
|
|
@ -18,36 +18,40 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
var keyResult = await TryBindStrongModel<TKey>(bindingContext, "Key");
|
||||
var valueResult = await TryBindStrongModel<TValue>(bindingContext, "Value");
|
||||
var model = bindingContext.ModelMetadata.Model;
|
||||
var isModelSet = false;
|
||||
|
||||
if (keyResult.IsModelSet && valueResult.IsModelSet)
|
||||
{
|
||||
model = new KeyValuePair<TKey, TValue>(
|
||||
var model = new KeyValuePair<TKey, TValue>(
|
||||
ModelBindingHelper.CastOrDefault<TKey>(keyResult.Model),
|
||||
ModelBindingHelper.CastOrDefault<TValue>(valueResult.Model));
|
||||
isModelSet = true;
|
||||
|
||||
return new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true);
|
||||
}
|
||||
else if (!keyResult.IsModelSet && valueResult.IsModelSet)
|
||||
{
|
||||
bindingContext.ModelState.TryAddModelError(keyResult.Key,
|
||||
bindingContext.ModelState.TryAddModelError(
|
||||
keyResult.Key,
|
||||
Resources.KeyValuePair_BothKeyAndValueMustBePresent);
|
||||
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
||||
}
|
||||
else if (keyResult.IsModelSet && !valueResult.IsModelSet)
|
||||
{
|
||||
bindingContext.ModelState.TryAddModelError(valueResult.Key,
|
||||
bindingContext.ModelState.TryAddModelError(
|
||||
valueResult.Key,
|
||||
Resources.KeyValuePair_BothKeyAndValueMustBePresent);
|
||||
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = new ModelBindingResult(model, bindingContext.ModelName, isModelSet);
|
||||
return (keyResult.IsModelSet || valueResult.IsModelSet) ? result : null;
|
||||
}
|
||||
|
||||
internal async Task<ModelBindingResult> TryBindStrongModel<TModel>(ModelBindingContext parentBindingContext,
|
||||
string propertyName)
|
||||
{
|
||||
var propertyModelMetadata =
|
||||
parentBindingContext.OperationBindingContext.MetadataProvider.GetMetadataForType(modelAccessor: null,
|
||||
modelType: typeof(TModel));
|
||||
parentBindingContext.OperationBindingContext.MetadataProvider.GetMetadataForType(typeof(TModel));
|
||||
var propertyModelName =
|
||||
ModelBindingHelper.CreatePropertyModelName(parentBindingContext.ModelName, propertyName);
|
||||
var propertyBindingContext =
|
||||
|
|
|
|||
|
|
@ -38,8 +38,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// post-processing, e.g. property setters and hooking up validation
|
||||
ProcessDto(bindingContext, (ComplexModelDto)result.Model);
|
||||
return
|
||||
new ModelBindingResult(bindingContext.ModelMetadata.Model, bindingContext.ModelName, isModelSet: true);
|
||||
return new ModelBindingResult(
|
||||
bindingContext.Model,
|
||||
bindingContext.ModelName,
|
||||
isModelSet: true);
|
||||
}
|
||||
|
||||
protected virtual bool CanUpdateProperty(ModelMetadata propertyMetadata)
|
||||
|
|
@ -236,18 +238,25 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return true;
|
||||
}
|
||||
|
||||
private async Task<ModelBindingResult> CreateAndPopulateDto(ModelBindingContext bindingContext,
|
||||
IEnumerable<ModelMetadata> propertyMetadatas)
|
||||
private async Task<ModelBindingResult> CreateAndPopulateDto(
|
||||
ModelBindingContext bindingContext,
|
||||
IEnumerable<ModelMetadata> propertyMetadatas)
|
||||
{
|
||||
// create a DTO and call into the DTO binder
|
||||
var originalDto = new ComplexModelDto(bindingContext.ModelMetadata, propertyMetadatas);
|
||||
var complexModelDtoMetadata =
|
||||
bindingContext.OperationBindingContext.MetadataProvider.GetMetadataForType(() => originalDto,
|
||||
typeof(ComplexModelDto));
|
||||
var dtoBindingContext =
|
||||
new ModelBindingContext(bindingContext, bindingContext.ModelName, complexModelDtoMetadata);
|
||||
var dto = new ComplexModelDto(bindingContext.ModelMetadata, propertyMetadatas);
|
||||
|
||||
return await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(dtoBindingContext);
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var dtoMetadata = metadataProvider.GetMetadataForType(typeof(ComplexModelDto));
|
||||
|
||||
var childContext = new ModelBindingContext(
|
||||
bindingContext,
|
||||
bindingContext.ModelName,
|
||||
dtoMetadata)
|
||||
{
|
||||
Model = dto,
|
||||
};
|
||||
|
||||
return await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(childContext);
|
||||
}
|
||||
|
||||
protected virtual object CreateModel(ModelBindingContext bindingContext)
|
||||
|
|
@ -259,9 +268,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
protected virtual void EnsureModel(ModelBindingContext bindingContext)
|
||||
{
|
||||
if (bindingContext.ModelMetadata.Model == null)
|
||||
if (bindingContext.Model == null)
|
||||
{
|
||||
bindingContext.ModelMetadata.Model = CreateModel(bindingContext);
|
||||
bindingContext.Model = CreateModel(bindingContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -349,6 +358,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
internal void ProcessDto(ModelBindingContext bindingContext, ComplexModelDto dto)
|
||||
{
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(bindingContext.ModelType, bindingContext.Model);
|
||||
|
||||
var validationInfo = GetPropertyValidationInfo(bindingContext);
|
||||
|
||||
// Eliminate provided properties from requiredProperties; leaving just *missing* required properties.
|
||||
|
|
@ -359,12 +371,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
var addedError = false;
|
||||
|
||||
// Update Model as SetProperty() would: Place null value where validator will check for non-null. This
|
||||
// ensures a failure result from a required validator (if any) even for a non-nullable property.
|
||||
// (Otherwise, propertyMetadata.Model is likely already null.)
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties[missingRequiredProperty];
|
||||
propertyMetadata.Model = null;
|
||||
var propertyName = propertyMetadata.BinderModelName ?? missingRequiredProperty;
|
||||
// We want to provide the 'null' value, not the value of model.Property,
|
||||
// so avoiding modelExplorer.GetProperty here which would call the actual getter on the
|
||||
// model. This avoids issues with value types, or properties with pre-initialized values.
|
||||
var propertyExplorer = modelExplorer.GetExplorerForProperty(missingRequiredProperty, model: null);
|
||||
|
||||
var propertyName = propertyExplorer.Metadata.BinderModelName ?? missingRequiredProperty;
|
||||
var modelStateKey = ModelBindingHelper.CreatePropertyModelName(
|
||||
bindingContext.ModelName,
|
||||
propertyName);
|
||||
|
|
@ -373,7 +385,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
IModelValidator validator;
|
||||
if (validationInfo.RequiredValidators.TryGetValue(missingRequiredProperty, out validator))
|
||||
{
|
||||
addedError = RunValidator(validator, bindingContext, propertyMetadata, modelStateKey);
|
||||
addedError = RunValidator(validator, bindingContext, propertyExplorer, modelStateKey);
|
||||
}
|
||||
|
||||
// Fall back to default message if BindingBehaviorAttribute required this property or validator
|
||||
|
|
@ -389,26 +401,31 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// for each property that was bound, call the setter, recording exceptions as necessary
|
||||
foreach (var entry in dto.Results)
|
||||
{
|
||||
var propertyMetadata = entry.Key;
|
||||
var dtoResult = entry.Value;
|
||||
if (dtoResult != null)
|
||||
{
|
||||
var propertyMetadata = entry.Key;
|
||||
IModelValidator requiredValidator;
|
||||
validationInfo.RequiredValidators.TryGetValue(propertyMetadata.PropertyName,
|
||||
out requiredValidator);
|
||||
SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
|
||||
validationInfo.RequiredValidators.TryGetValue(
|
||||
propertyMetadata.PropertyName,
|
||||
out requiredValidator);
|
||||
|
||||
SetProperty(bindingContext, modelExplorer, propertyMetadata, dtoResult, requiredValidator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void SetProperty(ModelBindingContext bindingContext,
|
||||
ModelMetadata propertyMetadata,
|
||||
ModelBindingResult dtoResult,
|
||||
IModelValidator requiredValidator)
|
||||
protected virtual void SetProperty(
|
||||
ModelBindingContext bindingContext,
|
||||
ModelExplorer modelExplorer,
|
||||
ModelMetadata propertyMetadata,
|
||||
ModelBindingResult dtoResult,
|
||||
IModelValidator requiredValidator)
|
||||
{
|
||||
var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase;
|
||||
var property = bindingContext.ModelType
|
||||
.GetProperty(propertyMetadata.PropertyName, bindingFlags);
|
||||
var property = bindingContext.ModelType.GetProperty(
|
||||
propertyMetadata.PropertyName,
|
||||
bindingFlags);
|
||||
|
||||
if (property == null || !property.CanWrite)
|
||||
{
|
||||
|
|
@ -427,8 +444,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
hasDefaultValue = TryGetPropertyDefaultValue(property, out value);
|
||||
}
|
||||
|
||||
propertyMetadata.Model = value;
|
||||
|
||||
// 'Required' validators need to run first so that we can provide useful error messages if
|
||||
// the property setters throw, e.g. if we're setting entity keys to null.
|
||||
if (value == null)
|
||||
|
|
@ -439,7 +454,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
if (requiredValidator != null)
|
||||
{
|
||||
var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);
|
||||
var propertyExplorer = modelExplorer.GetExplorerForExpression(propertyMetadata, model: null);
|
||||
var validationContext = new ModelValidationContext(bindingContext, propertyExplorer);
|
||||
foreach (var validationResult in requiredValidator.Validate(validationContext))
|
||||
{
|
||||
bindingContext.ModelState.TryAddModelError(modelStateKey, validationResult.Message);
|
||||
|
|
@ -459,7 +475,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
try
|
||||
{
|
||||
property.SetValue(bindingContext.ModelMetadata.Model, value);
|
||||
property.SetValue(bindingContext.Model, value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -492,12 +508,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
// Returns true if validator execution adds a model error.
|
||||
private static bool RunValidator(IModelValidator validator,
|
||||
ModelBindingContext bindingContext,
|
||||
ModelMetadata propertyMetadata,
|
||||
string modelStateKey)
|
||||
private static bool RunValidator(
|
||||
IModelValidator validator,
|
||||
ModelBindingContext bindingContext,
|
||||
ModelExplorer propertyExplorer,
|
||||
string modelStateKey)
|
||||
{
|
||||
var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);
|
||||
var validationContext = new ModelValidationContext(bindingContext, propertyExplorer);
|
||||
|
||||
var addedError = false;
|
||||
foreach (var validationResult in validator.Validate(validationContext))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public interface IObjectModelValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates the given model in <see cref="ModelValidationContext.ModelMetadata"/>.
|
||||
/// Validates the given model in <see cref="ModelValidationContext.ModelExplorer"/>.
|
||||
/// </summary>
|
||||
/// <param name="validationContext">The <see cref="ModelValidationContext"/> associated with the current call.
|
||||
/// </param>
|
||||
|
|
|
|||
|
|
@ -81,17 +81,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Internal
|
|||
throw new ArgumentException(message, "bindingContext");
|
||||
}
|
||||
|
||||
if (!allowNullModel && bindingContext.ModelMetadata.Model == null)
|
||||
if (!allowNullModel && bindingContext.Model == null)
|
||||
{
|
||||
var message = Resources.FormatModelBinderUtil_ModelCannotBeNull(requiredType);
|
||||
throw new ArgumentException(message, "bindingContext");
|
||||
}
|
||||
|
||||
if (bindingContext.ModelMetadata.Model != null &&
|
||||
if (bindingContext.Model != null &&
|
||||
!bindingContext.ModelType.GetTypeInfo().IsAssignableFrom(requiredType.GetTypeInfo()))
|
||||
{
|
||||
var message = Resources.FormatModelBinderUtil_ModelInstanceIsWrong(
|
||||
bindingContext.ModelMetadata.Model.GetType(),
|
||||
bindingContext.Model.GetType(),
|
||||
requiredType);
|
||||
throw new ArgumentException(message, "bindingContext");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,13 +19,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private readonly ConcurrentDictionary<Type, Dictionary<string, PropertyInformation>> _typePropertyInfoCache =
|
||||
new ConcurrentDictionary<Type, Dictionary<string, PropertyInformation>>();
|
||||
|
||||
public IEnumerable<ModelMetadata> GetMetadataForProperties(object container, [NotNull] Type containerType)
|
||||
public IEnumerable<ModelMetadata> GetMetadataForProperties([NotNull] Type containerType)
|
||||
{
|
||||
return GetMetadataForPropertiesCore(container, containerType);
|
||||
return GetMetadataForPropertiesCore(containerType);
|
||||
}
|
||||
|
||||
public ModelMetadata GetMetadataForProperty(Func<object> modelAccessor,
|
||||
[NotNull] Type containerType,
|
||||
public ModelMetadata GetMetadataForProperty([NotNull] Type containerType,
|
||||
[NotNull] string propertyName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(propertyName))
|
||||
|
|
@ -42,17 +41,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
throw new ArgumentException(message, nameof(propertyName));
|
||||
}
|
||||
|
||||
return CreatePropertyMetadata(modelAccessor, propertyInfo);
|
||||
return CreatePropertyMetadata(propertyInfo);
|
||||
}
|
||||
|
||||
public ModelMetadata GetMetadataForType(Func<object> modelAccessor, [NotNull] Type modelType)
|
||||
public ModelMetadata GetMetadataForType([NotNull] Type modelType)
|
||||
{
|
||||
var prototype = GetTypeInformation(modelType);
|
||||
return CreateMetadataFromPrototype(prototype, modelAccessor);
|
||||
return CreateMetadataFromPrototype(prototype);
|
||||
}
|
||||
|
||||
public ModelMetadata GetMetadataForParameter(
|
||||
Func<object> modelAccessor,
|
||||
[NotNull] MethodInfo methodInfo,
|
||||
[NotNull] string parameterName)
|
||||
{
|
||||
|
|
@ -69,7 +67,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
throw new ArgumentException(message, nameof(parameterName));
|
||||
}
|
||||
|
||||
return GetMetadataForParameterCore(modelAccessor, parameterName, parameter);
|
||||
return GetMetadataForParameterCore(parameterName, parameter);
|
||||
}
|
||||
|
||||
// Override for creating the prototype metadata (without the model accessor).
|
||||
|
|
@ -104,47 +102,36 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// <returns>
|
||||
/// A new <typeparamref name="TModelMetadata"/> instance based on <paramref name="prototype"/>.
|
||||
/// </returns>
|
||||
protected abstract TModelMetadata CreateMetadataFromPrototype(TModelMetadata prototype,
|
||||
Func<object> modelAccessor);
|
||||
protected abstract TModelMetadata CreateMetadataFromPrototype(TModelMetadata prototype);
|
||||
|
||||
private ModelMetadata GetMetadataForParameterCore(Func<object> modelAccessor,
|
||||
string parameterName,
|
||||
ParameterInfo parameter)
|
||||
private ModelMetadata GetMetadataForParameterCore(
|
||||
string parameterName,
|
||||
ParameterInfo parameter)
|
||||
{
|
||||
var parameterInfo =
|
||||
CreateParameterInfo(parameter.ParameterType,
|
||||
ModelAttributes.GetAttributesForParameter(parameter),
|
||||
parameterName);
|
||||
|
||||
var metadata = CreateMetadataFromPrototype(parameterInfo.Prototype, modelAccessor);
|
||||
var metadata = CreateMetadataFromPrototype(parameterInfo.Prototype);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private IEnumerable<ModelMetadata> GetMetadataForPropertiesCore(object container, Type containerType)
|
||||
private IEnumerable<ModelMetadata> GetMetadataForPropertiesCore(Type containerType)
|
||||
{
|
||||
var typePropertyInfo = GetTypePropertyInformation(containerType);
|
||||
|
||||
foreach (var kvp in typePropertyInfo)
|
||||
{
|
||||
var propertyInfo = kvp.Value;
|
||||
Func<object> modelAccessor = null;
|
||||
if (container != null)
|
||||
{
|
||||
modelAccessor = () => propertyInfo.PropertyHelper.GetValue(container);
|
||||
}
|
||||
var propertyMetadata = CreatePropertyMetadata(modelAccessor, propertyInfo);
|
||||
if (propertyMetadata != null)
|
||||
{
|
||||
propertyMetadata.Container = container;
|
||||
}
|
||||
|
||||
var propertyMetadata = CreatePropertyMetadata(propertyInfo);
|
||||
yield return propertyMetadata;
|
||||
}
|
||||
}
|
||||
|
||||
private TModelMetadata CreatePropertyMetadata(Func<object> modelAccessor, PropertyInformation propertyInfo)
|
||||
private TModelMetadata CreatePropertyMetadata(PropertyInformation propertyInfo)
|
||||
{
|
||||
var metadata = CreateMetadataFromPrototype(propertyInfo.Prototype, modelAccessor);
|
||||
var metadata = CreateMetadataFromPrototype(propertyInfo.Prototype);
|
||||
if (propertyInfo.IsReadOnly)
|
||||
{
|
||||
metadata.IsReadOnly = true;
|
||||
|
|
|
|||
|
|
@ -16,9 +16,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private static readonly string HtmlName = DataType.Html.ToString();
|
||||
private bool _isEditFormatStringFromCache;
|
||||
|
||||
public CachedDataAnnotationsModelMetadata(CachedDataAnnotationsModelMetadata prototype,
|
||||
Func<object> modelAccessor)
|
||||
: base(prototype, modelAccessor)
|
||||
public CachedDataAnnotationsModelMetadata(CachedDataAnnotationsModelMetadata prototype)
|
||||
: base(prototype)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -299,24 +298,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return result ?? base.ComputeOrder();
|
||||
}
|
||||
|
||||
protected override string ComputeSimpleDisplayText()
|
||||
/// <inheritdoc />
|
||||
protected override string ComputeSimpleDisplayProperty()
|
||||
{
|
||||
if (Model != null &&
|
||||
PrototypeCache.DisplayColumn != null &&
|
||||
!string.IsNullOrEmpty(PrototypeCache.DisplayColumn.DisplayColumn))
|
||||
if (!string.IsNullOrEmpty(PrototypeCache.DisplayColumn?.DisplayColumn))
|
||||
{
|
||||
var displayColumnProperty = ModelType.GetTypeInfo().GetDeclaredProperty(
|
||||
PrototypeCache.DisplayColumn.DisplayColumn);
|
||||
ValidateDisplayColumnAttribute(PrototypeCache.DisplayColumn, displayColumnProperty, ModelType);
|
||||
|
||||
var simpleDisplayTextValue = displayColumnProperty.GetValue(Model, null);
|
||||
if (simpleDisplayTextValue != null)
|
||||
{
|
||||
return simpleDisplayTextValue.ToString();
|
||||
}
|
||||
return displayColumnProperty.Name;
|
||||
}
|
||||
|
||||
return base.ComputeSimpleDisplayText();
|
||||
return base.ComputeSimpleDisplayProperty();
|
||||
}
|
||||
|
||||
protected override bool ComputeShowForDisplay()
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private int _order;
|
||||
private bool _showForDisplay;
|
||||
private bool _showForEdit;
|
||||
private string _simpleDisplayProperty;
|
||||
private string _templateHint;
|
||||
private IBinderMetadata _binderMetadata;
|
||||
private string _binderModelName;
|
||||
|
|
@ -56,6 +57,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private bool _orderComputed;
|
||||
private bool _showForDisplayComputed;
|
||||
private bool _showForEditComputed;
|
||||
private bool _simpleDisplayPropertyComputed;
|
||||
private bool _templateHintComputed;
|
||||
private bool _isBinderMetadataComputed;
|
||||
private bool _isBinderModelNameComputed;
|
||||
|
|
@ -63,10 +65,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private bool _propertyBindingPredicateProviderComputed;
|
||||
|
||||
// Constructor for creating real instances of the metadata class based on a prototype
|
||||
protected CachedModelMetadata(CachedModelMetadata<TPrototypeCache> prototype, Func<object> modelAccessor)
|
||||
protected CachedModelMetadata(CachedModelMetadata<TPrototypeCache> prototype)
|
||||
: base(prototype.Provider,
|
||||
prototype.ContainerType,
|
||||
modelAccessor,
|
||||
prototype.ModelType,
|
||||
prototype.PropertyName)
|
||||
{
|
||||
|
|
@ -82,7 +83,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Type modelType,
|
||||
string propertyName,
|
||||
TPrototypeCache prototypeCache)
|
||||
: base(provider, containerType, modelAccessor: null, modelType: modelType, propertyName: propertyName)
|
||||
: base(provider, containerType, modelType: modelType, propertyName: propertyName)
|
||||
{
|
||||
PrototypeCache = prototypeCache;
|
||||
}
|
||||
|
|
@ -500,17 +501,21 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed override string SimpleDisplayText
|
||||
public sealed override string SimpleDisplayProperty
|
||||
{
|
||||
get
|
||||
{
|
||||
// Value already cached in ModelMetadata. That class also already exposes ComputeSimpleDisplayText()
|
||||
// for overrides. Sealed here for consistency with other properties.
|
||||
return base.SimpleDisplayText;
|
||||
if (!_simpleDisplayPropertyComputed)
|
||||
{
|
||||
_simpleDisplayProperty = ComputeSimpleDisplayProperty();
|
||||
_simpleDisplayPropertyComputed = true;
|
||||
}
|
||||
return _simpleDisplayProperty;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.SimpleDisplayText = value;
|
||||
_simpleDisplayProperty = value;
|
||||
_simpleDisplayPropertyComputed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -701,6 +706,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return base.ShowForEdit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the <see cref="SimpleDisplayProperty"/> value.
|
||||
/// </summary>
|
||||
/// <returns>Calculated <see cref="SimpleDisplayProperty"/> value.</returns>
|
||||
protected virtual string ComputeSimpleDisplayProperty()
|
||||
{
|
||||
return base.SimpleDisplayProperty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the <see cref="TemplateHint"/> value.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -28,10 +28,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// Copies only a few values from the <paramref name="prototype"/>. Unlikely the rest have been computed.
|
||||
/// </remarks>
|
||||
protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(
|
||||
CachedDataAnnotationsModelMetadata prototype,
|
||||
Func<object> modelAccessor)
|
||||
CachedDataAnnotationsModelMetadata prototype)
|
||||
{
|
||||
var metadata = new CachedDataAnnotationsModelMetadata(prototype, modelAccessor);
|
||||
var metadata = new CachedDataAnnotationsModelMetadata(prototype);
|
||||
foreach (var keyValuePair in prototype.AdditionalValues)
|
||||
{
|
||||
metadata.AdditionalValues.Add(keyValuePair);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return new ModelMetadata(
|
||||
this,
|
||||
containerType,
|
||||
modelAccessor: null,
|
||||
modelType: modelType,
|
||||
propertyName: propertyName);
|
||||
}
|
||||
|
|
@ -36,13 +35,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// Copies very few values from the <paramref name="prototype"/>. Likely <paramref name="prototype"/> has not
|
||||
/// been modified except to add <see cref="ModelMetadata.AdditionalValues"/> entries.
|
||||
/// </remarks>
|
||||
protected override ModelMetadata CreateMetadataFromPrototype([NotNull] ModelMetadata prototype,
|
||||
Func<object> modelAccessor)
|
||||
protected override ModelMetadata CreateMetadataFromPrototype([NotNull] ModelMetadata prototype)
|
||||
{
|
||||
var metadata = new ModelMetadata(
|
||||
this,
|
||||
prototype.ContainerType,
|
||||
modelAccessor,
|
||||
prototype.ModelType,
|
||||
prototype.PropertyName);
|
||||
foreach (var keyValuePair in prototype.AdditionalValues)
|
||||
|
|
|
|||
|
|
@ -10,18 +10,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
public interface IModelMetadataProvider
|
||||
{
|
||||
IEnumerable<ModelMetadata> GetMetadataForProperties(object container, [NotNull] Type containerType);
|
||||
IEnumerable<ModelMetadata> GetMetadataForProperties([NotNull] Type containerType);
|
||||
|
||||
ModelMetadata GetMetadataForProperty(
|
||||
Func<object> modelAccessor,
|
||||
[NotNull] Type containerType,
|
||||
[NotNull] string propertyName);
|
||||
ModelMetadata GetMetadataForType([NotNull] Type modelType);
|
||||
|
||||
ModelMetadata GetMetadataForType(Func<object> modelAccessor, [NotNull] Type modelType);
|
||||
|
||||
ModelMetadata GetMetadataForParameter(
|
||||
Func<object> modelAccessor,
|
||||
[NotNull] MethodInfo methodInfo,
|
||||
[NotNull] string parameterName);
|
||||
ModelMetadata GetMetadataForParameter([NotNull] MethodInfo methodInfo, [NotNull] string parameterName);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,392 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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 System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Associates a model object with it's corresponding <see cref="ModelMetadata"/>.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("DeclaredType={Metadata.ModelType.Name} PropertyName={Metadata.PropertyName}")]
|
||||
public class ModelExplorer
|
||||
{
|
||||
private readonly IModelMetadataProvider _metadataProvider;
|
||||
|
||||
private object _model;
|
||||
private Func<object, object> _modelAccessor;
|
||||
private Type _modelType;
|
||||
private List<ModelExplorer> _properties;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ModelExplorer"/>.
|
||||
/// </summary>
|
||||
/// <param name="metadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
||||
/// <param name="metadata">The <see cref="ModelMetadata"/>.</param>
|
||||
/// <param name="model">The model object. May be <c>null</c>.</param>
|
||||
public ModelExplorer(
|
||||
[NotNull] IModelMetadataProvider metadataProvider,
|
||||
[NotNull] ModelMetadata metadata,
|
||||
object model)
|
||||
{
|
||||
_metadataProvider = metadataProvider;
|
||||
Metadata = metadata;
|
||||
_model = model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ModelExplorer"/>.
|
||||
/// </summary>
|
||||
/// <param name="metadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
||||
/// <param name="container">The container <see cref="ModelExplorer"/>.</param>
|
||||
/// <param name="metadata">The <see cref="ModelMetadata"/>.</param>
|
||||
/// <param name="modelAccessor">A model accessor function. May be <c>null</c>.</param>
|
||||
public ModelExplorer(
|
||||
[NotNull] IModelMetadataProvider metadataProvider,
|
||||
[NotNull] ModelExplorer container,
|
||||
[NotNull] ModelMetadata metadata,
|
||||
Func<object, object> modelAccessor)
|
||||
{
|
||||
_metadataProvider = metadataProvider;
|
||||
Container = container;
|
||||
Metadata = metadata;
|
||||
_modelAccessor = modelAccessor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ModelExplorer"/>.
|
||||
/// </summary>
|
||||
/// <param name="metadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
||||
/// <param name="container">The container <see cref="ModelExplorer"/>.</param>
|
||||
/// <param name="metadata">The <see cref="ModelMetadata"/>.</param>
|
||||
/// <param name="model">The model object. May be <c>null</c>.</param>
|
||||
public ModelExplorer(
|
||||
[NotNull] IModelMetadataProvider metadataProvider,
|
||||
[NotNull] ModelExplorer container,
|
||||
[NotNull] ModelMetadata metadata,
|
||||
object model)
|
||||
{
|
||||
_metadataProvider = metadataProvider;
|
||||
Container = container;
|
||||
Metadata = metadata;
|
||||
_model = model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the container <see cref="ModelExplorer"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The <see cref="Container"/> will most commonly be set as a result of calling
|
||||
/// <see cref="GetExplorerForProperty(string)"/>. In this case, the returned <see cref="ModelExplorer"/> will
|
||||
/// have it's <see cref="Container"/> set to the instance upon which <see cref="GetExplorerForProperty(string)"/>
|
||||
/// was called.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This however is not a requirement. The <see cref="Container"/> is informational, and may not
|
||||
/// represent a type that defines the property represented by <see cref="Metadata"/>. This can
|
||||
/// occur when constructing a <see cref="ModelExplorer"/> based on evaluation of a complex
|
||||
/// expression.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If calling code relies on a parent-child relationship between <see cref="ModelExplorer"/>
|
||||
/// instances, then use <see cref="ModelMetadata.ContainerType"/> to validate this assumption.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public ModelExplorer Container { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ModelMetadata"/>.
|
||||
/// </summary>
|
||||
public ModelMetadata Metadata { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Retrieving the <see cref="Model"/> object will execute the model accessor function if this
|
||||
/// <see cref="ModelExplorer"/> was provided with one.
|
||||
/// </remarks>
|
||||
public object Model
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_model == null && _modelAccessor != null)
|
||||
{
|
||||
Debug.Assert(Container != null);
|
||||
_model = _modelAccessor(Container.Model);
|
||||
|
||||
// Null-out the accessor so we don't invoke it repeatedly if it returns null.
|
||||
_modelAccessor = null;
|
||||
}
|
||||
|
||||
return _model;
|
||||
}
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Retrieving the <see cref="ModelType"/> will execute the model accessor function if this
|
||||
/// <see cref="ModelExplorer"/> was provided with one.
|
||||
/// </remarks>
|
||||
public Type ModelType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_modelType == null)
|
||||
{
|
||||
if (Model == null)
|
||||
{
|
||||
// If the model is null, then use the declared model type;
|
||||
_modelType = Metadata.ModelType;
|
||||
}
|
||||
else if (Metadata.IsNullableValueType)
|
||||
{
|
||||
// We have a model, but if it's a nullable value type, then Model.GetType() will return
|
||||
// the non-nullable type (int? -> int). Since it's a value type, there's no subclassing,
|
||||
// just go with the declared type.
|
||||
_modelType = Metadata.ModelType;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have a model, and it's not a nullable so use the runtime type to handle
|
||||
// cases where the model is a subclass of the declared type and has extra data.
|
||||
_modelType = Model.GetType();
|
||||
}
|
||||
}
|
||||
|
||||
return _modelType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the properties.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Includes a <see cref="ModelExplorer"/> for each property of the <see cref="ModelMetadata"/>
|
||||
/// for <see cref="ModelType"/>.
|
||||
/// </remarks>
|
||||
public IEnumerable<ModelExplorer> Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_properties == null)
|
||||
{
|
||||
_properties = new List<ModelExplorer>();
|
||||
|
||||
var metadata = GetMetadataForRuntimeType();
|
||||
|
||||
var properties = Enumerable.Join(
|
||||
metadata.Properties,
|
||||
PropertyHelper.GetProperties(ModelType),
|
||||
m => m.PropertyName,
|
||||
ph => ph.Property.Name,
|
||||
(m, ph) => CreateExplorerForProperty(m, ph));
|
||||
|
||||
_properties.AddRange(properties);
|
||||
}
|
||||
|
||||
return _properties;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ModelExplorer"/> for the given <paramref name="model"/> value.
|
||||
/// </summary>
|
||||
/// <param name="model">The model value.</param>
|
||||
/// <returns>A <see cref="ModelExplorer"/>.</returns>
|
||||
public ModelExplorer GetExplorerForModel(object model)
|
||||
{
|
||||
if (Container == null)
|
||||
{
|
||||
return new ModelExplorer(_metadataProvider, Metadata, model);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ModelExplorer(_metadataProvider, Container, Metadata, model);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ModelExplorer"/> for the property with given <paramref name="name"/>, or <c>null</c> if
|
||||
/// the property cannot be found.
|
||||
/// </summary>
|
||||
/// <param name="name">The property name.</param>
|
||||
/// <returns>A <see cref="ModelExplorer"/>, or <c>null</c>.</returns>
|
||||
public ModelExplorer GetExplorerForProperty([NotNull] string name)
|
||||
{
|
||||
return Properties.FirstOrDefault(p => string.Equals(
|
||||
p.Metadata.PropertyName,
|
||||
name,
|
||||
StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ModelExplorer"/> for the property with given <paramref name="name"/>, or <c>null</c> if
|
||||
/// the property cannot be found.
|
||||
/// </summary>
|
||||
/// <param name="name">The property name.</param>
|
||||
/// <param name="modelAccessor">An accessor for the model value.</param>
|
||||
/// <returns>A <see cref="ModelExplorer"/>, or <c>null</c>.</returns>
|
||||
/// <remarks>
|
||||
/// As this creates a model explorer with a specific model accessor function, the result is not cached.
|
||||
/// </remarks>
|
||||
public ModelExplorer GetExplorerForProperty([NotNull] string name, Func<object, object> modelAccessor)
|
||||
{
|
||||
var metadata = GetMetadataForRuntimeType();
|
||||
|
||||
var propertyMetadata = metadata.Properties[name];
|
||||
if (propertyMetadata == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ModelExplorer(_metadataProvider, this, propertyMetadata, modelAccessor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ModelExplorer"/> for the property with given <paramref name="name"/>, or <c>null</c> if
|
||||
/// the property cannot be found.
|
||||
/// </summary>
|
||||
/// <param name="name">The property name.</param>
|
||||
/// <param name="model">The model value.</param>
|
||||
/// <returns>A <see cref="ModelExplorer"/>, or <c>null</c>.</returns>
|
||||
/// <remarks>
|
||||
/// As this creates a model explorer with a specific model value, the result is not cached.
|
||||
/// </remarks>
|
||||
public ModelExplorer GetExplorerForProperty([NotNull] string name, object model)
|
||||
{
|
||||
var metadata = GetMetadataForRuntimeType();
|
||||
|
||||
var propertyMetadata = metadata.Properties[name];
|
||||
if (propertyMetadata == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ModelExplorer(_metadataProvider, this, propertyMetadata, model);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ModelExplorer"/> for the provided model value and model <see cref="Type"/>.
|
||||
/// </summary>
|
||||
/// <param name="modelType">The model <see cref="Type"/>.</param>
|
||||
/// <param name="model">The model value.</param>
|
||||
/// <returns>A <see cref="ModelExplorer"/>.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A <see cref="ModelExplorer"/> created by <see cref="GetExplorerForExpression(Type, object)"/>
|
||||
/// represents the result of executing an arbitrary expression against the model contained
|
||||
/// in the current <see cref="ModelExplorer"/> instance.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The returned <see cref="ModelExplorer"/> will have the current instance set as its <see cref="Container"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public ModelExplorer GetExplorerForExpression([NotNull] Type modelType, object model)
|
||||
{
|
||||
var metadata = _metadataProvider.GetMetadataForType(modelType);
|
||||
return GetExplorerForExpression(metadata, model);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ModelExplorer"/> for the provided model value and model <see cref="Type"/>.
|
||||
/// </summary>
|
||||
/// <param name="modelType">The model <see cref="Type"/>.</param>
|
||||
/// <param name="model">The model value.</param>
|
||||
/// <returns>A <see cref="ModelExplorer"/>.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A <see cref="ModelExplorer"/> created by
|
||||
/// <see cref="GetExplorerForExpression(ModelMetadata, object)"/>
|
||||
/// represents the result of executing an arbitrary expression against the model contained
|
||||
/// in the current <see cref="ModelExplorer"/> instance.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The returned <see cref="ModelExplorer"/> will have the current instance set as its <see cref="Container"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public ModelExplorer GetExplorerForExpression([NotNull] ModelMetadata metadata, object model)
|
||||
{
|
||||
return new ModelExplorer(_metadataProvider, this, metadata, model);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ModelExplorer"/> for the provided model value and model <see cref="Type"/>.
|
||||
/// </summary>
|
||||
/// <param name="modelType">The model <see cref="Type"/>.</param>
|
||||
/// <param name="model">The model value.</param>
|
||||
/// <returns>A <see cref="ModelExplorer"/>.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A <see cref="ModelExplorer"/> created by
|
||||
/// <see cref="GetExplorerForExpression(Type, Func{object, object})"/>
|
||||
/// represents the result of executing an arbitrary expression against the model contained
|
||||
/// in the current <see cref="ModelExplorer"/> instance.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The returned <see cref="ModelExplorer"/> will have the current instance set as its <see cref="Container"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public ModelExplorer GetExplorerForExpression([NotNull] Type modelType, Func<object, object> modelAccessor)
|
||||
{
|
||||
var metadata = _metadataProvider.GetMetadataForType(modelType);
|
||||
return GetExplorerForExpression(metadata, modelAccessor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ModelExplorer"/> for the provided model value and model <see cref="Type"/>.
|
||||
/// </summary>
|
||||
/// <param name="modelType">The model <see cref="Type"/>.</param>
|
||||
/// <param name="model">The model value.</param>
|
||||
/// <returns>A <see cref="ModelExplorer"/>.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// A <see cref="ModelExplorer"/> created by
|
||||
/// <see cref="GetExplorerForExpression(ModelMetadata, Func{object, object})"/>
|
||||
/// represents the result of executing an arbitrary expression against the model contained
|
||||
/// in the current <see cref="ModelExplorer"/> instance.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The returned <see cref="ModelExplorer"/> will have the current instance set as its <see cref="Container"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public ModelExplorer GetExplorerForExpression([NotNull] ModelMetadata metadata, Func<object, object> modelAccessor)
|
||||
{
|
||||
return new ModelExplorer(_metadataProvider, this, metadata, modelAccessor);
|
||||
}
|
||||
|
||||
private ModelMetadata GetMetadataForRuntimeType()
|
||||
{
|
||||
// We want to make sure we're looking at the runtime properties of the model, and for
|
||||
// that we need the model metadata of the runtime type.
|
||||
var metadata = Metadata;
|
||||
if (Metadata.ModelType != ModelType)
|
||||
{
|
||||
metadata = _metadataProvider.GetMetadataForType(ModelType);
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private ModelExplorer CreateExplorerForProperty(
|
||||
ModelMetadata propertyMetadata,
|
||||
PropertyHelper propertyHelper)
|
||||
{
|
||||
if (propertyHelper == null)
|
||||
{
|
||||
return new ModelExplorer(_metadataProvider, this, propertyMetadata, modelAccessor: null);
|
||||
}
|
||||
|
||||
var modelAccessor = new Func<object, object>((c) =>
|
||||
{
|
||||
return c == null ? null : propertyHelper.GetValue(c);
|
||||
});
|
||||
|
||||
return new ModelExplorer(_metadataProvider, this, propertyMetadata, modelAccessor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Linq;
|
||||
using System.Globalization;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="ModelExplorer"/>.
|
||||
/// </summary>
|
||||
public static class ModelExplorerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a simple display string for the <see cref="ModelExplorer.Model"/> property
|
||||
/// of <paramref name="modelExplorer"/>.
|
||||
/// </summary>
|
||||
/// <param name="modelExplorer">The <see cref="ModelExplorer"/>.</param>
|
||||
/// <returns>A simple display string for the model.</returns>
|
||||
public static string GetSimpleDisplayText([NotNull] this ModelExplorer modelExplorer)
|
||||
{
|
||||
if (modelExplorer.Metadata.SimpleDisplayProperty != null)
|
||||
{
|
||||
var propertyExplorer = modelExplorer.GetExplorerForProperty(
|
||||
modelExplorer.Metadata.SimpleDisplayProperty);
|
||||
if (propertyExplorer?.Model != null)
|
||||
{
|
||||
return propertyExplorer.Model.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
if (modelExplorer.Model == null)
|
||||
{
|
||||
return modelExplorer.Metadata.NullDisplayText;
|
||||
}
|
||||
|
||||
var stringResult = Convert.ToString(modelExplorer.Model, CultureInfo.CurrentCulture);
|
||||
if (stringResult == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (!stringResult.Equals(modelExplorer.Model.GetType().FullName, StringComparison.Ordinal))
|
||||
{
|
||||
return stringResult;
|
||||
}
|
||||
|
||||
var firstProperty = modelExplorer.Properties.FirstOrDefault();
|
||||
if (firstProperty == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (firstProperty.Model == null)
|
||||
{
|
||||
return firstProperty.Metadata.NullDisplayText;
|
||||
}
|
||||
|
||||
return Convert.ToString(firstProperty.Model, CultureInfo.CurrentCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
|
@ -25,24 +24,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private bool _showForDisplay = true;
|
||||
private bool _showForEdit = true;
|
||||
|
||||
private object _model;
|
||||
private Func<object> _modelAccessor;
|
||||
private int _order = DefaultOrder;
|
||||
private bool _isRequired;
|
||||
private ModelPropertyCollection _properties;
|
||||
private Type _realModelType;
|
||||
private string _simpleDisplayText;
|
||||
|
||||
public ModelMetadata([NotNull] IModelMetadataProvider provider,
|
||||
Type containerType,
|
||||
Func<object> modelAccessor,
|
||||
[NotNull] Type modelType,
|
||||
string propertyName)
|
||||
{
|
||||
Provider = provider;
|
||||
|
||||
_containerType = containerType;
|
||||
_modelAccessor = modelAccessor;
|
||||
_modelType = modelType;
|
||||
_propertyName = propertyName;
|
||||
_isRequired = !modelType.AllowsNullValue();
|
||||
|
|
@ -70,12 +63,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// </summary>
|
||||
public virtual IBinderMetadata BinderMetadata { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the model's container <see cref="object"/>.
|
||||
/// Will be non-<c>null</c> if the model represents a property.
|
||||
/// </summary>
|
||||
public object Container { get; set; }
|
||||
|
||||
public Type ContainerType
|
||||
{
|
||||
get { return _containerType; }
|
||||
|
|
@ -88,7 +75,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the <see cref="Model"/>'s datatype. Overrides <see cref="ModelType"/> in some
|
||||
/// Gets or sets the name of the Model's datatype. Overrides <see cref="ModelType"/> in some
|
||||
/// display scenarios.
|
||||
/// </summary>
|
||||
/// <value><c>null</c> unless set manually or through additional metadata e.g. attributes.</value>
|
||||
|
|
@ -98,7 +85,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
/// <summary>
|
||||
/// Gets or sets the composite format <see cref="string"/> (see
|
||||
/// http://msdn.microsoft.com/en-us/library/txafckwd.aspx) used to display the <see cref="Model"/>.
|
||||
/// http://msdn.microsoft.com/en-us/library/txafckwd.aspx) used to display the Model.
|
||||
/// </summary>
|
||||
public virtual string DisplayFormatString { get; set; }
|
||||
|
||||
|
|
@ -106,7 +93,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
/// <summary>
|
||||
/// Gets or sets the composite format <see cref="string"/> (see
|
||||
/// http://msdn.microsoft.com/en-us/library/txafckwd.aspx) used to edit the <see cref="Model"/>.
|
||||
/// http://msdn.microsoft.com/en-us/library/txafckwd.aspx) used to edit the Model.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <see cref="IModelMetadataProvider"/> instances that set this property to a non-<c>null</c>, non-empty,
|
||||
|
|
@ -195,26 +182,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
set { _order = value; }
|
||||
}
|
||||
|
||||
public object Model
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_modelAccessor != null)
|
||||
{
|
||||
_model = _modelAccessor();
|
||||
_modelAccessor = null;
|
||||
}
|
||||
return _model;
|
||||
}
|
||||
set
|
||||
{
|
||||
_model = value;
|
||||
_modelAccessor = null;
|
||||
_properties = null;
|
||||
_realModelType = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Type ModelType
|
||||
{
|
||||
get { return _modelType; }
|
||||
|
|
@ -231,7 +198,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
if (_properties == null)
|
||||
{
|
||||
var properties = Provider.GetMetadataForProperties(Model, RealModelType);
|
||||
var properties = Provider.GetMetadataForProperties(ModelType);
|
||||
_properties = new ModelPropertyCollection(properties.OrderBy(m => m.Order));
|
||||
}
|
||||
|
||||
|
|
@ -250,46 +217,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
get { return _propertyName; }
|
||||
}
|
||||
|
||||
protected IModelMetadataProvider Provider { get; set; }
|
||||
protected IModelMetadataProvider Provider { get; }
|
||||
|
||||
/// <returns>
|
||||
/// Gets runtime <see cref="Type"/> of <see cref="Model"/> if <see cref="Model"/> is non-<c>null</c> and
|
||||
/// <see cref="ModelType"/> is not <see cref="Nullable{T}"/>; <see cref="ModelType"/> otherwise.
|
||||
/// </returns>
|
||||
public Type RealModelType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_realModelType == null)
|
||||
{
|
||||
_realModelType = ModelType;
|
||||
|
||||
// Don't call GetType() if the model is Nullable<T>, because it will
|
||||
// turn Nullable<T> into T for non-null values
|
||||
if (Model != null && !ModelType.IsNullableValueType())
|
||||
{
|
||||
_realModelType = Model.GetType();
|
||||
}
|
||||
}
|
||||
|
||||
return _realModelType;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string SimpleDisplayText
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_simpleDisplayText == null)
|
||||
{
|
||||
_simpleDisplayText = ComputeSimpleDisplayText();
|
||||
}
|
||||
|
||||
return _simpleDisplayText;
|
||||
}
|
||||
|
||||
set { _simpleDisplayText = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets a value which is the name of the property used to display the model.
|
||||
/// </summary>
|
||||
public virtual string SimpleDisplayProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that indicates whether the property should be displayed in read-only views.
|
||||
|
|
@ -338,38 +271,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return DisplayName ?? PropertyName ?? ModelType.Name;
|
||||
}
|
||||
|
||||
protected virtual string ComputeSimpleDisplayText()
|
||||
{
|
||||
if (Model == null)
|
||||
{
|
||||
return NullDisplayText;
|
||||
}
|
||||
|
||||
var stringResult = Convert.ToString(Model, CultureInfo.CurrentCulture);
|
||||
if (stringResult == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (!stringResult.Equals(Model.GetType().FullName, StringComparison.Ordinal))
|
||||
{
|
||||
return stringResult;
|
||||
}
|
||||
|
||||
var firstProperty = Properties.FirstOrDefault();
|
||||
if (firstProperty == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (firstProperty.Model == null)
|
||||
{
|
||||
return firstProperty.NullDisplayText;
|
||||
}
|
||||
|
||||
return Convert.ToString(firstProperty.Model, CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
|
||||
private static EfficientTypePropertyKey<Type, string> CreateCacheKey(Type containerType,
|
||||
Type modelType,
|
||||
string propertyName)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions methods for <see cref="IModelMetadataProvider"/>.
|
||||
/// </summary>
|
||||
public static class ModelMetadataProviderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ModelExplorer"/> for the provided <paramref name="modelType"/> and
|
||||
/// <paramref name="model"/>.
|
||||
/// </summary>
|
||||
/// <param name="provider">The <see cref="IModelMetadataProvider"/>.</param>
|
||||
/// <param name="modelType">The declared <see cref="Type"/> of the model object.</param>
|
||||
/// <param name="model">The model object.</param>
|
||||
/// <returns></returns>
|
||||
public static ModelExplorer GetModelExplorerForType(
|
||||
[NotNull] this IModelMetadataProvider provider,
|
||||
[NotNull] Type modelType,
|
||||
object model)
|
||||
{
|
||||
var modelMetadata = provider.GetMetadataForType(modelType);
|
||||
return new ModelExplorer(provider, modelMetadata, model);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ModelMetadata"/> for property identified by the provided
|
||||
/// <paramref name="containerType"/> and <paramref name="propertyName"/>.
|
||||
/// </summary>
|
||||
/// <param name="provider">The <see cref="ModelMetadata"/>.</param>
|
||||
/// <param name="containerType">The <see cref="Type"/> for which the property is defined.</param>
|
||||
/// <param name="propertyName">The property name.</param>
|
||||
/// <returns>A <see cref="ModelMetadata"/> for the property.</returns>
|
||||
public static ModelMetadata GetMetadataForProperty(
|
||||
[NotNull] this IModelMetadataProvider provider,
|
||||
[NotNull] Type containerType,
|
||||
[NotNull] string propertyName)
|
||||
{
|
||||
var containerMetadata = provider.GetMetadataForType(containerType);
|
||||
|
||||
var propertyMetadata = containerMetadata.Properties[propertyName];
|
||||
if (propertyMetadata == null)
|
||||
{
|
||||
var message = Resources.FormatCommon_PropertyNotFound(containerType, propertyName);
|
||||
throw new ArgumentException(message, nameof(propertyName));
|
||||
}
|
||||
|
||||
return propertyMetadata;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,6 +55,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// </summary>
|
||||
public OperationBindingContext OperationBindingContext { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the model value for the current operation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <see cref="Model"/> will typically be set for a binding operation that works
|
||||
/// against a pre-existing model object to update certain properties.
|
||||
/// </remarks>
|
||||
public object Model { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the metadata for the model associated with this context.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -66,10 +66,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var otherPropertyDisplayName = OtherPropertyDisplayName;
|
||||
if (otherPropertyDisplayName == null && metadata.ContainerType != null)
|
||||
{
|
||||
var otherProperty = context.MetadataProvider
|
||||
.GetMetadataForProperty(() => metadata.Model,
|
||||
metadata.ContainerType,
|
||||
OtherProperty);
|
||||
var otherProperty = context.MetadataProvider.GetMetadataForProperty(
|
||||
metadata.ContainerType,
|
||||
OtherProperty);
|
||||
if (otherProperty != null)
|
||||
{
|
||||
return otherProperty.GetDisplayName();
|
||||
|
|
|
|||
|
|
@ -25,17 +25,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext validationContext)
|
||||
{
|
||||
var metadata = validationContext.ModelMetadata;
|
||||
var modelExplorer = validationContext.ModelExplorer;
|
||||
var metadata = modelExplorer.Metadata;
|
||||
|
||||
var memberName = metadata.PropertyName ?? metadata.ModelType.Name;
|
||||
var containerMetadata = validationContext.ContainerMetadata;
|
||||
var container = containerMetadata != null ? containerMetadata.Model : null;
|
||||
var context = new ValidationContext(container ?? metadata.Model)
|
||||
var containerExplorer = modelExplorer.Container;
|
||||
|
||||
var container = containerExplorer?.Model;
|
||||
var context = new ValidationContext(container ?? modelExplorer.Model)
|
||||
{
|
||||
DisplayName = metadata.GetDisplayName(),
|
||||
MemberName = memberName
|
||||
};
|
||||
|
||||
var result = Attribute.GetValidationResult(metadata.Model, context);
|
||||
var result = Attribute.GetValidationResult(modelExplorer.Model, context);
|
||||
if (result != ValidationResult.Success)
|
||||
{
|
||||
// ModelValidationResult.MemberName is used by invoking validators (such as ModelValidator) to
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// <inheritdoc />
|
||||
public void Validate([NotNull] ModelValidationContext modelValidationContext)
|
||||
{
|
||||
var metadata = modelValidationContext.ModelMetadata;
|
||||
var modelExplorer = modelValidationContext.ModelExplorer;
|
||||
var validationContext = new ValidationContext()
|
||||
{
|
||||
ModelValidationContext = modelValidationContext,
|
||||
|
|
@ -39,17 +39,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
};
|
||||
|
||||
ValidateNonVisitedNodeAndChildren(
|
||||
modelValidationContext.RootPrefix, metadata, validationContext, validators: null);
|
||||
modelValidationContext.RootPrefix,
|
||||
modelExplorer,
|
||||
validationContext,
|
||||
validators: null);
|
||||
}
|
||||
|
||||
private bool ValidateNonVisitedNodeAndChildren(string modelKey,
|
||||
ModelMetadata metadata, ValidationContext validationContext, IEnumerable<IModelValidator> validators)
|
||||
private bool ValidateNonVisitedNodeAndChildren(
|
||||
string modelKey,
|
||||
ModelExplorer modelExplorer,
|
||||
ValidationContext validationContext,
|
||||
IEnumerable<IModelValidator> validators)
|
||||
{
|
||||
// Recursion guard to avoid stack overflows
|
||||
RuntimeHelpers.EnsureSufficientExecutionStack();
|
||||
|
||||
var modelState = validationContext.ModelValidationContext.ModelState;
|
||||
var bindingSourceMetadata = metadata.BinderMetadata as IBindingSourceMetadata;
|
||||
var bindingSourceMetadata = modelExplorer.Metadata.BinderMetadata as IBindingSourceMetadata;
|
||||
var bindingSource = bindingSourceMetadata?.BindingSource;
|
||||
|
||||
if (bindingSource != null && !bindingSource.IsFromRequest)
|
||||
|
|
@ -78,37 +84,38 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// The validators are not null in the case of validating an array. Since the validators are
|
||||
// the same for all the elements of the array, we do not do GetValidators for each element,
|
||||
// instead we just pass them over. See ValidateElements function.
|
||||
validators = validationContext.ModelValidationContext.ValidatorProvider.GetValidators(metadata);
|
||||
var validatorProvider = validationContext.ModelValidationContext.ValidatorProvider;
|
||||
validators = validatorProvider.GetValidators(modelExplorer.Metadata);
|
||||
}
|
||||
|
||||
// We don't need to recursively traverse the graph for null values
|
||||
if (metadata.Model == null)
|
||||
if (modelExplorer.Model == null)
|
||||
{
|
||||
return ShallowValidate(modelKey, metadata, validationContext, validators);
|
||||
return ShallowValidate(modelKey, modelExplorer, validationContext, validators);
|
||||
}
|
||||
|
||||
// We don't need to recursively traverse the graph for types that shouldn't be validated
|
||||
var modelType = metadata.Model.GetType();
|
||||
var modelType = modelExplorer.Model.GetType();
|
||||
if (IsTypeExcludedFromValidation(_excludeFilterProvider.ExcludeFilters, modelType))
|
||||
{
|
||||
var result = ShallowValidate(modelKey, metadata, validationContext, validators);
|
||||
MarkPropertiesAsSkipped(modelKey, metadata, validationContext);
|
||||
var result = ShallowValidate(modelKey, modelExplorer, validationContext, validators);
|
||||
MarkPropertiesAsSkipped(modelKey, modelExplorer.Metadata, validationContext);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check to avoid infinite recursion. This can happen with cycles in an object graph.
|
||||
if (validationContext.Visited.Contains(metadata.Model))
|
||||
if (validationContext.Visited.Contains(modelExplorer.Model))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
validationContext.Visited.Add(metadata.Model);
|
||||
validationContext.Visited.Add(modelExplorer.Model);
|
||||
|
||||
// Validate the children first - depth-first traversal
|
||||
var enumerableModel = metadata.Model as IEnumerable;
|
||||
var enumerableModel = modelExplorer.Model as IEnumerable;
|
||||
if (enumerableModel == null)
|
||||
{
|
||||
isValid = ValidateProperties(modelKey, metadata, validationContext);
|
||||
isValid = ValidateProperties(modelKey, modelExplorer, validationContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -118,11 +125,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
if (isValid)
|
||||
{
|
||||
// Don't bother to validate this node if children failed.
|
||||
isValid = ShallowValidate(modelKey, metadata, validationContext, validators);
|
||||
isValid = ShallowValidate(modelKey, modelExplorer, validationContext, validators);
|
||||
}
|
||||
|
||||
// Pop the object so that it can be validated again in a different path
|
||||
validationContext.Visited.Remove(metadata.Model);
|
||||
validationContext.Visited.Remove(modelExplorer.Model);
|
||||
return isValid;
|
||||
}
|
||||
|
||||
|
|
@ -151,15 +158,22 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
}
|
||||
|
||||
private bool ValidateProperties(string currentModelKey, ModelMetadata metadata, ValidationContext validationContext)
|
||||
private bool ValidateProperties(string currentModelKey, ModelExplorer modelExplorer, ValidationContext validationContext)
|
||||
{
|
||||
var isValid = true;
|
||||
|
||||
foreach (var childMetadata in metadata.Properties)
|
||||
foreach (var property in modelExplorer.Metadata.Properties)
|
||||
{
|
||||
var propertyName = childMetadata.BinderModelName ?? childMetadata.PropertyName;
|
||||
var childKey = ModelBindingHelper.CreatePropertyModelName(currentModelKey, propertyName);
|
||||
if (!ValidateNonVisitedNodeAndChildren(childKey, childMetadata, validationContext, validators: null))
|
||||
var propertyExplorer = modelExplorer.GetExplorerForProperty(property.PropertyName);
|
||||
var propertyMetadata = propertyExplorer.Metadata;
|
||||
|
||||
var propertyBindingName = propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName;
|
||||
var childKey = ModelBindingHelper.CreatePropertyModelName(currentModelKey, propertyBindingName);
|
||||
if (!ValidateNonVisitedNodeAndChildren(
|
||||
childKey,
|
||||
propertyExplorer,
|
||||
validationContext,
|
||||
validators: null))
|
||||
{
|
||||
isValid = false;
|
||||
}
|
||||
|
|
@ -171,9 +185,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private bool ValidateElements(string currentKey, IEnumerable model, ValidationContext validationContext)
|
||||
{
|
||||
var elementType = GetElementType(model.GetType());
|
||||
var elementMetadata = _modelMetadataProvider.GetMetadataForType(
|
||||
modelAccessor: null,
|
||||
modelType: elementType);
|
||||
var elementMetadata = _modelMetadataProvider.GetMetadataForType(elementType);
|
||||
|
||||
var validators = validationContext.ModelValidationContext.ValidatorProvider.GetValidators(elementMetadata);
|
||||
|
||||
|
|
@ -189,9 +201,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// If it's null, then a shallow validation will be performed.
|
||||
if (element != null || anyValidatorsDefined)
|
||||
{
|
||||
elementMetadata.Model = element;
|
||||
var elementExplorer = new ModelExplorer(_modelMetadataProvider, elementMetadata, element);
|
||||
var elementKey = ModelBindingHelper.CreateIndexModelName(currentKey, index);
|
||||
if (!ValidateNonVisitedNodeAndChildren(elementKey, elementMetadata, validationContext, validators))
|
||||
if (!ValidateNonVisitedNodeAndChildren(elementKey, elementExplorer, validationContext, validators))
|
||||
{
|
||||
isValid = false;
|
||||
}
|
||||
|
|
@ -207,7 +219,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Returns true if validation passes successfully
|
||||
private static bool ShallowValidate(
|
||||
string modelKey,
|
||||
ModelMetadata metadata,
|
||||
ModelExplorer modelExplorer,
|
||||
ValidationContext validationContext,
|
||||
IEnumerable<IModelValidator> validators)
|
||||
{
|
||||
|
|
@ -219,7 +231,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
if (validatorsAsCollection == null || validatorsAsCollection.Count > 0)
|
||||
{
|
||||
var modelValidationContext =
|
||||
new ModelValidationContext(validationContext.ModelValidationContext, metadata);
|
||||
new ModelValidationContext(validationContext.ModelValidationContext, modelExplorer);
|
||||
var modelState = validationContext.ModelValidationContext.ModelState;
|
||||
var modelValidationState = modelState.GetValidationState(modelKey);
|
||||
var fieldValidationState = modelState.GetFieldValidationState(modelKey);
|
||||
|
|
@ -298,4 +310,4 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public HashSet<object> Visited { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,42 +8,40 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
public class ModelValidationContext
|
||||
{
|
||||
public ModelValidationContext([NotNull] ModelBindingContext bindingContext,
|
||||
[NotNull] ModelMetadata metadata)
|
||||
public ModelValidationContext(
|
||||
[NotNull] ModelBindingContext bindingContext,
|
||||
[NotNull] ModelExplorer modelExplorer)
|
||||
: this(bindingContext.ModelName,
|
||||
bindingContext.OperationBindingContext.ValidatorProvider,
|
||||
bindingContext.ModelState,
|
||||
metadata,
|
||||
bindingContext.ModelMetadata)
|
||||
modelExplorer)
|
||||
{
|
||||
}
|
||||
|
||||
public ModelValidationContext(string rootPrefix,
|
||||
[NotNull] IModelValidatorProvider validatorProvider,
|
||||
[NotNull] ModelStateDictionary modelState,
|
||||
[NotNull] ModelMetadata metadata,
|
||||
ModelMetadata containerMetadata)
|
||||
public ModelValidationContext(
|
||||
string rootPrefix,
|
||||
[NotNull] IModelValidatorProvider validatorProvider,
|
||||
[NotNull] ModelStateDictionary modelState,
|
||||
[NotNull] ModelExplorer modelExplorer)
|
||||
{
|
||||
ModelMetadata = metadata;
|
||||
ModelState = modelState;
|
||||
RootPrefix = rootPrefix;
|
||||
ValidatorProvider = validatorProvider;
|
||||
ContainerMetadata = containerMetadata;
|
||||
ModelExplorer = modelExplorer;
|
||||
}
|
||||
|
||||
public ModelValidationContext([NotNull] ModelValidationContext parentContext,
|
||||
[NotNull] ModelMetadata metadata)
|
||||
public ModelValidationContext(
|
||||
[NotNull] ModelValidationContext parentContext,
|
||||
[NotNull] ModelExplorer modelExplorer)
|
||||
{
|
||||
ModelMetadata = metadata;
|
||||
ContainerMetadata = parentContext.ModelMetadata;
|
||||
ModelExplorer = modelExplorer;
|
||||
ModelState = parentContext.ModelState;
|
||||
RootPrefix = parentContext.RootPrefix;
|
||||
ValidatorProvider = parentContext.ValidatorProvider;
|
||||
}
|
||||
|
||||
public ModelMetadata ModelMetadata { get; }
|
||||
|
||||
public ModelMetadata ContainerMetadata { get; }
|
||||
public ModelExplorer ModelExplorer { get; }
|
||||
|
||||
public ModelStateDictionary ModelState { get; }
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
|
||||
{
|
||||
var model = context.ModelMetadata.Model;
|
||||
var model = context.ModelExplorer.Model;
|
||||
if (model == null)
|
||||
{
|
||||
return Enumerable.Empty<ModelValidationResult>();
|
||||
|
|
|
|||
|
|
@ -48,14 +48,14 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
|
||||
var name = ExpressionHelper.GetExpressionText(expression);
|
||||
var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression, ViewData, _provider);
|
||||
if (metadata == null)
|
||||
var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression(expression, ViewData, _provider);
|
||||
if (modelExplorer == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatRazorPage_NullModelMetadata(nameof(IModelMetadataProvider), name));
|
||||
}
|
||||
|
||||
return new ModelExpression(name, metadata);
|
||||
return new ModelExpression(name, modelExplorer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Note null or empty For.Name is allowed because TemplateInfo.HtmlFieldPrefix may be sufficient.
|
||||
// IHtmlGenerator will enforce name requirements.
|
||||
var metadata = For.Metadata;
|
||||
var modelExplorer = For.ModelExplorer;
|
||||
if (metadata == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatTagHelpers_NoProvidedMetadata(
|
||||
|
|
@ -151,7 +152,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
if (string.IsNullOrEmpty(InputTypeName))
|
||||
{
|
||||
// Note GetInputType never returns null.
|
||||
inputType = GetInputType(metadata, out inputTypeHint);
|
||||
inputType = GetInputType(modelExplorer, out inputTypeHint);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -169,15 +170,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
switch (inputType)
|
||||
{
|
||||
case "checkbox":
|
||||
GenerateCheckBox(metadata, output);
|
||||
GenerateCheckBox(modelExplorer, output);
|
||||
return;
|
||||
|
||||
case "hidden":
|
||||
tagBuilder = Generator.GenerateHidden(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
For.Name,
|
||||
value: metadata.Model,
|
||||
value: For.Model,
|
||||
useViewData: false,
|
||||
htmlAttributes: null);
|
||||
break;
|
||||
|
|
@ -185,18 +186,18 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
case "password":
|
||||
tagBuilder = Generator.GeneratePassword(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
For.Name,
|
||||
value: null,
|
||||
htmlAttributes: null);
|
||||
break;
|
||||
|
||||
case "radio":
|
||||
tagBuilder = GenerateRadio(metadata);
|
||||
tagBuilder = GenerateRadio(modelExplorer);
|
||||
break;
|
||||
|
||||
default:
|
||||
tagBuilder = GenerateTextBox(metadata, inputTypeHint, inputType);
|
||||
tagBuilder = GenerateTextBox(modelExplorer, inputTypeHint, inputType);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -210,14 +211,14 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
}
|
||||
}
|
||||
|
||||
private void GenerateCheckBox(ModelMetadata metadata, TagHelperOutput output)
|
||||
private void GenerateCheckBox(ModelExplorer modelExplorer, TagHelperOutput output)
|
||||
{
|
||||
if (typeof(bool) != metadata.RealModelType)
|
||||
if (typeof(bool) != modelExplorer.ModelType)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatInputTagHelper_InvalidExpressionResult(
|
||||
"<input>",
|
||||
ForAttributeName,
|
||||
metadata.RealModelType.FullName,
|
||||
modelExplorer.ModelType.FullName,
|
||||
typeof(bool).FullName,
|
||||
"type",
|
||||
"checkbox"));
|
||||
|
|
@ -230,7 +231,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
var tagBuilder = Generator.GenerateCheckBox(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
For.Name,
|
||||
isChecked: null,
|
||||
htmlAttributes: htmlAttributes);
|
||||
|
|
@ -243,7 +244,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
output.Content += tagBuilder.ToString(TagRenderMode.SelfClosing);
|
||||
|
||||
tagBuilder = Generator.GenerateHiddenForCheckbox(ViewContext, metadata, For.Name);
|
||||
tagBuilder = Generator.GenerateHiddenForCheckbox(ViewContext, modelExplorer, For.Name);
|
||||
if (tagBuilder != null)
|
||||
{
|
||||
output.Content += tagBuilder.ToString(TagRenderMode.SelfClosing);
|
||||
|
|
@ -251,7 +252,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
}
|
||||
}
|
||||
|
||||
private TagBuilder GenerateRadio(ModelMetadata metadata)
|
||||
private TagBuilder GenerateRadio(ModelExplorer modelExplorer)
|
||||
{
|
||||
// Note empty string is allowed.
|
||||
if (Value == null)
|
||||
|
|
@ -265,38 +266,38 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
return Generator.GenerateRadioButton(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
For.Name,
|
||||
Value,
|
||||
isChecked: null,
|
||||
htmlAttributes: null);
|
||||
}
|
||||
|
||||
private TagBuilder GenerateTextBox(ModelMetadata metadata, string inputTypeHint, string inputType)
|
||||
private TagBuilder GenerateTextBox(ModelExplorer modelExplorer, string inputTypeHint, string inputType)
|
||||
{
|
||||
var format = Format;
|
||||
if (string.IsNullOrEmpty(format))
|
||||
{
|
||||
format = GetFormat(metadata, inputTypeHint, inputType);
|
||||
format = GetFormat(modelExplorer, inputTypeHint, inputType);
|
||||
}
|
||||
|
||||
return Generator.GenerateTextBox(
|
||||
ViewContext,
|
||||
metadata,
|
||||
modelExplorer,
|
||||
For.Name,
|
||||
value: metadata.Model,
|
||||
value: modelExplorer.Model,
|
||||
format: Format,
|
||||
htmlAttributes: null);
|
||||
}
|
||||
|
||||
// Get a fall-back format based on the metadata.
|
||||
private string GetFormat(ModelMetadata metadata, string inputTypeHint, string inputType)
|
||||
private string GetFormat(ModelExplorer modelExplorer, string inputTypeHint, string inputType)
|
||||
{
|
||||
string format;
|
||||
string rfc3339Format;
|
||||
if (string.Equals("decimal", inputTypeHint, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals("text", inputType, StringComparison.Ordinal) &&
|
||||
string.IsNullOrEmpty(metadata.EditFormatString))
|
||||
string.IsNullOrEmpty(modelExplorer.Metadata.EditFormatString))
|
||||
{
|
||||
// Decimal data is edited using an <input type="text"/> element, with a reasonable format.
|
||||
// EditFormatString has precedence over this fall-back format.
|
||||
|
|
@ -304,8 +305,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
}
|
||||
else if (_rfc3339Formats.TryGetValue(inputType, out rfc3339Format) &&
|
||||
ViewContext.Html5DateRenderingMode == Html5DateRenderingMode.Rfc3339 &&
|
||||
!metadata.HasNonDefaultEditFormat &&
|
||||
(typeof(DateTime) == metadata.RealModelType || typeof(DateTimeOffset) == metadata.RealModelType))
|
||||
!modelExplorer.Metadata.HasNonDefaultEditFormat &&
|
||||
(typeof(DateTime) == modelExplorer.ModelType || typeof(DateTimeOffset) == modelExplorer.ModelType))
|
||||
{
|
||||
// Rfc3339 mode _may_ override EditFormatString in a limited number of cases e.g. EditFormatString
|
||||
// must be a default format (i.e. came from a built-in [DataType] attribute).
|
||||
|
|
@ -314,15 +315,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
else
|
||||
{
|
||||
// Otherwise use EditFormatString, if any.
|
||||
format = metadata.EditFormatString;
|
||||
format = modelExplorer.Metadata.EditFormatString;
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
private string GetInputType(ModelMetadata metadata, out string inputTypeHint)
|
||||
private string GetInputType(ModelExplorer modelExplorer, out string inputTypeHint)
|
||||
{
|
||||
foreach (var hint in GetInputTypeHints(metadata))
|
||||
foreach (var hint in GetInputTypeHints(modelExplorer))
|
||||
{
|
||||
string inputType;
|
||||
if (_defaultInputTypes.TryGetValue(hint, out inputType))
|
||||
|
|
@ -337,12 +338,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
}
|
||||
|
||||
// A variant of TemplateRenderer.GetViewNames(). Main change relates to bool? handling.
|
||||
private static IEnumerable<string> GetInputTypeHints(ModelMetadata metadata)
|
||||
private static IEnumerable<string> GetInputTypeHints(ModelExplorer modelExplorer)
|
||||
{
|
||||
var inputTypeHints = new string[]
|
||||
{
|
||||
metadata.TemplateHint,
|
||||
metadata.DataTypeName,
|
||||
modelExplorer.Metadata.TemplateHint,
|
||||
modelExplorer.Metadata.DataTypeName,
|
||||
};
|
||||
|
||||
foreach (string inputTypeHint in inputTypeHints.Where(s => !string.IsNullOrEmpty(s)))
|
||||
|
|
@ -352,7 +353,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
|
||||
// In most cases, we don't want to search for Nullable<T>. We want to search for T, which should handle
|
||||
// both T and Nullable<T>. However we special-case bool? to avoid turning an <input/> into a <select/>.
|
||||
var fieldType = metadata.RealModelType;
|
||||
var fieldType = modelExplorer.ModelType;
|
||||
if (typeof(bool?) != fieldType)
|
||||
{
|
||||
var underlyingType = Nullable.GetUnderlyingType(fieldType);
|
||||
|
|
@ -369,7 +370,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Nothing more to provide
|
||||
yield break;
|
||||
}
|
||||
else if (!metadata.IsComplexType)
|
||||
else if (!modelExplorer.Metadata.IsComplexType)
|
||||
{
|
||||
// IsEnum is false for the Enum class itself
|
||||
if (fieldType.IsEnum())
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
if (For != null)
|
||||
{
|
||||
var tagBuilder = Generator.GenerateLabel(ViewContext,
|
||||
For.Metadata,
|
||||
For.ModelExplorer,
|
||||
For.Name,
|
||||
labelText: null,
|
||||
htmlAttributes: null);
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
// Base allowMultiple on the instance or declared type of the expression to avoid a
|
||||
// "SelectExpressionNotEnumerable" InvalidOperationException during generation.
|
||||
// Metadata.IsCollectionType() is similar but does not take runtime type into account.
|
||||
var realModelType = For.Metadata.RealModelType;
|
||||
var realModelType = For.ModelExplorer.ModelType;
|
||||
var allowMultiple =
|
||||
typeof(string) != realModelType && typeof(IEnumerable).IsAssignableFrom(realModelType);
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
ICollection<string> selectedValues;
|
||||
var tagBuilder = Generator.GenerateSelect(
|
||||
ViewContext,
|
||||
For.Metadata,
|
||||
For.ModelExplorer,
|
||||
optionLabel: null,
|
||||
expression: For.Name,
|
||||
selectList: items,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
{
|
||||
var tagBuilder = Generator.GenerateTextArea(
|
||||
ViewContext,
|
||||
For.Metadata,
|
||||
For.ModelExplorer,
|
||||
For.Name,
|
||||
rows: 0,
|
||||
columns: 0,
|
||||
|
|
|
|||
|
|
@ -420,14 +420,13 @@ namespace System.Web.Http
|
|||
/// </param>
|
||||
public void Validate<TEntity>(TEntity entity, string keyPrefix)
|
||||
{
|
||||
var modelMetadata = MetadataProvider.GetMetadataForType(() => entity, typeof(TEntity));
|
||||
var modelExplorer = MetadataProvider.GetModelExplorerForType(typeof(TEntity), entity);
|
||||
|
||||
var modelValidationContext = new ModelValidationContext(
|
||||
keyPrefix,
|
||||
BindingContext.ValidatorProvider,
|
||||
ModelState,
|
||||
modelMetadata,
|
||||
containerMetadata: null);
|
||||
modelExplorer);
|
||||
|
||||
ObjectValidator.Validate(modelValidationContext);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, modelType),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(modelType),
|
||||
ModelName = "someName",
|
||||
ValueProvider = Mock.Of<IValueProvider>(),
|
||||
ModelState = new ModelStateDictionary(),
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||
|
||||
var actionContext = GetActionContext(contentBytes);
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User));
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(User));
|
||||
var context = new InputFormatterContext(actionContext, metadata.ModelType);
|
||||
|
||||
// Act
|
||||
|
|
@ -119,7 +119,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||
|
||||
var httpContext = GetActionContext(contentBytes);
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User));
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(User));
|
||||
var context = new InputFormatterContext(httpContext, metadata.ModelType);
|
||||
|
||||
// Act and Assert
|
||||
|
|
@ -135,7 +135,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||
|
||||
var actionContext = GetActionContext(contentBytes);
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User));
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(User));
|
||||
var context = new InputFormatterContext(actionContext, metadata.ModelType);
|
||||
|
||||
// Act
|
||||
|
|
@ -155,7 +155,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||
|
||||
var actionContext = GetActionContext(contentBytes);
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User));
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(User));
|
||||
var context = new InputFormatterContext(actionContext, metadata.ModelType);
|
||||
actionContext.ModelState.MaxAllowedErrors = 3;
|
||||
actionContext.ModelState.AddModelError("key1", "error1");
|
||||
|
|
@ -193,8 +193,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
jsonFormatter.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error;
|
||||
|
||||
var actionContext = GetActionContext(contentBytes, "application/json;charset=utf-8");
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(modelAccessor: null,
|
||||
modelType: typeof(UserLogin));
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(UserLogin));
|
||||
var inputFormatterContext = new InputFormatterContext(actionContext, metadata.ModelType);
|
||||
|
||||
// Act
|
||||
|
|
@ -222,8 +221,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
};
|
||||
|
||||
var actionContext = GetActionContext(contentBytes, "application/json;charset=utf-8");
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(modelAccessor: null,
|
||||
modelType: typeof(UserLogin));
|
||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(UserLogin));
|
||||
var inputFormatterContext = new InputFormatterContext(actionContext, metadata.ModelType);
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -53,8 +53,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
// Arrange
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
var modelMetadata = metadataProvider.GetMetadataForType(
|
||||
modelAccessor: null,
|
||||
modelType: typeof(TypeWithIncludedPropertiesUsingBindAttribute));
|
||||
typeof(TypeWithIncludedPropertiesUsingBindAttribute));
|
||||
|
||||
// Act
|
||||
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||
|
|
@ -75,9 +74,9 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
var methodInfo = type.GetMethod("ParameterWithNoBindAttribute");
|
||||
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
|
||||
methodInfo: methodInfo,
|
||||
parameterName: "parameter");
|
||||
var modelMetadata = metadataProvider.GetMetadataForParameter(
|
||||
methodInfo: methodInfo,
|
||||
parameterName: "parameter");
|
||||
|
||||
// Act
|
||||
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||
|
|
@ -104,9 +103,9 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
var methodInfo = type.GetMethod(actionMethodName);
|
||||
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
|
||||
methodInfo: methodInfo,
|
||||
parameterName: "parameter");
|
||||
var modelMetadata = metadataProvider.GetMetadataForParameter(
|
||||
methodInfo: methodInfo,
|
||||
parameterName: "parameter");
|
||||
|
||||
// Act
|
||||
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||
|
|
@ -133,9 +132,9 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
var methodInfo = type.GetMethod(actionMethodName);
|
||||
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
|
||||
methodInfo: methodInfo,
|
||||
parameterName: "parameter1");
|
||||
var modelMetadata = metadataProvider.GetMetadataForParameter(
|
||||
methodInfo: methodInfo,
|
||||
parameterName: "parameter1");
|
||||
|
||||
// Act
|
||||
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||
|
|
@ -275,9 +274,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||
.Callback((ModelBindingContext context) =>
|
||||
{
|
||||
context.ModelMetadata = metadataProvider.GetMetadataForType(
|
||||
modelAccessor: null,
|
||||
modelType: typeof(string));
|
||||
context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string));
|
||||
})
|
||||
.Returns(Task.FromResult(result: new ModelBindingResult(value, "", true)));
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, null, typeof(MyModel), null))
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, typeof(MyModel), null))
|
||||
.Verifiable();
|
||||
|
||||
var binder = new Mock<IModelBinder>();
|
||||
|
|
@ -136,8 +136,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, null, typeof(MyModel), null))
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, typeof(MyModel), null))
|
||||
.Verifiable();
|
||||
|
||||
var binder = new Mock<IModelBinder>();
|
||||
|
|
@ -227,8 +227,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, null, typeof(MyModel), null))
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, typeof(MyModel), null))
|
||||
.Verifiable();
|
||||
|
||||
var binder = new Mock<IModelBinder>();
|
||||
|
|
@ -484,8 +484,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, null, typeof(MyModel), null))
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, typeof(MyModel), null))
|
||||
.Verifiable();
|
||||
|
||||
var binder = new Mock<IModelBinder>();
|
||||
|
|
@ -580,8 +580,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, null, typeof(MyModel), null))
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object, null, typeof(MyModel), null))
|
||||
.Verifiable();
|
||||
|
||||
var binder = new Mock<IModelBinder>();
|
||||
|
|
@ -655,13 +655,14 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
metadataProvider.Setup(m => m.GetMetadataForType(null, It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(metadataProvider.Object,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: typeof(MyModel),
|
||||
propertyName: null))
|
||||
.Verifiable();
|
||||
metadataProvider
|
||||
.Setup(m => m.GetMetadataForType(It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata(
|
||||
metadataProvider.Object,
|
||||
containerType: null,
|
||||
modelType: typeof(MyModel),
|
||||
propertyName: null))
|
||||
.Verifiable();
|
||||
|
||||
var binder = new Mock<IModelBinder>();
|
||||
binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
private static readonly IModelMetadataProvider _metadataProvider = new EmptyModelMetadataProvider();
|
||||
private static readonly ModelMetadata _metadata = _metadataProvider.GetMetadataForProperty(
|
||||
modelAccessor: null,
|
||||
containerType: typeof(string),
|
||||
propertyName: "Length");
|
||||
typeof(string),
|
||||
"Length");
|
||||
|
||||
public static TheoryData<string> SomeNames
|
||||
{
|
||||
|
|
|
|||
|
|
@ -71,17 +71,14 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
// Arrange
|
||||
var html = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
var metadata =
|
||||
new EmptyModelMetadataProvider()
|
||||
.GetMetadataForType(null, typeof(DefaultTemplatesUtilities.ObjectTemplateModel));
|
||||
metadata.NullDisplayText = "(null value)";
|
||||
html.ViewData.ModelMetadata = metadata;
|
||||
|
||||
html.ViewData.ModelMetadata.NullDisplayText = "(null value)";
|
||||
|
||||
// Act
|
||||
var result = DefaultDisplayTemplates.ObjectTemplate(html);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(metadata.NullDisplayText, result);
|
||||
Assert.Equal("(null value)", result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -93,13 +90,13 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
// Arrange
|
||||
var model = new DefaultTemplatesUtilities.ObjectTemplateModel();
|
||||
model.Property1 = simpleDisplayText;
|
||||
|
||||
var html = DefaultTemplatesUtilities.GetHtmlHelper(model);
|
||||
var metadata =
|
||||
new EmptyModelMetadataProvider()
|
||||
.GetMetadataForType(() => model, typeof(DefaultTemplatesUtilities.ObjectTemplateModel));
|
||||
metadata.HtmlEncode = htmlEncode;
|
||||
metadata.SimpleDisplayText = simpleDisplayText;
|
||||
html.ViewData.ModelMetadata = metadata;
|
||||
|
||||
html.ViewData.ModelMetadata.HtmlEncode = htmlEncode;
|
||||
html.ViewData.ModelMetadata.SimpleDisplayProperty = "Property1";
|
||||
|
||||
html.ViewData.TemplateInfo.AddVisited("foo");
|
||||
html.ViewData.TemplateInfo.AddVisited("bar");
|
||||
|
||||
|
|
|
|||
|
|
@ -103,12 +103,10 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
// Arrange
|
||||
var html = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
var metadata =
|
||||
new EmptyModelMetadataProvider()
|
||||
.GetMetadataForType(null, typeof(DefaultTemplatesUtilities.ObjectTemplateModel));
|
||||
metadata.NullDisplayText = "Null Display Text";
|
||||
metadata.SimpleDisplayText = "Simple Display Text";
|
||||
html.ViewData.ModelMetadata = metadata;
|
||||
|
||||
html.ViewData.ModelMetadata.NullDisplayText = "Null Display Text";
|
||||
html.ViewData.ModelMetadata.SimpleDisplayProperty = "Property1";
|
||||
|
||||
html.ViewData.TemplateInfo.AddVisited("foo");
|
||||
html.ViewData.TemplateInfo.AddVisited("bar");
|
||||
|
||||
|
|
@ -116,7 +114,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
var result = DefaultEditorTemplates.ObjectTemplate(html);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(metadata.NullDisplayText, result);
|
||||
Assert.Equal(html.ViewData.ModelMetadata.NullDisplayText, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -127,15 +125,17 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
string expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var model = new DefaultTemplatesUtilities.ObjectTemplateModel();
|
||||
var model = new DefaultTemplatesUtilities.ObjectTemplateModel()
|
||||
{
|
||||
Property1 = simpleDisplayText,
|
||||
};
|
||||
|
||||
var html = DefaultTemplatesUtilities.GetHtmlHelper(model);
|
||||
var metadata =
|
||||
new EmptyModelMetadataProvider()
|
||||
.GetMetadataForType(() => model, typeof(DefaultTemplatesUtilities.ObjectTemplateModel));
|
||||
metadata.HtmlEncode = htmlEncode;
|
||||
metadata.NullDisplayText = "Null Display Text";
|
||||
metadata.SimpleDisplayText = simpleDisplayText;
|
||||
html.ViewData.ModelMetadata = metadata;
|
||||
|
||||
html.ViewData.ModelMetadata.HtmlEncode = htmlEncode;
|
||||
html.ViewData.ModelMetadata.NullDisplayText = "Null Display Text";
|
||||
html.ViewData.ModelMetadata.SimpleDisplayProperty = "Property1";
|
||||
|
||||
html.ViewData.TemplateInfo.AddVisited("foo");
|
||||
html.ViewData.TemplateInfo.AddVisited("bar");
|
||||
|
||||
|
|
@ -917,7 +917,9 @@ Environment.NewLine;
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, string name)
|
||||
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
|
||||
ModelExplorer modelExplorer,
|
||||
string name)
|
||||
{
|
||||
return Enumerable.Empty<ModelClientValidationRule>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// 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 System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
|
@ -45,6 +46,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return GetHtmlHelper<ObjectTemplateModel>(model: null);
|
||||
}
|
||||
|
||||
public static HtmlHelper<IEnumerable<ObjectTemplateModel>> GetHtmlHelperForEnumerable()
|
||||
{
|
||||
return GetHtmlHelper<IEnumerable<ObjectTemplateModel>>(model: null);
|
||||
}
|
||||
|
||||
public static HtmlHelper<ObjectTemplateModel> GetHtmlHelper(IUrlHelper urlHelper)
|
||||
{
|
||||
return GetHtmlHelper<ObjectTemplateModel>(
|
||||
|
|
@ -82,11 +88,27 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return GetHtmlHelper(model, CreateViewEngine());
|
||||
}
|
||||
|
||||
public static HtmlHelper<IEnumerable<TModel>> GetHtmlHelperForEnumerable<TModel>(TModel model)
|
||||
{
|
||||
return GetHtmlHelper<IEnumerable<TModel>>(new TModel[] { model });
|
||||
}
|
||||
|
||||
public static HtmlHelper<TModel> GetHtmlHelper<TModel>(IModelMetadataProvider provider)
|
||||
{
|
||||
return GetHtmlHelper<TModel>(model: default(TModel), provider: provider);
|
||||
}
|
||||
|
||||
public static HtmlHelper<ObjectTemplateModel> GetHtmlHelper(IModelMetadataProvider provider)
|
||||
{
|
||||
return GetHtmlHelper<ObjectTemplateModel>(model: null, provider: provider);
|
||||
}
|
||||
|
||||
public static HtmlHelper<IEnumerable<ObjectTemplateModel>> GetHtmlHelperForEnumerable(
|
||||
IModelMetadataProvider provider)
|
||||
{
|
||||
return GetHtmlHelper<IEnumerable<ObjectTemplateModel>>(model: null, provider: provider);
|
||||
}
|
||||
|
||||
public static HtmlHelper<TModel> GetHtmlHelper<TModel>(TModel model, IModelMetadataProvider provider)
|
||||
{
|
||||
return GetHtmlHelper(model, CreateUrlHelper(), CreateViewEngine(), provider);
|
||||
|
|
@ -191,8 +213,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
public static string FormatOutput(IHtmlHelper helper, object model)
|
||||
{
|
||||
var metadata = helper.MetadataProvider.GetMetadataForType(() => model, model.GetType());
|
||||
return FormatOutput(metadata);
|
||||
var modelExplorer = helper.MetadataProvider.GetModelExplorerForType(model.GetType(), model);
|
||||
return FormatOutput(modelExplorer);
|
||||
}
|
||||
|
||||
private static ICompositeViewEngine CreateViewEngine()
|
||||
|
|
@ -203,7 +225,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
.Callback(async (ViewContext v) =>
|
||||
{
|
||||
view.ToString();
|
||||
await v.Writer.WriteAsync(FormatOutput(v.ViewData.ModelMetadata));
|
||||
await v.Writer.WriteAsync(FormatOutput(v.ViewData.ModelExplorer));
|
||||
})
|
||||
.Returns(Task.FromResult(0));
|
||||
|
||||
|
|
@ -228,14 +250,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
optionsAccessor.Object);
|
||||
}
|
||||
|
||||
private static string FormatOutput(ModelMetadata metadata)
|
||||
private static string FormatOutput(ModelExplorer modelExplorer)
|
||||
{
|
||||
var metadata = modelExplorer.Metadata;
|
||||
return string.Format(CultureInfo.InvariantCulture,
|
||||
"Model = {0}, ModelType = {1}, PropertyName = {2}, SimpleDisplayText = {3}",
|
||||
metadata.Model ?? "(null)",
|
||||
modelExplorer.Model ?? "(null)",
|
||||
metadata.ModelType == null ? "(null)" : metadata.ModelType.FullName,
|
||||
metadata.PropertyName ?? "(null)",
|
||||
metadata.SimpleDisplayText ?? "(null)");
|
||||
modelExplorer.GetSimpleDisplayText() ?? "(null)");
|
||||
}
|
||||
|
||||
private static IUrlHelper CreateUrlHelper()
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.Rendering.Expressions
|
|||
provider);
|
||||
|
||||
// Assert
|
||||
Assert.Same(myModel, metadata.Container);
|
||||
Assert.Same(myModel, metadata.Container.Model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.Rendering.Expressions
|
|||
provider);
|
||||
|
||||
// Assert
|
||||
Assert.Same(myModel, metadata.Container);
|
||||
Assert.Same(myModel, metadata.Container.Model);
|
||||
}
|
||||
|
||||
private class TestModel
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Core
|
||||
|
|
@ -43,8 +42,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
// Arrange
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
var enumerableHelper =
|
||||
DefaultTemplatesUtilities.GetHtmlHelper<IEnumerable<DefaultTemplatesUtilities.ObjectTemplateModel>>(model: null);
|
||||
var enumerableHelper = DefaultTemplatesUtilities.GetHtmlHelperForEnumerable();
|
||||
|
||||
// Act
|
||||
var displayNameResult = helper.DisplayName("Property1");
|
||||
|
|
@ -57,13 +55,27 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
Assert.Equal("Property1", displayNameForEnumerableResult);
|
||||
}
|
||||
|
||||
// If the metadata is for a type (not property), then DisplayName(expression) will evaluate the expression
|
||||
[Fact]
|
||||
public void DisplayNameHelpers_DisplayName_Evaluates_Expression()
|
||||
{
|
||||
// Arrange
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
helper.ViewData["value"] = "testvalue";
|
||||
|
||||
// Act
|
||||
var displayNameResult = helper.DisplayName(expression: "value");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("value", displayNameResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayNameHelpers_ReturnPropertyName_ForNestedProperty()
|
||||
{
|
||||
// Arrange
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper<OuterClass>(model: null);
|
||||
var enumerableHelper =
|
||||
DefaultTemplatesUtilities.GetHtmlHelper<IEnumerable<OuterClass>>(model: null);
|
||||
var enumerableHelper = DefaultTemplatesUtilities.GetHtmlHelperForEnumerable<OuterClass>(model: null);
|
||||
|
||||
// Act
|
||||
var displayNameResult = helper.DisplayName("Inner.Id");
|
||||
|
|
@ -76,86 +88,24 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
Assert.Equal("Id", displayNameForEnumerableResult);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("Custom property name from metadata")]
|
||||
public void DisplayNameHelpers_ReturnMetadataPropertyName_IfOverridden(string propertyName)
|
||||
{
|
||||
// Arrange
|
||||
var metadata = new ModelMetadata(
|
||||
new DataAnnotationsModelMetadataProvider(),
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: typeof(string), // Ensure FromStringExpression() doesn't ignore the ModelMetadata.
|
||||
propertyName: propertyName);
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
helper.ViewData.ModelMetadata = metadata;
|
||||
var enumerableHelper =
|
||||
DefaultTemplatesUtilities.GetHtmlHelper<IEnumerable<DefaultTemplatesUtilities.ObjectTemplateModel>>(model: null);
|
||||
enumerableHelper.ViewData.ModelMetadata = metadata;
|
||||
|
||||
// Act
|
||||
var displayNameResult = helper.DisplayName(expression: string.Empty);
|
||||
var displayNameForResult = helper.DisplayNameFor(m => m);
|
||||
var displayNameForEnumerableResult = enumerableHelper.DisplayNameFor(m => m);
|
||||
var displayNameForModelResult = helper.DisplayNameForModel();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(propertyName, displayNameResult);
|
||||
Assert.Equal(propertyName, displayNameForResult);
|
||||
Assert.Equal(propertyName, displayNameForEnumerableResult);
|
||||
Assert.Equal(propertyName, displayNameForModelResult);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("Custom property name from metadata")]
|
||||
public void DisplayNameHelpers_ReturnMetadataPropertyNameForProperty_IfOverridden(string propertyName)
|
||||
{
|
||||
// Arrange
|
||||
var metadataHelper = new MetadataHelper();
|
||||
var metadata = new ModelMetadata(
|
||||
metadataHelper.MetadataProvider.Object,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: typeof(object),
|
||||
propertyName: propertyName);
|
||||
metadataHelper.MetadataProvider
|
||||
.Setup(provider => provider.GetMetadataForProperty(It.IsAny<Func<object>>(), It.IsAny<Type>(), "Property1"))
|
||||
.Returns(metadata);
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(metadataHelper.MetadataProvider.Object);
|
||||
var enumerableHelper =
|
||||
DefaultTemplatesUtilities.GetHtmlHelper<IEnumerable<DefaultTemplatesUtilities.ObjectTemplateModel>>(
|
||||
model: null,
|
||||
provider: metadataHelper.MetadataProvider.Object);
|
||||
|
||||
// Act
|
||||
var displayNameForResult = helper.DisplayNameFor(m => m.Property1);
|
||||
var displayNameForEnumerableResult = enumerableHelper.DisplayNameFor(m => m.Property1);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(propertyName, displayNameForResult);
|
||||
Assert.Equal(propertyName, displayNameForEnumerableResult);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")] // Empty display name wins over non-empty property name.
|
||||
[InlineData("Custom display name from metadata")]
|
||||
public void DisplayNameHelpers_ReturnDisplayName_IfNonNull(string displayName)
|
||||
{
|
||||
// Arrange
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
helper.ViewData.ModelMetadata.DisplayName = displayName;
|
||||
var enumerableHelper =
|
||||
DefaultTemplatesUtilities.GetHtmlHelper<IEnumerable<DefaultTemplatesUtilities.ObjectTemplateModel>>(model: null);
|
||||
enumerableHelper.ViewData.ModelMetadata.DisplayName = displayName;
|
||||
var provider = new TestModelMetadataProvider();
|
||||
provider
|
||||
.ForType<DefaultTemplatesUtilities.ObjectTemplateModel>()
|
||||
.Then(mm => mm.DisplayName = displayName);
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(provider: provider);
|
||||
var enumerableHelper = DefaultTemplatesUtilities.GetHtmlHelperForEnumerable(provider: provider);
|
||||
|
||||
// Act
|
||||
var displayNameResult = helper.DisplayName(expression: string.Empty);
|
||||
var displayNameForResult = helper.DisplayNameFor(m => m);
|
||||
var displayNameForEnumerableResult = enumerableHelper.DisplayNameFor(m => m);
|
||||
var displayNameForEnumerableResult = enumerableHelper.DisplayNameFor((DefaultTemplatesUtilities.ObjectTemplateModel m) => m);
|
||||
var displayNameForModelResult = helper.DisplayNameForModel();
|
||||
|
||||
// Assert
|
||||
|
|
@ -171,15 +121,13 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
public void DisplayNameHelpers_ReturnDisplayNameForProperty_IfNonNull(string displayName)
|
||||
{
|
||||
// Arrange
|
||||
var metadataHelper = new MetadataHelper(); // All properties will use the same metadata.
|
||||
metadataHelper.Metadata
|
||||
.Setup(metadata => metadata.DisplayName)
|
||||
.Returns(displayName);
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(metadataHelper.MetadataProvider.Object);
|
||||
var enumerableHelper =
|
||||
DefaultTemplatesUtilities.GetHtmlHelper<IEnumerable<DefaultTemplatesUtilities.ObjectTemplateModel>>(
|
||||
model: null,
|
||||
provider: metadataHelper.MetadataProvider.Object);
|
||||
var provider = new TestModelMetadataProvider();
|
||||
provider
|
||||
.ForProperty<DefaultTemplatesUtilities.ObjectTemplateModel>("Property1")
|
||||
.Then(mm => mm.DisplayName = displayName);
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(provider: provider);
|
||||
var enumerableHelper = DefaultTemplatesUtilities.GetHtmlHelperForEnumerable(provider: provider);
|
||||
|
||||
// Act
|
||||
var displayNameResult = helper.DisplayName("Property1");
|
||||
|
|
@ -202,8 +150,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
string expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var metadataHelper = new MetadataHelper();
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(metadataHelper.MetadataProvider.Object);
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
|
||||
// Act
|
||||
var result = helper.DisplayName(expression);
|
||||
|
|
@ -213,29 +160,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayNameFor_ConsultsMetadataProviderForMetadataAboutProperty()
|
||||
{
|
||||
// Arrange
|
||||
var modelType = typeof(DefaultTemplatesUtilities.ObjectTemplateModel);
|
||||
var metadataHelper = new MetadataHelper();
|
||||
metadataHelper.MetadataProvider
|
||||
.Setup(p => p.GetMetadataForProperty(It.IsAny<Func<object>>(), modelType, "Property1"))
|
||||
.Returns(metadataHelper.Metadata.Object)
|
||||
.Verifiable();
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(metadataHelper.MetadataProvider.Object);
|
||||
|
||||
// Act
|
||||
var result = helper.DisplayNameFor(m => m.Property1);
|
||||
|
||||
// Assert
|
||||
metadataHelper.MetadataProvider.Verify();
|
||||
|
||||
// DisplayNameFor() falls back to expression name when DisplayName and PropertyName are null.
|
||||
Assert.Equal("Property1", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayNameFor_ThrowsInvalidOperation_IfExpressionUnsupported()
|
||||
{
|
||||
|
|
@ -303,25 +227,5 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
public InnerClass Inner { get; set; }
|
||||
}
|
||||
|
||||
private sealed class MetadataHelper
|
||||
{
|
||||
public Mock<ModelMetadata> Metadata { get; set; }
|
||||
public Mock<IModelMetadataProvider> MetadataProvider { get; set; }
|
||||
|
||||
public MetadataHelper()
|
||||
{
|
||||
MetadataProvider = new Mock<IModelMetadataProvider>();
|
||||
Metadata = new Mock<ModelMetadata>(MetadataProvider.Object, null, null, typeof(object), null);
|
||||
Metadata.SetupGet(m => m.Properties).CallBase();
|
||||
|
||||
MetadataProvider.Setup(p => p.GetMetadataForProperties(It.IsAny<object>(), It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata[0]);
|
||||
MetadataProvider.Setup(p => p.GetMetadataForProperty(It.IsAny<Func<object>>(), It.IsAny<Type>(), It.IsAny<string>()))
|
||||
.Returns(Metadata.Object);
|
||||
MetadataProvider.Setup(p => p.GetMetadataForType(It.IsAny<Func<object>>(), It.IsAny<Type>()))
|
||||
.Returns(Metadata.Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -115,9 +115,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public void DisplayText_ReturnsSimpleDisplayText_IfSetAndValueNonNull()
|
||||
{
|
||||
// Arrange
|
||||
var model = new OverriddenToStringModel("Ignored text");
|
||||
var model = new OverriddenToStringModel("Ignored text")
|
||||
{
|
||||
SimpleDisplay = "Simple display text",
|
||||
};
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model);
|
||||
helper.ViewData.ModelMetadata.SimpleDisplayText = "Simple display text";
|
||||
helper.ViewData.ModelMetadata.SimpleDisplayProperty = nameof(OverriddenToStringModel.SimpleDisplay);
|
||||
|
||||
// Act
|
||||
var result = helper.DisplayText(expression: string.Empty);
|
||||
|
|
@ -130,9 +134,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
public void DisplayTextFor_ReturnsSimpleDisplayText_IfSetAndValueNonNull()
|
||||
{
|
||||
// Arrange
|
||||
var model = new OverriddenToStringModel("Ignored text");
|
||||
var model = new OverriddenToStringModel("Ignored text")
|
||||
{
|
||||
SimpleDisplay = "Simple display text",
|
||||
};
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model);
|
||||
helper.ViewData.ModelMetadata.SimpleDisplayText = "Simple display text";
|
||||
helper.ViewData.ModelMetadata.SimpleDisplayProperty = nameof(OverriddenToStringModel.SimpleDisplay);
|
||||
|
||||
// Act
|
||||
var result = helper.DisplayTextFor(m => m);
|
||||
|
|
@ -148,9 +156,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
var model = new OverriddenToStringModel("Ignored text")
|
||||
{
|
||||
Name = "Property value",
|
||||
SimpleDisplay = "Simple display text",
|
||||
};
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(model);
|
||||
helper.ViewData.ModelMetadata.SimpleDisplayText = "Simple display text";
|
||||
helper.ViewData.ModelMetadata.SimpleDisplayProperty = nameof(OverriddenToStringModel.SimpleDisplay);
|
||||
|
||||
// Act
|
||||
var result = helper.DisplayText("Name");
|
||||
|
|
@ -276,6 +286,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
_simpleDisplayText = simpleDisplayText;
|
||||
}
|
||||
|
||||
public string SimpleDisplay { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Core
|
||||
|
|
@ -67,15 +66,15 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
public void LabelHelpers_ReturnEmptyForModel_IfMetadataPropertyNameEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = new ModelMetadata(
|
||||
new DataAnnotationsModelMetadataProvider(),
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: typeof(object),
|
||||
propertyName: string.Empty);
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
helper.ViewData.ModelMetadata = metadata;
|
||||
helper.ViewData.ModelExplorer = new ModelExplorer(provider, metadata, model: null);
|
||||
|
||||
// Act
|
||||
var labelResult = helper.Label(expression: string.Empty);
|
||||
|
|
@ -90,21 +89,20 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
Assert.Empty(labelForModelResult.ToString());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("MyProperty")]
|
||||
[InlineData("Custom property name from metadata")]
|
||||
public void LabelHelpers_DisplayMetadataPropertyName_IfOverridden(string propertyName)
|
||||
[Fact]
|
||||
public void LabelHelpers_DisplayMetadataPropertyNameForProperty()
|
||||
{
|
||||
// Arrange
|
||||
var metadata = new ModelMetadata(
|
||||
new DataAnnotationsModelMetadataProvider(),
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: typeof(string), // Ensure FromStringExpression() doesn't ignore the ModelMetadata.
|
||||
propertyName: propertyName);
|
||||
var propertyName = "Property1";
|
||||
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
|
||||
var modelExplorer = provider
|
||||
.GetModelExplorerForType(typeof(DefaultTemplatesUtilities.ObjectTemplateModel), model: null)
|
||||
.GetExplorerForProperty(propertyName);
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
helper.ViewData.ModelMetadata = metadata;
|
||||
helper.ViewData.ModelExplorer = modelExplorer;
|
||||
|
||||
// Act
|
||||
var labelResult = helper.Label(expression: string.Empty);
|
||||
|
|
@ -117,30 +115,19 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
Assert.Equal("<label for=\"\">" + propertyName + "</label>", labelForModelResult.ToString());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("MyProperty")]
|
||||
[InlineData("Custom property name from metadata")]
|
||||
public void LabelHelpers_DisplayMetadataPropertyNameForProperty_IfOverridden(string propertyName)
|
||||
// If the metadata is for a type (not property), then Label(expression) will evaluate the expression
|
||||
[Fact]
|
||||
public void LabelHelpers_Label_Evaluates_Expression()
|
||||
{
|
||||
// Arrange
|
||||
var metadataHelper = new MetadataHelper();
|
||||
var metadata = new ModelMetadata(
|
||||
metadataHelper.MetadataProvider.Object,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: typeof(object),
|
||||
propertyName: propertyName);
|
||||
metadataHelper.MetadataProvider
|
||||
.Setup(provider => provider.GetMetadataForProperty(It.IsAny<Func<object>>(), It.IsAny<Type>(), "Property1"))
|
||||
.Returns(metadata);
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(metadataHelper.MetadataProvider.Object);
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
helper.ViewData["value"] = "testvalue";
|
||||
|
||||
// Act
|
||||
var labelForResult = helper.LabelFor(m => m.Property1);
|
||||
var labelResult = helper.Label(expression: "value");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("<label for=\"Property1\">" + propertyName + "</label>", labelForResult.ToString());
|
||||
Assert.Equal("<label for=\"value\">value</label>", labelResult.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -187,11 +174,15 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
public void LabelHelpers_ReturnEmptyForProperty_IfDisplayNameEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var metadataHelper = new MetadataHelper(); // All properties will use the same metadata.
|
||||
metadataHelper.Metadata
|
||||
.Setup(metadata => metadata.DisplayName)
|
||||
.Returns(string.Empty);
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(metadataHelper.MetadataProvider.Object);
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
|
||||
var modelExplorer = provider
|
||||
.GetModelExplorerForType(typeof(DefaultTemplatesUtilities.ObjectTemplateModel), model: null)
|
||||
.GetExplorerForProperty("Property1");
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
helper.ViewData.ModelExplorer = modelExplorer;
|
||||
helper.ViewData.ModelMetadata.DisplayName = string.Empty;
|
||||
|
||||
// Act
|
||||
var labelResult = helper.Label(expression: string.Empty);
|
||||
|
|
@ -212,11 +203,12 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
public void LabelHelpers_DisplayDisplayNameForProperty_IfNonNull(string displayName)
|
||||
{
|
||||
// Arrange
|
||||
var metadataHelper = new MetadataHelper(); // All properties will use the same metadata.
|
||||
metadataHelper.Metadata
|
||||
.Setup(metadata => metadata.DisplayName)
|
||||
.Returns(displayName);
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(metadataHelper.MetadataProvider.Object);
|
||||
var provider = new TestModelMetadataProvider();
|
||||
provider
|
||||
.ForProperty<DefaultTemplatesUtilities.ObjectTemplateModel>("Property1")
|
||||
.Then(mm => mm.DisplayName = displayName);
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(provider: provider);
|
||||
|
||||
// Act
|
||||
var labelResult = helper.Label("Property1");
|
||||
|
|
@ -238,8 +230,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
string expectedId)
|
||||
{
|
||||
// Arrange
|
||||
var metadataHelper = new MetadataHelper();
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(metadataHelper.MetadataProvider.Object);
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper();
|
||||
|
||||
// Act
|
||||
var result = helper.Label(expression);
|
||||
|
|
@ -249,29 +240,6 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
Assert.Equal("<label for=\"" + expectedId + "\">" + expectedText + "</label>", result.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelFor_ConsultsMetadataProviderForMetadataAboutProperty()
|
||||
{
|
||||
// Arrange
|
||||
var modelType = typeof(DefaultTemplatesUtilities.ObjectTemplateModel);
|
||||
var metadataHelper = new MetadataHelper();
|
||||
metadataHelper.MetadataProvider
|
||||
.Setup(p => p.GetMetadataForProperty(It.IsAny<Func<object>>(), modelType, "Property1"))
|
||||
.Returns(metadataHelper.Metadata.Object)
|
||||
.Verifiable();
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(metadataHelper.MetadataProvider.Object);
|
||||
|
||||
// Act
|
||||
var result = helper.LabelFor(m => m.Property1);
|
||||
|
||||
// Assert
|
||||
metadataHelper.MetadataProvider.Verify();
|
||||
|
||||
// LabelFor() falls back to expression name when DisplayName and PropertyName are null.
|
||||
Assert.Equal("<label for=\"Property1\">Property1</label>", result.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LabelFor_ThrowsInvalidOperation_IfExpressionUnsupported()
|
||||
{
|
||||
|
|
@ -309,25 +277,5 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
public InnerClass Inner { get; set; }
|
||||
}
|
||||
|
||||
private sealed class MetadataHelper
|
||||
{
|
||||
public Mock<ModelMetadata> Metadata { get; set; }
|
||||
public Mock<IModelMetadataProvider> MetadataProvider { get; set; }
|
||||
|
||||
public MetadataHelper()
|
||||
{
|
||||
MetadataProvider = new Mock<IModelMetadataProvider>();
|
||||
Metadata = new Mock<ModelMetadata>(MetadataProvider.Object, null, null, typeof(object), null);
|
||||
Metadata.SetupGet(m => m.Properties).CallBase();
|
||||
|
||||
MetadataProvider.Setup(p => p.GetMetadataForProperties(It.IsAny<object>(), It.IsAny<Type>()))
|
||||
.Returns(new ModelMetadata[0]);
|
||||
MetadataProvider.Setup(p => p.GetMetadataForProperty(It.IsAny<Func<object>>(), It.IsAny<Type>(), It.IsAny<string>()))
|
||||
.Returns(Metadata.Object);
|
||||
MetadataProvider.Setup(p => p.GetMetadataForType(It.IsAny<Func<object>>(), It.IsAny<Type>()))
|
||||
.Returns(Metadata.Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -139,13 +139,16 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
// Arrange
|
||||
var provider = new Mock<IModelMetadataProvider>(MockBehavior.Strict);
|
||||
var metadata =
|
||||
new Mock<ModelMetadata>(MockBehavior.Strict, provider.Object, null, null, typeof(object), null);
|
||||
var metadata = new Mock<ModelMetadata>(
|
||||
MockBehavior.Strict,
|
||||
provider.Object,
|
||||
null,
|
||||
typeof(object),
|
||||
null);
|
||||
provider
|
||||
.Setup(m => m.GetMetadataForType(
|
||||
It.IsAny<Func<object>>(),
|
||||
typeof(DefaultTemplatesUtilities.ObjectTemplateModel)))
|
||||
.Setup(m => m.GetMetadataForType(typeof(DefaultTemplatesUtilities.ObjectTemplateModel)))
|
||||
.Returns(metadata.Object);
|
||||
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(provider.Object);
|
||||
|
||||
// Act (do not throw)
|
||||
|
|
@ -159,7 +162,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
// Assert
|
||||
// Only the ViewDataDictionary should do anything with metadata.
|
||||
provider.Verify(
|
||||
m => m.GetMetadataForType(It.IsAny<Func<object>>(), typeof(DefaultTemplatesUtilities.ObjectTemplateModel)),
|
||||
m => m.GetMetadataForType(typeof(DefaultTemplatesUtilities.ObjectTemplateModel)),
|
||||
Times.Exactly(2));
|
||||
}
|
||||
|
||||
|
|
@ -168,12 +171,15 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
// Arrange
|
||||
var provider = new Mock<IModelMetadataProvider>(MockBehavior.Strict);
|
||||
var metadata =
|
||||
new Mock<ModelMetadata>(MockBehavior.Strict, provider.Object, null, null, typeof(object), null);
|
||||
var metadata = new Mock<ModelMetadata>(
|
||||
MockBehavior.Strict,
|
||||
provider.Object,
|
||||
null,
|
||||
typeof(object),
|
||||
null);
|
||||
|
||||
provider
|
||||
.Setup(m => m.GetMetadataForType(
|
||||
It.IsAny<Func<object>>(),
|
||||
typeof(DefaultTemplatesUtilities.ObjectTemplateModel)))
|
||||
.Setup(m => m.GetMetadataForType(typeof(DefaultTemplatesUtilities.ObjectTemplateModel)))
|
||||
.Returns(metadata.Object);
|
||||
var helper = DefaultTemplatesUtilities.GetHtmlHelper(provider.Object);
|
||||
|
||||
|
|
@ -186,7 +192,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
// Assert
|
||||
// Only the ViewDataDictionary should do anything with metadata.
|
||||
provider.Verify(
|
||||
m => m.GetMetadataForType(It.IsAny<Func<object>>(), typeof(DefaultTemplatesUtilities.ObjectTemplateModel)),
|
||||
m => m.GetMetadataForType(typeof(DefaultTemplatesUtilities.ObjectTemplateModel)),
|
||||
Times.Exactly(2));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class TestModelMetadataProvider : EmptyModelMetadataProvider
|
||||
{
|
||||
private List<MetadataBuilder> _builders = new List<MetadataBuilder>();
|
||||
|
||||
protected override ModelMetadata CreateMetadataFromPrototype([NotNull] ModelMetadata prototype)
|
||||
{
|
||||
var metadata = base.CreateMetadataFromPrototype(prototype);
|
||||
|
||||
if (prototype.PropertyName == null)
|
||||
{
|
||||
foreach (var builder in _builders)
|
||||
{
|
||||
builder.Apply(prototype.ModelType, metadata);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var builder in _builders)
|
||||
{
|
||||
builder.Apply(prototype.ContainerType, prototype.PropertyName, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public IMetadataBuilder ForType(Type type)
|
||||
{
|
||||
var builder = new MetadataBuilder(type);
|
||||
_builders.Add(builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public IMetadataBuilder ForType<TModel>()
|
||||
{
|
||||
var builder = new MetadataBuilder(typeof(TModel));
|
||||
_builders.Add(builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public IMetadataBuilder ForProperty(Type containerType, string propertyName)
|
||||
{
|
||||
var builder = new MetadataBuilder(containerType, propertyName);
|
||||
_builders.Add(builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public IMetadataBuilder ForProperty<TContainer>(string propertyName)
|
||||
{
|
||||
var builder = new MetadataBuilder(typeof(TContainer), propertyName);
|
||||
_builders.Add(builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public interface IMetadataBuilder
|
||||
{
|
||||
IMetadataBuilder Then(Action<ModelMetadata> action);
|
||||
}
|
||||
|
||||
private class MetadataBuilder : IMetadataBuilder
|
||||
{
|
||||
private List<Action<ModelMetadata>> _actions = new List<Action<ModelMetadata>>();
|
||||
|
||||
private readonly Type _type;
|
||||
private readonly Type _containerType;
|
||||
private readonly string _propertyName;
|
||||
|
||||
public MetadataBuilder(Type type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public MetadataBuilder(Type containerType, string propertyName)
|
||||
{
|
||||
_containerType = containerType;
|
||||
_propertyName = propertyName;
|
||||
}
|
||||
|
||||
public IMetadataBuilder Then(Action<ModelMetadata> action)
|
||||
{
|
||||
_actions.Add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Apply(Type type, ModelMetadata metadata)
|
||||
{
|
||||
if (type == _type)
|
||||
{
|
||||
foreach (var action in _actions)
|
||||
{
|
||||
action(metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Apply(Type containerType, string propertyName, ModelMetadata metadata)
|
||||
{
|
||||
if (containerType == _containerType && propertyName == _propertyName)
|
||||
{
|
||||
foreach (var action in _actions)
|
||||
{
|
||||
action(metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -193,12 +193,14 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
|
||||
// Assert
|
||||
Assert.NotNull(viewData1.ModelMetadata);
|
||||
Assert.NotNull(viewData1.ModelExplorer);
|
||||
Assert.Equal(expectedType, viewData1.ModelMetadata.ModelType);
|
||||
Assert.Equal(expectedType, viewData1.ModelMetadata.RealModelType);
|
||||
Assert.Equal(expectedType, viewData1.ModelExplorer.ModelType);
|
||||
|
||||
Assert.NotNull(viewData2.ModelMetadata);
|
||||
Assert.NotNull(viewData2.ModelExplorer);
|
||||
Assert.Equal(expectedType, viewData2.ModelMetadata.ModelType);
|
||||
Assert.Equal(expectedType, viewData2.ModelMetadata.RealModelType);
|
||||
Assert.Equal(expectedType, viewData2.ModelExplorer.ModelType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -56,12 +56,12 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
// Arrange
|
||||
var metadataProvider = new Mock<IModelMetadataProvider>();
|
||||
metadataProvider
|
||||
.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), typeof(object)))
|
||||
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(object)))
|
||||
.Setup(m => m.GetMetadataForType(typeof(object)))
|
||||
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)))
|
||||
.Verifiable();
|
||||
metadataProvider
|
||||
.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), typeof(TestModel)))
|
||||
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(TestModel)))
|
||||
.Setup(m => m.GetMetadataForType(typeof(TestModel)))
|
||||
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(typeof(TestModel)))
|
||||
.Verifiable();
|
||||
var modelState = new ModelStateDictionary();
|
||||
var viewData = new TestViewDataDictionary(metadataProvider.Object, modelState);
|
||||
|
|
@ -82,12 +82,12 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
// Arrange
|
||||
var metadataProvider = new Mock<IModelMetadataProvider>(MockBehavior.Strict);
|
||||
metadataProvider
|
||||
.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), typeof(object)))
|
||||
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(object)))
|
||||
.Setup(m => m.GetMetadataForType(typeof(object)))
|
||||
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)))
|
||||
.Verifiable();
|
||||
metadataProvider
|
||||
.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), typeof(TestModel)))
|
||||
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(TestModel)))
|
||||
.Setup(m => m.GetMetadataForType(typeof(TestModel)))
|
||||
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(typeof(TestModel)))
|
||||
.Verifiable();
|
||||
var modelState = new ModelStateDictionary();
|
||||
var viewData = new TestViewDataDictionary(metadataProvider.Object, modelState);
|
||||
|
|
@ -100,13 +100,10 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
Assert.NotNull(viewData.ModelMetadata);
|
||||
// Verifies if the GetMetadataForType is called only once.
|
||||
metadataProvider.Verify(
|
||||
m => m.GetMetadataForType(It.IsAny<Func<object>>(), typeof(object)), Times.Once());
|
||||
m => m.GetMetadataForType(typeof(object)), Times.Once());
|
||||
// Verifies if GetMetadataForProperties and GetMetadataForProperty is not called.
|
||||
metadataProvider.Verify(
|
||||
m => m.GetMetadataForProperties(It.IsAny<Func<object>>(), typeof(object)), Times.Never());
|
||||
metadataProvider.Verify(
|
||||
m => m.GetMetadataForProperty(
|
||||
It.IsAny<Func<object>>(), typeof(object), It.IsAny<string>()), Times.Never());
|
||||
m => m.GetMetadataForProperties(typeof(object)), Times.Never());
|
||||
}
|
||||
|
||||
public static TheoryData<object> SetModelData
|
||||
|
|
@ -299,19 +296,14 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var metadata = metadataProvider.GetMetadataForType(() => null, typeof(object));
|
||||
var source = new ViewDataDictionary(metadataProvider)
|
||||
{
|
||||
ModelMetadata = metadata,
|
||||
};
|
||||
var source = new ViewDataDictionary(metadataProvider);
|
||||
|
||||
// Act
|
||||
var viewData1 = new ViewDataDictionary(source);
|
||||
var viewData2 = new ViewDataDictionary(source, model: null);
|
||||
|
||||
// Assert
|
||||
Assert.Same(metadata, viewData1.ModelMetadata);
|
||||
Assert.Same(metadata, viewData2.ModelMetadata);
|
||||
Assert.Same(viewData1.ModelMetadata, viewData2.ModelMetadata);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -326,11 +318,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var metadata = metadataProvider.GetMetadataForType(() => null, sourceType);
|
||||
var source = new ViewDataDictionary(metadataProvider)
|
||||
{
|
||||
ModelMetadata = metadata,
|
||||
};
|
||||
var source = new ViewDataDictionary(metadataProvider);
|
||||
|
||||
// Act
|
||||
var viewData1 = new ViewDataDictionary(source)
|
||||
|
|
@ -342,33 +330,84 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
// Assert
|
||||
Assert.NotNull(viewData1.ModelMetadata);
|
||||
Assert.Equal(expectedType, viewData1.ModelMetadata.ModelType);
|
||||
Assert.Equal(expectedType, viewData1.ModelMetadata.RealModelType);
|
||||
|
||||
Assert.NotNull(viewData2.ModelMetadata);
|
||||
Assert.Equal(expectedType, viewData2.ModelMetadata.ModelType);
|
||||
Assert.Equal(expectedType, viewData2.ModelMetadata.RealModelType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelSetter_UpdatesModelMetadata()
|
||||
public void ModelSetter_SameType_UpdatesModelExplorer()
|
||||
{
|
||||
// Arrange
|
||||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var viewData = new ViewDataDictionary(metadataProvider)
|
||||
{
|
||||
Model = "same-string",
|
||||
Model = 3,
|
||||
};
|
||||
|
||||
var originalMetadata = viewData.ModelMetadata;
|
||||
var originalExplorer = viewData.ModelExplorer;
|
||||
|
||||
// Act
|
||||
viewData.Model = "same-string";
|
||||
viewData.Model = 5;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(viewData.ModelMetadata);
|
||||
Assert.Equal("same-string", viewData.Model);
|
||||
Assert.Equal("same-string", viewData.ModelMetadata.Model);
|
||||
Assert.Same(originalMetadata.ModelType, viewData.ModelMetadata.ModelType);
|
||||
Assert.NotSame(originalMetadata, viewData.ModelMetadata);
|
||||
Assert.NotNull(viewData.ModelExplorer);
|
||||
Assert.Equal(5, viewData.Model);
|
||||
Assert.Equal(5, viewData.ModelExplorer.Model);
|
||||
Assert.Same(originalMetadata, viewData.ModelMetadata);
|
||||
Assert.NotSame(originalExplorer, viewData.ModelExplorer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelSetter_SameType_BoxedValueTypeUpdatesModelExplorer()
|
||||
{
|
||||
// Arrange
|
||||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var viewData = new ViewDataDictionary(metadataProvider)
|
||||
{
|
||||
Model = 3,
|
||||
};
|
||||
|
||||
var originalMetadata = viewData.ModelMetadata;
|
||||
var originalExplorer = viewData.ModelExplorer;
|
||||
|
||||
// Act
|
||||
viewData.Model = 3; // This is the same value, but it's in a different box.
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(viewData.ModelMetadata);
|
||||
Assert.NotNull(viewData.ModelExplorer);
|
||||
Assert.Equal(3, viewData.Model);
|
||||
Assert.Equal(3, viewData.ModelExplorer.Model);
|
||||
Assert.Same(originalMetadata, viewData.ModelMetadata);
|
||||
Assert.NotSame(originalExplorer, viewData.ModelExplorer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelSetter_SameModel_NoChanges()
|
||||
{
|
||||
// Arrange
|
||||
var model = "Hello";
|
||||
|
||||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var viewData = new ViewDataDictionary(metadataProvider)
|
||||
{
|
||||
Model = model,
|
||||
};
|
||||
|
||||
var originalMetadata = viewData.ModelMetadata;
|
||||
var originalExplorer = viewData.ModelExplorer;
|
||||
|
||||
// Act
|
||||
viewData.Model = model;
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(viewData.ModelMetadata);
|
||||
Assert.Equal("Hello", viewData.Model);
|
||||
Assert.Same(originalMetadata, viewData.ModelMetadata);
|
||||
Assert.Same(originalExplorer, viewData.ModelExplorer);
|
||||
}
|
||||
|
||||
public static TheoryData<object, string, object> Eval_EvaluatesExpressionsData
|
||||
|
|
|
|||
|
|
@ -1354,7 +1354,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
|
||||
};
|
||||
var url = "http://localhost/dealers/43/update-vehicle?dealer.name=TestCarDealer&dealer.location=NE";
|
||||
|
||||
|
||||
// Act
|
||||
var response = await client.PostAsJsonAsync(url, postedContent);
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
ModelBindingContext bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, typeof(int[])),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(typeof(int[])),
|
||||
ModelName = "someName",
|
||||
ValueProvider = valueProvider,
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, modelType),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(modelType),
|
||||
ModelName = "someName",
|
||||
ValueProvider = Mock.Of<IValueProvider>(),
|
||||
ModelState = new ModelStateDictionary(),
|
||||
|
|
|
|||
|
|
@ -36,9 +36,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var context = new ModelBindingContext();
|
||||
context.ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(
|
||||
modelAccessor: null,
|
||||
modelType: typeof(string));
|
||||
context.ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(string));
|
||||
|
||||
var binder = new TestableBindingSourceModelBinder(BindingSource.Body);
|
||||
|
||||
|
|
@ -55,9 +53,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var context = new ModelBindingContext();
|
||||
context.ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(
|
||||
modelAccessor: null,
|
||||
modelType: typeof(string));
|
||||
context.ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(string));
|
||||
|
||||
context.ModelMetadata.BinderMetadata = new ModelBinderAttribute()
|
||||
{
|
||||
|
|
@ -79,9 +75,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var context = new ModelBindingContext();
|
||||
context.ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(
|
||||
modelAccessor: null,
|
||||
modelType: typeof(string));
|
||||
context.ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(string));
|
||||
|
||||
context.ModelMetadata.BinderMetadata = new ModelBinderAttribute()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, modelType),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(modelType),
|
||||
ModelName = "foo",
|
||||
ValueProvider = valueProvider,
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
ModelBindingContext bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, modelType),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(modelType),
|
||||
ModelName = "someName",
|
||||
ValueProvider = new SimpleHttpValueProvider(),
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
|
|
|
|||
|
|
@ -103,8 +103,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
// Arrange
|
||||
var binder = new CollectionModelBinder<int>();
|
||||
|
||||
var context = new ModelBindingContext()
|
||||
{
|
||||
OperationBindingContext = new OperationBindingContext()
|
||||
{
|
||||
MetadataProvider = new DataAnnotationsModelMetadataProvider(),
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
var boundCollection = await binder.BindSimpleCollection(bindingContext: null, rawValue: new object[0], culture: null);
|
||||
var boundCollection = await binder.BindSimpleCollection(context, rawValue: new object[0], culture: null);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(boundCollection);
|
||||
|
|
@ -153,7 +161,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, typeof(int)),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(typeof(int)),
|
||||
ModelName = "someName",
|
||||
ValueProvider = valueProvider,
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
|
||||
private static ModelMetadata GetModelMetadata()
|
||||
{
|
||||
return new ModelMetadata(new EmptyModelMetadataProvider(), typeof(object), null, typeof(object), "PropertyName");
|
||||
return new ModelMetadata(new EmptyModelMetadataProvider(), typeof(object), typeof(object), "PropertyName");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
FallbackToEmptyPrefix = true,
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(int)),
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int)),
|
||||
ModelName = "someName",
|
||||
ModelState = new ModelStateDictionary(),
|
||||
ValueProvider = new SimpleHttpValueProvider
|
||||
|
|
@ -68,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
FallbackToEmptyPrefix = true,
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(List<int>)),
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
|
||||
ModelName = "someName",
|
||||
ModelState = new ModelStateDictionary(),
|
||||
ValueProvider = new SimpleHttpValueProvider
|
||||
|
|
@ -119,7 +119,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
FallbackToEmptyPrefix = true,
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(List<int>)),
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
|
||||
ModelName = "someName",
|
||||
ModelState = new ModelStateDictionary(),
|
||||
ValueProvider = new SimpleHttpValueProvider
|
||||
|
|
@ -157,7 +157,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
FallbackToEmptyPrefix = true,
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(List<int>)),
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
|
||||
ModelName = "someName",
|
||||
ModelState = new ModelStateDictionary(),
|
||||
ValueProvider = new SimpleHttpValueProvider
|
||||
|
|
@ -201,7 +201,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
FallbackToEmptyPrefix = false,
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(List<int>)),
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(List<int>)),
|
||||
};
|
||||
|
||||
// Act
|
||||
|
|
@ -223,7 +223,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
FallbackToEmptyPrefix = true,
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(int)),
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int)),
|
||||
ModelState = new ModelStateDictionary(),
|
||||
OperationBindingContext = Mock.Of<OperationBindingContext>(),
|
||||
};
|
||||
|
|
@ -275,6 +275,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
{ "friends[1].lastName", "name"},
|
||||
{ "resume", "4+mFeTp3tPF=" }
|
||||
};
|
||||
|
||||
var bindingContext = CreateBindingContext(binder, valueProvider, typeof(Person));
|
||||
|
||||
// Act
|
||||
|
|
@ -305,7 +306,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
FallbackToEmptyPrefix = true,
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, type),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(type),
|
||||
ModelState = new ModelStateDictionary(),
|
||||
ValueProvider = valueProvider,
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
ModelBindingContext bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, typeof(IDictionary<int, string>)),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(typeof(IDictionary<int, string>)),
|
||||
ModelName = "someName",
|
||||
ValueProvider = new SimpleHttpValueProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, modelType),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(modelType),
|
||||
ModelName = "file",
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
{
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, modelType),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(modelType),
|
||||
ModelName = "file",
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
{
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var metadataProvider = new EmptyModelMetadataProvider();
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(null, modelType),
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(modelType),
|
||||
ModelName = "modelName",
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
{
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var metataProvider = new EmptyModelMetadataProvider();
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metataProvider.GetMetadataForType(null, keyValuePairType ?? typeof(KeyValuePair<int, string>)),
|
||||
ModelMetadata = metataProvider.GetMetadataForType(keyValuePairType ?? typeof(KeyValuePair<int, string>)),
|
||||
ModelName = "someName",
|
||||
ValueProvider = valueProvider,
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||
|
|
@ -15,13 +13,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
// Arrange
|
||||
var originalBindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(object)),
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
|
||||
ModelName = "theName",
|
||||
ModelState = new ModelStateDictionary(),
|
||||
ValueProvider = new SimpleHttpValueProvider()
|
||||
};
|
||||
|
||||
var newModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(object));
|
||||
var newModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(object));
|
||||
|
||||
// Act
|
||||
var newBindingContext = new ModelBindingContext(originalBindingContext, string.Empty, newModelMetadata);
|
||||
|
|
@ -39,7 +37,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
// Act
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => 42, typeof(int))
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int))
|
||||
};
|
||||
|
||||
// Assert
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var mockDtoBinder = new Mock<IModelBinder>();
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = GetMetadataForObject(new Person()),
|
||||
ModelMetadata = GetMetadataForType(typeof(Person)),
|
||||
ModelName = "someName",
|
||||
ValueProvider = mockValueProvider.Object,
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
|
|
@ -359,12 +359,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
.Returns((ModelBindingContext mbc) =>
|
||||
{
|
||||
// just return the DTO unchanged
|
||||
return Task.FromResult(new ModelBindingResult(mbc.ModelMetadata.Model, mbc.ModelName, true));
|
||||
return Task.FromResult(new ModelBindingResult(mbc.Model, mbc.ModelName, true));
|
||||
});
|
||||
|
||||
var model = new Person();
|
||||
|
||||
var testableBinder = new Mock<TestableMutableObjectModelBinder> { CallBase = true };
|
||||
testableBinder.Setup(o => o.EnsureModelPublic(bindingContext)).Verifiable();
|
||||
testableBinder.Setup(o => o.GetMetadataForProperties(bindingContext))
|
||||
testableBinder
|
||||
.Setup(o => o.EnsureModelPublic(bindingContext))
|
||||
.Callback<ModelBindingContext>(c => c.Model = model)
|
||||
.Verifiable();
|
||||
testableBinder
|
||||
.Setup(o => o.GetMetadataForProperties(bindingContext))
|
||||
.Returns(new ModelMetadata[0]);
|
||||
|
||||
// Act
|
||||
|
|
@ -373,7 +379,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Assert
|
||||
Assert.NotNull(retValue);
|
||||
Assert.True(retValue.IsModelSet);
|
||||
Assert.NotNull(retValue.Model);
|
||||
Assert.Same(model, retValue.Model);
|
||||
Assert.IsType<Person>(retValue.Model);
|
||||
testableBinder.Verify();
|
||||
}
|
||||
|
|
@ -389,7 +395,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var mockDtoBinder = new Mock<IModelBinder>();
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = GetMetadataForObject(new Person()),
|
||||
ModelMetadata = GetMetadataForType(typeof(Person)),
|
||||
ModelName = "",
|
||||
ValueProvider = mockValueProvider.Object,
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
|
|
@ -405,13 +411,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
.Returns((ModelBindingContext mbc) =>
|
||||
{
|
||||
// just return the DTO unchanged
|
||||
return Task.FromResult(new ModelBindingResult(mbc.ModelMetadata.Model, mbc.ModelName, true));
|
||||
return Task.FromResult(new ModelBindingResult(mbc.Model, mbc.ModelName, true));
|
||||
});
|
||||
|
||||
var model = new Person();
|
||||
|
||||
var testableBinder = new Mock<TestableMutableObjectModelBinder> { CallBase = true };
|
||||
testableBinder.Setup(o => o.EnsureModelPublic(bindingContext)).Verifiable();
|
||||
testableBinder.Setup(o => o.GetMetadataForProperties(bindingContext))
|
||||
.Returns(new ModelMetadata[0]);
|
||||
testableBinder
|
||||
.Setup(o => o.EnsureModelPublic(bindingContext))
|
||||
.Callback<ModelBindingContext>(c => c.Model = model)
|
||||
.Verifiable();
|
||||
|
||||
testableBinder
|
||||
.Setup(o => o.GetMetadataForProperties(bindingContext))
|
||||
.Returns(new ModelMetadata[0]);
|
||||
|
||||
// Act
|
||||
var retValue = await testableBinder.Object.BindModelAsync(bindingContext);
|
||||
|
|
@ -419,7 +432,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Assert
|
||||
Assert.NotNull(retValue);
|
||||
Assert.True(retValue.IsModelSet);
|
||||
Assert.NotNull(retValue.Model);
|
||||
Assert.Same(model, retValue.Model);
|
||||
Assert.IsType<Person>(retValue.Model);
|
||||
testableBinder.Verify();
|
||||
}
|
||||
|
|
@ -513,18 +526,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Arrange
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = GetMetadataForObject(new Person())
|
||||
Model = new Person(),
|
||||
ModelMetadata = GetMetadataForType(typeof(Person))
|
||||
};
|
||||
|
||||
var testableBinder = new Mock<TestableMutableObjectModelBinder> { CallBase = true };
|
||||
|
||||
// Act
|
||||
var originalModel = bindingContext.ModelMetadata.Model;
|
||||
var originalModel = bindingContext.Model;
|
||||
testableBinder.Object.EnsureModelPublic(bindingContext);
|
||||
var newModel = bindingContext.ModelMetadata.Model;
|
||||
|
||||
// Assert
|
||||
Assert.Same(originalModel, newModel);
|
||||
Assert.Same(originalModel, bindingContext.Model);
|
||||
testableBinder.Verify(o => o.CreateModelPublic(bindingContext), Times.Never());
|
||||
}
|
||||
|
||||
|
|
@ -542,9 +555,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
.Returns(new Person()).Verifiable();
|
||||
|
||||
// Act
|
||||
var originalModel = bindingContext.ModelMetadata.Model;
|
||||
var originalModel = bindingContext.Model;
|
||||
testableBinder.Object.EnsureModelPublic(bindingContext);
|
||||
var newModel = bindingContext.ModelMetadata.Model;
|
||||
var newModel = bindingContext.Model;
|
||||
|
||||
// Assert
|
||||
Assert.Null(originalModel);
|
||||
|
|
@ -672,7 +685,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Arrange
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = GetMetadataForObject(new ModelWithMixedBindingBehaviors()),
|
||||
ModelMetadata = GetMetadataForType(typeof(ModelWithMixedBindingBehaviors)),
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
{
|
||||
ValidatorProvider = Mock.Of<IModelValidatorProvider>()
|
||||
|
|
@ -698,13 +711,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Age = -20
|
||||
};
|
||||
|
||||
var containerMetadata = GetMetadataForObject(model);
|
||||
var containerMetadata = GetMetadataForType(model.GetType());
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
Model = model,
|
||||
ModelMetadata = containerMetadata,
|
||||
ModelName = "theModel",
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
{
|
||||
MetadataProvider = new DataAnnotationsModelMetadataProvider(),
|
||||
ValidatorProvider = Mock.Of<IModelValidatorProvider>()
|
||||
}
|
||||
};
|
||||
|
|
@ -746,23 +761,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Age = -20
|
||||
};
|
||||
|
||||
var containerMetadata = GetMetadataForObject(model);
|
||||
var containerMetadata = GetMetadataForType(model.GetType());
|
||||
var bindingContext = new ModelBindingContext()
|
||||
{
|
||||
Model = model,
|
||||
ModelMetadata = containerMetadata,
|
||||
ModelName = "theModel",
|
||||
ModelState = new ModelStateDictionary(),
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
{
|
||||
MetadataProvider = new DataAnnotationsModelMetadataProvider(),
|
||||
ValidatorProvider = Mock.Of<IModelValidatorProvider>()
|
||||
}
|
||||
};
|
||||
var validationContext = new ModelValidationContext("theModel",
|
||||
bindingContext.OperationBindingContext
|
||||
.ValidatorProvider,
|
||||
bindingContext.ModelState,
|
||||
containerMetadata,
|
||||
null);
|
||||
|
||||
var dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
|
||||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
|
@ -806,8 +817,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var model = new ModelWithRequired();
|
||||
var containerMetadata = GetMetadataForObject(model);
|
||||
var bindingContext = CreateContext(containerMetadata);
|
||||
var containerMetadata = GetMetadataForType(model.GetType());
|
||||
|
||||
var bindingContext = CreateContext(containerMetadata, model);
|
||||
|
||||
// Set no properties though Age (a non-Nullable struct) and City (a class) properties are required.
|
||||
var dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
|
||||
|
|
@ -847,8 +859,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var model = new ModelWithRequired();
|
||||
var containerMetadata = GetMetadataForObject(model);
|
||||
var bindingContext = CreateContext(containerMetadata);
|
||||
var containerMetadata = GetMetadataForType(model.GetType());
|
||||
var bindingContext = CreateContext(containerMetadata, model);
|
||||
|
||||
var dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
|
||||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
|
@ -890,8 +902,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var model = new Person();
|
||||
var containerMetadata = GetMetadataForObject(model);
|
||||
var bindingContext = CreateContext(containerMetadata);
|
||||
var containerMetadata = GetMetadataForType(model.GetType());
|
||||
var bindingContext = CreateContext(containerMetadata, model);
|
||||
|
||||
// Set no properties though ValueTypeRequired (a non-Nullable struct) property is required.
|
||||
var dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
|
||||
|
|
@ -920,9 +932,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var model = new Person();
|
||||
var containerMetadata = GetMetadataForObject(model);
|
||||
var containerMetadata = GetMetadataForType(model.GetType());
|
||||
|
||||
var bindingContext = CreateContext(containerMetadata);
|
||||
var bindingContext = CreateContext(containerMetadata, model);
|
||||
|
||||
var dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
|
||||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
|
@ -961,9 +973,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
DateOfBirth = dob
|
||||
};
|
||||
var containerMetadata = GetMetadataForObject(model);
|
||||
var containerMetadata = GetMetadataForType(model.GetType());
|
||||
|
||||
var bindingContext = CreateContext(containerMetadata);
|
||||
var bindingContext = CreateContext(containerMetadata, model);
|
||||
var dto = new ComplexModelDto(containerMetadata, containerMetadata.Properties);
|
||||
|
||||
var firstNameProperty = dto.PropertyMetadata.Single(o => o.PropertyName == "FirstName");
|
||||
|
|
@ -997,9 +1009,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void SetProperty_PropertyHasDefaultValue_SetsDefaultValue()
|
||||
{
|
||||
// Arrange
|
||||
var bindingContext = CreateContext(GetMetadataForObject(new Person()));
|
||||
var model = new Person();
|
||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties.First(o => o.PropertyName == "PropertyWithDefaultValue");
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model);
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties["PropertyWithDefaultValue"];
|
||||
|
||||
var dtoResult = new ModelBindingResult(
|
||||
model: null,
|
||||
|
|
@ -1014,10 +1029,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
||||
// Act
|
||||
testableBinder.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
|
||||
testableBinder.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator);
|
||||
|
||||
// Assert
|
||||
var person = Assert.IsType<Person>(bindingContext.ModelMetadata.Model);
|
||||
var person = Assert.IsType<Person>(bindingContext.Model);
|
||||
Assert.Equal(123.456m, person.PropertyWithDefaultValue);
|
||||
Assert.True(bindingContext.ModelState.IsValid);
|
||||
}
|
||||
|
|
@ -1026,10 +1046,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void SetProperty_PropertyIsPreinitialized_NoValue_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var bindingContext = CreateContext(GetMetadataForObject(new Person()));
|
||||
var model = new Person();
|
||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(
|
||||
o => o.PropertyName == "PropertyWithInitializedValue");
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model);
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties["PropertyWithInitializedValue"];
|
||||
|
||||
// This value won't be used because IsModelBound = false.
|
||||
var dtoResult = new ModelBindingResult(
|
||||
|
|
@ -1040,10 +1062,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
||||
// Act
|
||||
testableBinder.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator: null);
|
||||
testableBinder.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator: null);
|
||||
|
||||
// Assert
|
||||
var person = Assert.IsType<Person>(bindingContext.ModelMetadata.Model);
|
||||
var person = Assert.IsType<Person>(bindingContext.Model);
|
||||
Assert.Equal("preinitialized", person.PropertyWithInitializedValue);
|
||||
Assert.True(bindingContext.ModelState.IsValid);
|
||||
}
|
||||
|
|
@ -1052,10 +1079,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void SetProperty_PropertyIsPreinitialized_WithDefaultValue_NoValue_CallsSetter()
|
||||
{
|
||||
// Arrange
|
||||
var bindingContext = CreateContext(GetMetadataForObject(new Person()));
|
||||
var model = new Person();
|
||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(
|
||||
o => o.PropertyName == "PropertyWithInitializedValueAndDefault");
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model);
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties["PropertyWithInitializedValueAndDefault"];
|
||||
|
||||
// This value won't be used because IsModelBound = false.
|
||||
var dtoResult = new ModelBindingResult(
|
||||
|
|
@ -1066,10 +1095,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
||||
// Act
|
||||
testableBinder.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator: null);
|
||||
testableBinder.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator: null);
|
||||
|
||||
// Assert
|
||||
var person = Assert.IsType<Person>(bindingContext.ModelMetadata.Model);
|
||||
var person = Assert.IsType<Person>(bindingContext.Model);
|
||||
Assert.Equal("default", person.PropertyWithInitializedValueAndDefault);
|
||||
Assert.True(bindingContext.ModelState.IsValid);
|
||||
}
|
||||
|
|
@ -1078,8 +1112,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void SetProperty_PropertyIsReadOnly_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var bindingContext = CreateContext(GetMetadataForObject(new Person()));
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "NonUpdateableProperty");
|
||||
var model = new Person();
|
||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model);
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties["NonUpdateableProperty"];
|
||||
|
||||
var dtoResult = new ModelBindingResult(
|
||||
model: null,
|
||||
|
|
@ -1089,7 +1127,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
||||
// Act
|
||||
testableBinder.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator: null);
|
||||
testableBinder.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator: null);
|
||||
|
||||
// Assert
|
||||
// If didn't throw, success!
|
||||
|
|
@ -1100,26 +1143,32 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var model = new Person();
|
||||
var bindingContext = CreateContext(GetMetadataForObject(model));
|
||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model);
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties["DateOfBirth"];
|
||||
|
||||
var dtoResult = new ModelBindingResult(
|
||||
new DateTime(2001, 1, 1),
|
||||
key: "foo",
|
||||
isModelSet: true);
|
||||
|
||||
|
||||
|
||||
var requiredValidator = bindingContext.OperationBindingContext
|
||||
.ValidatorProvider
|
||||
.GetValidators(propertyMetadata)
|
||||
.FirstOrDefault(v => v.IsRequired);
|
||||
var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);
|
||||
|
||||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
||||
// Act
|
||||
testableBinder.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
|
||||
testableBinder.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator);
|
||||
|
||||
// Assert
|
||||
Assert.True(bindingContext.ModelState.IsValid);
|
||||
|
|
@ -1135,9 +1184,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
DateOfBirth = new DateTime(1900, 1, 1)
|
||||
};
|
||||
var bindingContext = CreateContext(GetMetadataForObject(model));
|
||||
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfDeath");
|
||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model);
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties["DateOfDeath"];
|
||||
|
||||
var dtoResult = new ModelBindingResult(
|
||||
new DateTime(1800, 1, 1),
|
||||
isModelSet: true,
|
||||
|
|
@ -1146,7 +1199,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
||||
// Act
|
||||
testableBinder.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator: null);
|
||||
testableBinder.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Date of death can't be before date of birth." + Environment.NewLine
|
||||
|
|
@ -1158,21 +1216,29 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorNotPresent_RegistersValidationCallback()
|
||||
{
|
||||
// Arrange
|
||||
var bindingContext = CreateContext(GetMetadataForObject(new Person()));
|
||||
var model = new Person();
|
||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model);
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties["DateOfBirth"];
|
||||
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
|
||||
var dtoResult = new ModelBindingResult(
|
||||
model: null,
|
||||
isModelSet: true,
|
||||
key: "foo");
|
||||
|
||||
var requiredValidator = GetRequiredValidator(bindingContext, propertyMetadata);
|
||||
var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);
|
||||
|
||||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
||||
// Act
|
||||
testableBinder.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
|
||||
testableBinder.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator);
|
||||
|
||||
// Assert
|
||||
Assert.False(bindingContext.ModelState.IsValid);
|
||||
|
|
@ -1182,10 +1248,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorPresent_AddsModelError()
|
||||
{
|
||||
// Arrange
|
||||
var bindingContext = CreateContext(GetMetadataForObject(new Person()));
|
||||
var model = new Person();
|
||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||
bindingContext.ModelName = " foo";
|
||||
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "ValueTypeRequired");
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model);
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties["ValueTypeRequired"];
|
||||
|
||||
var dtoResult = new ModelBindingResult(
|
||||
model: null,
|
||||
isModelSet: true,
|
||||
|
|
@ -1196,7 +1266,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
||||
// Act
|
||||
testableBinder.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
|
||||
testableBinder.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator);
|
||||
|
||||
// Assert
|
||||
Assert.False(bindingContext.ModelState.IsValid);
|
||||
|
|
@ -1208,10 +1283,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void SetProperty_SettingNullableTypeToNull_RequiredValidatorNotPresent_PropertySetterThrows_AddsRequiredMessageString()
|
||||
{
|
||||
// Arrange
|
||||
var bindingContext = CreateContext(GetMetadataForObject(new ModelWhosePropertySetterThrows()));
|
||||
var model = new ModelWhosePropertySetterThrows();
|
||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||
bindingContext.ModelName = "foo";
|
||||
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "NameNoAttribute");
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model);
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties["NameNoAttribute"];
|
||||
|
||||
var dtoResult = new ModelBindingResult(
|
||||
model: null,
|
||||
isModelSet: true,
|
||||
|
|
@ -1222,7 +1301,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
||||
// Act
|
||||
testableBinder.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
|
||||
testableBinder.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator);
|
||||
|
||||
// Assert
|
||||
Assert.False(bindingContext.ModelState.IsValid);
|
||||
|
|
@ -1236,11 +1320,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void SetProperty_SettingNullableTypeToNull_RequiredValidatorPresent_PropertySetterThrows_AddsRequiredMessageString()
|
||||
{
|
||||
// Arrange
|
||||
var bindingContext = CreateContext(GetMetadataForObject(new ModelWhosePropertySetterThrows()));
|
||||
var model = new ModelWhosePropertySetterThrows();
|
||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||
bindingContext.ModelName = "foo";
|
||||
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "Name");
|
||||
var dtoResult = new ModelBindingResult(model: null,
|
||||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var modelExplorer = metadataProvider.GetModelExplorerForType(typeof(Person), model);
|
||||
var propertyMetadata = bindingContext.ModelMetadata.Properties["Name"];
|
||||
|
||||
var dtoResult = new ModelBindingResult(
|
||||
model: null,
|
||||
isModelSet: true,
|
||||
key: "foo.Name");
|
||||
|
||||
|
|
@ -1249,7 +1338,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var testableBinder = new TestableMutableObjectModelBinder();
|
||||
|
||||
// Act
|
||||
testableBinder.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
|
||||
testableBinder.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator);
|
||||
|
||||
// Assert
|
||||
Assert.False(bindingContext.ModelState.IsValid);
|
||||
|
|
@ -1257,7 +1351,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.Equal("This message comes from the [Required] attribute.", error.ErrorMessage);
|
||||
}
|
||||
|
||||
private static ModelBindingContext CreateContext(ModelMetadata metadata)
|
||||
private static ModelBindingContext CreateContext(ModelMetadata metadata, object model)
|
||||
{
|
||||
var providers = new IModelValidatorProvider[]
|
||||
{
|
||||
|
|
@ -1267,11 +1361,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
return new ModelBindingContext
|
||||
{
|
||||
Model = model,
|
||||
ModelState = new ModelStateDictionary(),
|
||||
ModelMetadata = metadata,
|
||||
ModelName = "theModel",
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
{
|
||||
MetadataProvider = new DataAnnotationsModelMetadataProvider(),
|
||||
ValidatorProvider = new CompositeModelValidatorProvider(providers)
|
||||
}
|
||||
};
|
||||
|
|
@ -1288,26 +1384,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private static ModelMetadata GetMetadataForCanUpdateProperty(string propertyName)
|
||||
{
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
return metadataProvider.GetMetadataForProperty(null, typeof(MyModelTestingCanUpdateProperty), propertyName);
|
||||
}
|
||||
|
||||
private static ModelMetadata GetMetadataForObject(object o)
|
||||
{
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
return metadataProvider.GetMetadataForType(() => o, o.GetType());
|
||||
return metadataProvider.GetMetadataForProperty(typeof(MyModelTestingCanUpdateProperty), propertyName);
|
||||
}
|
||||
|
||||
private static ModelMetadata GetMetadataForType(Type t)
|
||||
{
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
return metadataProvider.GetMetadataForType(null, t);
|
||||
return metadataProvider.GetMetadataForType(t);
|
||||
}
|
||||
|
||||
private static ModelMetadata GetMetadataForParameter(MethodInfo methodInfo, string parameterName)
|
||||
{
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
return metadataProvider.GetMetadataForParameter(
|
||||
modelAccessor: null,
|
||||
methodInfo: methodInfo,
|
||||
parameterName: parameterName);
|
||||
}
|
||||
|
|
@ -1548,12 +1637,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return base.GetMetadataForProperties(bindingContext);
|
||||
}
|
||||
|
||||
public new void SetProperty(ModelBindingContext bindingContext,
|
||||
ModelMetadata propertyMetadata,
|
||||
ModelBindingResult dtoResult,
|
||||
IModelValidator requiredValidator)
|
||||
public new void SetProperty(
|
||||
ModelBindingContext bindingContext,
|
||||
ModelExplorer modelExplorer,
|
||||
ModelMetadata propertyMetadata,
|
||||
ModelBindingResult dtoResult,
|
||||
IModelValidator requiredValidator)
|
||||
{
|
||||
base.SetProperty(bindingContext, propertyMetadata, dtoResult, requiredValidator);
|
||||
base.SetProperty(
|
||||
bindingContext,
|
||||
modelExplorer,
|
||||
propertyMetadata,
|
||||
dtoResult,
|
||||
requiredValidator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
{
|
||||
return new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, modelType),
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(modelType),
|
||||
ModelName = "theModelName",
|
||||
ValueProvider = new SimpleHttpValueProvider() // empty
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Act
|
||||
// Call ToList() to force the lazy evaluation to evaluate
|
||||
provider.GetMetadataForProperties(model, typeof(PropertyModel)).ToList();
|
||||
provider.GetMetadataForProperties(typeof(PropertyModel)).ToList();
|
||||
|
||||
// Assert
|
||||
var local = Assert.Single(
|
||||
|
|
@ -53,18 +53,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void GetMetadataForProperties_ExcludesIndexers()
|
||||
{
|
||||
// Arrange
|
||||
var value = "some value";
|
||||
var model = new ModelWithIndexer { Value = value };
|
||||
var model = new ModelWithIndexer();
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
var modelType = model.GetType();
|
||||
|
||||
// Act
|
||||
provider.GetMetadataForProperties(model, modelType).ToList();
|
||||
provider.GetMetadataForProperties(modelType).ToList();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, provider.CreateMetadataFromPrototypeLog.Count);
|
||||
Assert.Equal(value, provider.CreateMetadataFromPrototypeLog[0].Model);
|
||||
Assert.Null(provider.CreateMetadataFromPrototypeLog[1].Model);
|
||||
|
||||
var valueMetadata = Assert.Single(
|
||||
provider.CreateMetadataPrototypeLog,
|
||||
|
|
@ -78,23 +75,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.Equal(typeof(string), testPropertyMetadata.ModelType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForPropertyWithNullContainerReturnsMetadataWithNullValuesForProperties()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
|
||||
// Act
|
||||
provider.GetMetadataForProperties(null, typeof(PropertyModel)).ToList(); // Call ToList() to force the lazy evaluation to evaluate
|
||||
|
||||
// Assert
|
||||
Assert.NotEmpty(provider.CreateMetadataFromPrototypeLog);
|
||||
foreach (var parms in provider.CreateMetadataFromPrototypeLog)
|
||||
{
|
||||
Assert.Null(parms.Model);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForParameterNullOrEmptyPropertyNameThrows()
|
||||
{
|
||||
|
|
@ -103,56 +83,30 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsArgumentNullOrEmpty(
|
||||
() => provider.GetMetadataForParameter(modelAccessor: null, methodInfo: null, parameterName: null),
|
||||
() => provider.GetMetadataForParameter(methodInfo: null, parameterName: null),
|
||||
"parameterName");
|
||||
ExceptionAssert.ThrowsArgumentNullOrEmpty(
|
||||
() => provider.GetMetadataForParameter(modelAccessor: null, methodInfo: null, parameterName: null),
|
||||
() => provider.GetMetadataForParameter(methodInfo: null, parameterName: null),
|
||||
"parameterName");
|
||||
}
|
||||
|
||||
// GetMetadataForProperty
|
||||
// GetMetadata and access metadata for a property
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForPropertyNullOrEmptyPropertyNameThrows()
|
||||
public void GetMetadataForProperty_WithLocalAttributes()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, null, typeof(PropertyModel), null);
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsArgumentNullOrEmpty(
|
||||
() => provider.GetMetadataForProperty(modelAccessor: null, containerType: typeof(object), propertyName: null),
|
||||
"propertyName");
|
||||
ExceptionAssert.ThrowsArgumentNullOrEmpty(
|
||||
() => provider.GetMetadataForProperty(modelAccessor: null, containerType: typeof(object), propertyName: String.Empty),
|
||||
"propertyName");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForPropertyInvalidPropertyNameThrows()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsArgument(
|
||||
() => provider.GetMetadataForProperty(modelAccessor: null, containerType: typeof(object), propertyName: "BadPropertyName"),
|
||||
"propertyName",
|
||||
"The property System.Object.BadPropertyName could not be found.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForPropertyWithLocalAttributes()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(int), "LocalAttributes");
|
||||
provider.CreateMetadataFromPrototypeReturnValue = metadata;
|
||||
var propertyMetadata = new ModelMetadata(provider, typeof(PropertyModel), typeof(int), "LocalAttributes");
|
||||
provider.CreateMetadataFromPrototypeReturnValue = propertyMetadata;
|
||||
|
||||
// Act
|
||||
var result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "LocalAttributes");
|
||||
var result = provider.GetMetadataForProperty(typeof(PropertyModel), "LocalAttributes");
|
||||
|
||||
// Assert
|
||||
Assert.Same(metadata, result);
|
||||
Assert.Same(propertyMetadata, result);
|
||||
var localAttributes = Assert.Single(
|
||||
provider.CreateMetadataPrototypeLog,
|
||||
parameters => parameters.PropertyName == "LocalAttributes");
|
||||
|
|
@ -160,18 +114,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForPropertyWithMetadataAttributes()
|
||||
public void GetMetadataForProperty_WithMetadataAttributes()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(string), "MetadataAttributes");
|
||||
provider.CreateMetadataFromPrototypeReturnValue = metadata;
|
||||
var metadata = new ModelMetadata(provider, null, typeof(PropertyModel), null);
|
||||
|
||||
var propertyMetadata = new ModelMetadata(provider, typeof(PropertyModel), typeof(string), "MetadataAttributes");
|
||||
provider.CreateMetadataFromPrototypeReturnValue = propertyMetadata;
|
||||
|
||||
// Act
|
||||
var result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "MetadataAttributes");
|
||||
var result = metadata.Properties["MetadataAttributes"];
|
||||
|
||||
// Assert
|
||||
Assert.Same(metadata, result);
|
||||
Assert.Same(propertyMetadata, result);
|
||||
var parmaters = Assert.Single(
|
||||
provider.CreateMetadataPrototypeLog,
|
||||
p => p.PropertyName == "MetadataAttributes");
|
||||
|
|
@ -179,18 +135,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForPropertyWithMixedAttributes()
|
||||
public void GetMetadataForProperty_WithMixedAttributes()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, typeof(PropertyModel), null, typeof(double), "MixedAttributes");
|
||||
provider.CreateMetadataFromPrototypeReturnValue = metadata;
|
||||
var metadata = new ModelMetadata(provider, null, typeof(PropertyModel), null);
|
||||
|
||||
var propertyMetadata = new ModelMetadata(provider, typeof(PropertyModel), typeof(double), "MixedAttributes");
|
||||
provider.CreateMetadataFromPrototypeReturnValue = propertyMetadata;
|
||||
|
||||
// Act
|
||||
var result = provider.GetMetadataForProperty(null, typeof(PropertyModel), "MixedAttributes");
|
||||
var result = metadata.Properties["MixedAttributes"];
|
||||
|
||||
// Assert
|
||||
Assert.Same(metadata, result);
|
||||
Assert.Same(propertyMetadata, result);
|
||||
var parms = Assert.Single(provider.CreateMetadataPrototypeLog, p => p.PropertyName == "MixedAttributes");
|
||||
Assert.Single(parms.Attributes, a => a is RequiredAttribute);
|
||||
Assert.Single(parms.Attributes, a => a is RangeAttribute);
|
||||
|
|
@ -203,11 +161,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void GetMetadataForTypeIncludesAttributesOnType()
|
||||
{
|
||||
var provider = new TestableAssociatedMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, null, null, typeof(TypeModel), null);
|
||||
var metadata = new ModelMetadata(provider, null, typeof(TypeModel), null);
|
||||
provider.CreateMetadataFromPrototypeReturnValue = metadata;
|
||||
|
||||
// Act
|
||||
var result = provider.GetMetadataForType(null, typeof(TypeModel));
|
||||
var result = provider.GetMetadataForType(typeof(TypeModel));
|
||||
|
||||
// Assert
|
||||
Assert.Same(metadata, result);
|
||||
|
|
@ -216,23 +174,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
#endif
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForProperties_SetsContainerAsExpected()
|
||||
{
|
||||
// Arrange
|
||||
var model = new PropertyModel { LocalAttributes = 42, MetadataAttributes = "hello", MixedAttributes = 21.12 };
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
|
||||
// Act
|
||||
var metadata = provider.GetMetadataForProperties(model, typeof(PropertyModel)).ToList();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, metadata.Count);
|
||||
Assert.Same(model, metadata[0].Container);
|
||||
Assert.Same(model, metadata[1].Container);
|
||||
Assert.Same(model, metadata[2].Container);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
private class PropertyModel
|
||||
|
|
@ -292,12 +233,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return CreateMetadataPrototypeReturnValue;
|
||||
}
|
||||
|
||||
protected override ModelMetadata CreateMetadataFromPrototype(ModelMetadata prototype, Func<object> modelAccessor)
|
||||
protected override ModelMetadata CreateMetadataFromPrototype(ModelMetadata prototype)
|
||||
{
|
||||
CreateMetadataFromPrototypeLog.Add(new CreateMetadataFromPrototypeParams
|
||||
{
|
||||
Prototype = prototype,
|
||||
Model = modelAccessor == null ? null : modelAccessor()
|
||||
});
|
||||
|
||||
return CreateMetadataFromPrototypeReturnValue;
|
||||
|
|
@ -315,7 +255,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private class CreateMetadataFromPrototypeParams
|
||||
{
|
||||
public ModelMetadata Prototype { get; set; }
|
||||
public object Model { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var expected = new[] { "IsAdmin", "UserName" };
|
||||
|
||||
// Act
|
||||
var metadata = provider.GetMetadataForType(null, type);
|
||||
var metadata = provider.GetMetadataForType(type);
|
||||
|
||||
// Assert
|
||||
var predicate = metadata.PropertyBindingPredicateProvider.PropertyFilter;
|
||||
|
|
@ -59,7 +59,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Act
|
||||
var metadata = provider.GetMetadataForParameter(
|
||||
modelAccessor: null,
|
||||
methodInfo: methodInfo,
|
||||
parameterName: "param");
|
||||
|
||||
|
|
@ -97,7 +96,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Act
|
||||
var metadata = provider.GetMetadataForParameter(
|
||||
modelAccessor: null,
|
||||
methodInfo: methodInfo,
|
||||
parameterName: "param");
|
||||
|
||||
|
|
@ -130,7 +128,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Act
|
||||
var metadata = provider.GetMetadataForParameter(
|
||||
modelAccessor: null,
|
||||
methodInfo: methodInfo,
|
||||
parameterName: "param");
|
||||
|
||||
|
|
@ -146,7 +143,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
|
||||
// Act
|
||||
var metadata = provider.GetMetadataForType(null, type);
|
||||
var metadata = provider.GetMetadataForType(type);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("TypePrefix", metadata.BinderModelName);
|
||||
|
|
@ -161,9 +158,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
|
||||
// Act & Assert
|
||||
Assert.True(provider.GetMetadataForProperty(null, type, "NoAttribute").ShowForDisplay);
|
||||
Assert.True(provider.GetMetadataForProperty(null, type, "ScaffoldColumnTrue").ShowForDisplay);
|
||||
Assert.False(provider.GetMetadataForProperty(null, type, "ScaffoldColumnFalse").ShowForDisplay);
|
||||
Assert.True(provider.GetMetadataForProperty(type, "NoAttribute").ShowForDisplay);
|
||||
Assert.True(provider.GetMetadataForProperty(type, "ScaffoldColumnTrue").ShowForDisplay);
|
||||
Assert.False(provider.GetMetadataForProperty(type, "ScaffoldColumnFalse").ShowForDisplay);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -174,9 +171,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
|
||||
// Act & Assert
|
||||
Assert.True(provider.GetMetadataForProperty(null, type, "NoAttribute").ShowForEdit);
|
||||
Assert.True(provider.GetMetadataForProperty(null, type, "ScaffoldColumnTrue").ShowForEdit);
|
||||
Assert.False(provider.GetMetadataForProperty(null, type, "ScaffoldColumnFalse").ShowForEdit);
|
||||
Assert.True(provider.GetMetadataForProperty(type, "NoAttribute").ShowForEdit);
|
||||
Assert.True(provider.GetMetadataForProperty(type, "ScaffoldColumnTrue").ShowForEdit);
|
||||
Assert.False(provider.GetMetadataForProperty(type, "ScaffoldColumnFalse").ShowForEdit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -184,7 +181,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForType(modelAccessor: null, modelType: typeof(ClassWithHiddenProperties));
|
||||
var metadata = provider.GetMetadataForType(modelType: typeof(ClassWithHiddenProperties));
|
||||
var property = metadata.Properties["DirectlyHidden"];
|
||||
|
||||
// Act
|
||||
|
|
@ -199,7 +196,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForType(modelAccessor: null, modelType: typeof(ClassWithHiddenProperties));
|
||||
var metadata = provider.GetMetadataForType(typeof(ClassWithHiddenProperties));
|
||||
var property = metadata.Properties["OfHiddenType"];
|
||||
|
||||
// Act
|
||||
|
|
@ -214,7 +211,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForType(modelAccessor: null, modelType: typeof(ClassWithHiddenProperties));
|
||||
var metadata = provider.GetMetadataForType(typeof(ClassWithHiddenProperties));
|
||||
var property = metadata.Properties["DirectlyHidden"];
|
||||
|
||||
// Act
|
||||
|
|
@ -229,7 +226,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForType(modelAccessor: null, modelType: typeof(ClassWithHiddenProperties));
|
||||
var metadata = provider.GetMetadataForType(typeof(ClassWithHiddenProperties));
|
||||
var property = metadata.Properties["OfHiddenType"];
|
||||
|
||||
// Act
|
||||
|
|
@ -246,7 +243,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
|
||||
// Act
|
||||
var propertyMetadata = provider.GetMetadataForProperty(null, typeof(Person), nameof(Person.Parent));
|
||||
var propertyMetadata = provider.GetMetadataForProperty(typeof(Person), nameof(Person.Parent));
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(propertyMetadata.BinderMetadata);
|
||||
|
|
@ -261,7 +258,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
|
||||
// Act
|
||||
var propertyMetadata = provider.GetMetadataForProperty(null, typeof(Person), nameof(Person.GrandParent));
|
||||
var propertyMetadata = provider.GetMetadataForProperty(typeof(Person), nameof(Person.GrandParent));
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(propertyMetadata.BinderMetadata);
|
||||
|
|
@ -277,7 +274,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Act
|
||||
var parameterMetadata = provider.GetMetadataForParameter(
|
||||
null,
|
||||
typeof(Person).GetMethod("Update"),
|
||||
"person");
|
||||
|
||||
|
|
@ -295,7 +291,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Act
|
||||
var parameterMetadata = provider.GetMetadataForParameter(
|
||||
null,
|
||||
typeof(Person).GetMethod("Save"),
|
||||
"person");
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Assert
|
||||
Assert.NotNull(metadata.AdditionalValues);
|
||||
Assert.Empty(metadata.AdditionalValues);
|
||||
Assert.Null(metadata.Container);
|
||||
Assert.Null(metadata.ContainerType);
|
||||
|
||||
Assert.True(metadata.ConvertEmptyStringToNull);
|
||||
|
|
@ -52,12 +51,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.Null(metadata.DisplayName);
|
||||
Assert.Null(metadata.EditFormatString);
|
||||
Assert.Null(metadata.NullDisplayText);
|
||||
Assert.Null(metadata.SimpleDisplayText);
|
||||
Assert.Null(metadata.SimpleDisplayProperty);
|
||||
Assert.Null(metadata.TemplateHint);
|
||||
|
||||
Assert.Null(metadata.Model);
|
||||
Assert.Equal(typeof(object), metadata.ModelType);
|
||||
Assert.Equal(typeof(object), metadata.RealModelType);
|
||||
Assert.Null(metadata.PropertyName);
|
||||
|
||||
Assert.Equal(ModelMetadata.DefaultOrder, metadata.Order);
|
||||
|
|
@ -89,9 +86,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
new DisplayAttribute { Name = "value" }, metadata => metadata.DisplayName
|
||||
},
|
||||
{
|
||||
new DisplayColumnAttribute("Property"), metadata => metadata.SimpleDisplayText
|
||||
},
|
||||
{
|
||||
new DisplayFormatAttribute { DataFormatString = "value" },
|
||||
metadata => metadata.DisplayFormatString
|
||||
|
|
@ -130,10 +124,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
containerType: null,
|
||||
modelType: typeof(ClassWithDisplayableColumn),
|
||||
propertyName: null,
|
||||
attributes: attributes)
|
||||
{
|
||||
Model = new ClassWithDisplayableColumn { Property = "value" },
|
||||
};
|
||||
attributes: attributes);
|
||||
|
||||
// Act
|
||||
var result = accessor(metadata);
|
||||
|
|
@ -142,6 +133,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.Equal("value", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributesOverrideMetadataStrings_SimpleDisplayProperty()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new[] { new DisplayColumnAttribute("Property") };
|
||||
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = new CachedDataAnnotationsModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelType: typeof(ClassWithDisplayableColumn),
|
||||
propertyName: null,
|
||||
attributes: attributes);
|
||||
|
||||
// Act
|
||||
var result = metadata.SimpleDisplayProperty;
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Property", result);
|
||||
}
|
||||
|
||||
public static TheoryData<Attribute, Func<ModelMetadata, bool>, bool> ExpectedAttributeDataBooleans
|
||||
{
|
||||
get
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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 Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class ModelExplorerExtensionsTest
|
||||
{
|
||||
public static TheoryData<object, Type, string> SimpleDisplayTextData
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TheoryData<object, Type, string>
|
||||
{
|
||||
{
|
||||
new ComplexClass()
|
||||
{
|
||||
Prop1 = new Class1 { Prop1 = "Hello" }
|
||||
},
|
||||
typeof(ComplexClass),
|
||||
"Class1"
|
||||
},
|
||||
{
|
||||
new Class1(),
|
||||
typeof(Class1),
|
||||
"Class1"
|
||||
},
|
||||
{
|
||||
new ClassWithNoProperties(),
|
||||
typeof(ClassWithNoProperties),
|
||||
string.Empty
|
||||
},
|
||||
{
|
||||
null,
|
||||
typeof(object),
|
||||
null
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SimpleDisplayTextData))]
|
||||
public void GetSimpleDisplayText_WithoutSimpleDisplayProperty(
|
||||
object model,
|
||||
Type modelType,
|
||||
string expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var modelExplorer = provider.GetModelExplorerForType(modelType, model);
|
||||
|
||||
// Act
|
||||
var result = modelExplorer.GetSimpleDisplayText();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
private class ClassWithNoProperties
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class ComplexClass
|
||||
{
|
||||
public Class1 Prop1 { get; set; }
|
||||
}
|
||||
|
||||
private class Class1
|
||||
{
|
||||
public string Prop1 { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Class1";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class ModelExplorerTest
|
||||
{
|
||||
[Fact]
|
||||
public void ModelType_UsesRuntimeType()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var modelExplorer = provider.GetModelExplorerForType(typeof(BaseClass), new DerivedClass());
|
||||
|
||||
// Act
|
||||
var modelType = modelExplorer.ModelType;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(DerivedClass), modelType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelType_UsesDeclaredType_WhenModelIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var modelExplorer = provider.GetModelExplorerForType(typeof(BaseClass), model: null);
|
||||
|
||||
// Act
|
||||
var modelType = modelExplorer.ModelType;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(typeof(BaseClass), modelType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Properties_UsesRuntimeType()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var modelExplorer = provider.GetModelExplorerForType(typeof(BaseClass), new DerivedClass());
|
||||
|
||||
// Act
|
||||
var properties = modelExplorer.Properties.ToArray();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, properties.Length);
|
||||
|
||||
var baseProperty = Assert.Single(properties, p => p.Metadata.PropertyName == "Base1");
|
||||
Assert.Equal(typeof(int), baseProperty.Metadata.ModelType);
|
||||
Assert.Equal(typeof(DerivedClass), baseProperty.Metadata.ContainerType);
|
||||
Assert.Same(modelExplorer, baseProperty.Container);
|
||||
|
||||
var derivedProperty = Assert.Single(properties, p => p.Metadata.PropertyName == "Derived1");
|
||||
Assert.Equal(typeof(string), derivedProperty.Metadata.ModelType);
|
||||
Assert.Equal(typeof(DerivedClass), derivedProperty.Metadata.ContainerType);
|
||||
Assert.Same(modelExplorer, derivedProperty.Container);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Properties_UsesDeclaredType_WhenModelIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var modelExplorer = provider.GetModelExplorerForType(typeof(BaseClass), model: null);
|
||||
|
||||
// Act
|
||||
var properties = modelExplorer.Properties.ToArray();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, properties.Length);
|
||||
|
||||
var baseProperty = Assert.Single(properties, p => p.Metadata.PropertyName == "Base1");
|
||||
Assert.Equal(typeof(int), baseProperty.Metadata.ModelType);
|
||||
Assert.Equal(typeof(BaseClass), baseProperty.Metadata.ContainerType);
|
||||
Assert.Same(modelExplorer, baseProperty.Container);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPropertyExplorer_DeferredModelAccess()
|
||||
{
|
||||
// Arrange
|
||||
var model = new DerivedClass()
|
||||
{
|
||||
Base1 = 5,
|
||||
};
|
||||
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var modelExplorer = provider.GetModelExplorerForType(typeof(BaseClass), model);
|
||||
|
||||
// Change the model value after creating the explorer
|
||||
var propertyExplorer = modelExplorer.GetExplorerForProperty("Base1");
|
||||
model.Base1 = 17;
|
||||
|
||||
// Act
|
||||
var propertyValue = propertyExplorer.Model;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(17, propertyValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPropertyExplorer_DeferredModelAccess_ContainerModelIsNull()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var modelExplorer = provider.GetModelExplorerForType(typeof(BaseClass), model: null);
|
||||
|
||||
var propertyExplorer = modelExplorer.GetExplorerForProperty("Base1");
|
||||
|
||||
// Act
|
||||
var propertyValue = propertyExplorer.Model;
|
||||
|
||||
// Assert
|
||||
Assert.Null(propertyValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPropertyExplorer_ReturnsNull_ForPropertyNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var model = new DerivedClass()
|
||||
{
|
||||
Base1 = 5,
|
||||
};
|
||||
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var modelExplorer = provider.GetModelExplorerForType(typeof(BaseClass), model);
|
||||
|
||||
// Act
|
||||
var propertyExplorer = modelExplorer.GetExplorerForProperty("BadName");
|
||||
|
||||
// Assert
|
||||
Assert.Null(propertyExplorer);
|
||||
}
|
||||
|
||||
private class BaseClass
|
||||
{
|
||||
public int Base1 { get; set; }
|
||||
}
|
||||
|
||||
private class DerivedClass : BaseClass
|
||||
{
|
||||
public string Derived1 { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class ModelMetadataProviderExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void GetMetadataForPropertyInvalidPropertyNameThrows()
|
||||
{
|
||||
// Arrange
|
||||
var provider = (IModelMetadataProvider)new EmptyModelMetadataProvider();
|
||||
|
||||
// Act & Assert
|
||||
ExceptionAssert.ThrowsArgument(
|
||||
() => provider.GetMetadataForProperty(typeof(object), propertyName: "BadPropertyName"),
|
||||
"propertyName",
|
||||
"The property System.Object.BadPropertyName could not be found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -42,13 +42,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{ m => m.DisplayName = "New display name", m => m.DisplayName, "New display name" },
|
||||
{ m => m.EditFormatString = "New edit format", m => m.EditFormatString, "New edit format" },
|
||||
{ m => m.NullDisplayText = "New null display", m => m.NullDisplayText, "New null display" },
|
||||
{ m => m.SimpleDisplayText = "New simple display", m => m.SimpleDisplayText, "New simple display" },
|
||||
{ m => m.SimpleDisplayProperty = "NewSimpleDisplay", m => m.SimpleDisplayProperty, "NewSimpleDisplay" },
|
||||
{ m => m.TemplateHint = "New template hint", m => m.TemplateHint, "New template hint" },
|
||||
|
||||
{ m => m.Order = 23, m => m.Order, 23 },
|
||||
{ m => m.Container = null, m => m.Container, null },
|
||||
{ m => m.Container = emptycontainerModel, m => m.Container, emptycontainerModel },
|
||||
{ m => m.Container = nonEmptycontainerModel, m => m.Container, nonEmptycontainerModel },
|
||||
|
||||
{ m => m.BinderMetadata = null, m => m.BinderMetadata, null },
|
||||
{ m => m.BinderMetadata = binderMetadata, m => m.BinderMetadata, binderMetadata },
|
||||
|
|
@ -72,14 +69,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var provider = new EmptyModelMetadataProvider();
|
||||
|
||||
// Act
|
||||
var metadata =
|
||||
new ModelMetadata(provider, typeof(Exception), () => "model", typeof(string), "propertyName");
|
||||
var metadata = new ModelMetadata(provider, typeof(Exception), typeof(string), "propertyName");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(metadata.AdditionalValues);
|
||||
Assert.Empty(metadata.AdditionalValues);
|
||||
Assert.Equal(typeof(Exception), metadata.ContainerType);
|
||||
Assert.Null(metadata.Container);
|
||||
|
||||
Assert.True(metadata.ConvertEmptyStringToNull);
|
||||
Assert.False(metadata.HasNonDefaultEditFormat);
|
||||
|
|
@ -100,10 +95,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.Null(metadata.EditFormatString);
|
||||
Assert.Null(metadata.NullDisplayText);
|
||||
Assert.Null(metadata.TemplateHint);
|
||||
|
||||
Assert.Equal("model", metadata.Model);
|
||||
Assert.Equal("model", metadata.SimpleDisplayText);
|
||||
Assert.Equal(typeof(string), metadata.RealModelType);
|
||||
Assert.Null(metadata.SimpleDisplayProperty);
|
||||
|
||||
Assert.Equal(typeof(string), metadata.ModelType);
|
||||
Assert.Equal("propertyName", metadata.PropertyName);
|
||||
|
||||
|
|
@ -128,7 +121,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: () => null,
|
||||
modelType: typeof(object),
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -148,7 +140,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: () => null,
|
||||
modelType: typeof(object),
|
||||
propertyName: null);
|
||||
var valuesDictionary = new Dictionary<object, object>
|
||||
|
|
@ -187,7 +178,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var modelMetadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: type,
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -209,7 +199,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var modelMetadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: type,
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -231,7 +220,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var modelMetadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: type,
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -256,7 +244,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var modelMetadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: type,
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -281,10 +268,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var provider = new EmptyModelMetadataProvider();
|
||||
|
||||
// Act & Assert
|
||||
Assert.False(new ModelMetadata(provider, null, null, typeof(string), null).IsNullableValueType);
|
||||
Assert.False(new ModelMetadata(provider, null, null, typeof(IDisposable), null).IsNullableValueType);
|
||||
Assert.True(new ModelMetadata(provider, null, null, typeof(Nullable<int>), null).IsNullableValueType);
|
||||
Assert.False(new ModelMetadata(provider, null, null, typeof(int), null).IsNullableValueType);
|
||||
Assert.False(new ModelMetadata(provider, null, typeof(string), null).IsNullableValueType);
|
||||
Assert.False(new ModelMetadata(provider, null, typeof(IDisposable), null).IsNullableValueType);
|
||||
Assert.True(new ModelMetadata(provider, null, typeof(Nullable<int>), null).IsNullableValueType);
|
||||
Assert.False(new ModelMetadata(provider, null, typeof(int), null).IsNullableValueType);
|
||||
}
|
||||
|
||||
// IsRequired
|
||||
|
|
@ -299,7 +286,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var provider = new EmptyModelMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: modelType,
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -319,7 +305,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var provider = new EmptyModelMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: modelType,
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -341,7 +326,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: modelType,
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -393,7 +377,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: modelType,
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -482,7 +465,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: null,
|
||||
modelType: modelType,
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -506,7 +488,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: () => new Class1(),
|
||||
modelType: typeof(Class1),
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -536,7 +517,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: () => new Class1(),
|
||||
modelType: typeof(Class1),
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -549,27 +529,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.Equal(expected, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertiesListGetsResetWhenModelGetsReset()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, null, () => new Class1(), typeof(Class1), null);
|
||||
|
||||
// Act
|
||||
var originalProps = metadata.Properties.ToArray();
|
||||
metadata.Model = new Class2();
|
||||
var newProps = metadata.Properties.ToArray();
|
||||
|
||||
// Assert
|
||||
var originalProp = Assert.Single(originalProps);
|
||||
Assert.Equal(typeof(string), originalProp.ModelType);
|
||||
Assert.Equal("Prop1", originalProp.PropertyName);
|
||||
var newProp = Assert.Single(newProps);
|
||||
Assert.Equal(typeof(int), newProp.ModelType);
|
||||
Assert.Equal("Prop2", newProp.PropertyName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PropertiesSetOnce()
|
||||
{
|
||||
|
|
@ -578,7 +537,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: () => new Class1(),
|
||||
modelType: typeof(Class1),
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -599,7 +557,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
provider,
|
||||
containerType: null,
|
||||
modelAccessor: () => new Class1(),
|
||||
modelType: typeof(Class1),
|
||||
propertyName: null);
|
||||
|
||||
|
|
@ -633,7 +590,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, null, () => null, typeof(object), "unusedName")
|
||||
var metadata = new ModelMetadata(provider, null, typeof(object), "unusedName")
|
||||
{
|
||||
DisplayName = "displayName",
|
||||
};
|
||||
|
|
@ -650,7 +607,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, null, null, typeof(object), "PropertyName");
|
||||
var metadata = new ModelMetadata(provider, null, typeof(object), "PropertyName");
|
||||
|
||||
// Act
|
||||
var result = metadata.GetDisplayName();
|
||||
|
|
@ -664,7 +621,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, null, null, typeof(object), null);
|
||||
var metadata = new ModelMetadata(provider, null, typeof(object), null);
|
||||
|
||||
// Act
|
||||
var result = metadata.GetDisplayName();
|
||||
|
|
@ -673,57 +630,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.Equal("Object", result);
|
||||
}
|
||||
|
||||
// SimpleDisplayText
|
||||
|
||||
public static IEnumerable<object[]> SimpleDisplayTextData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new object[]
|
||||
{
|
||||
new Func<object>(() => new ComplexClass()
|
||||
{
|
||||
Prop1 = new Class1 { Prop1 = "Hello" }
|
||||
}),
|
||||
typeof(ComplexClass),
|
||||
"Class1"
|
||||
};
|
||||
yield return new object[]
|
||||
{
|
||||
new Func<object>(() => new Class1()),
|
||||
typeof(Class1),
|
||||
"Class1"
|
||||
};
|
||||
yield return new object[]
|
||||
{
|
||||
new Func<object>(() => new ClassWithNoProperties()),
|
||||
typeof(ClassWithNoProperties),
|
||||
string.Empty
|
||||
};
|
||||
yield return new object[]
|
||||
{
|
||||
null,
|
||||
typeof(object),
|
||||
null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SimpleDisplayTextData))]
|
||||
public void TestSimpleDisplayText(Func<object> modelAccessor, Type modelType, string expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var provider = new EmptyModelMetadataProvider();
|
||||
var metadata = new ModelMetadata(provider, null, modelAccessor, modelType, null);
|
||||
|
||||
// Act
|
||||
var result = metadata.SimpleDisplayText;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
private class ClassWithNoProperties
|
||||
{
|
||||
public override string ToString()
|
||||
|
|
@ -774,7 +680,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
this,
|
||||
containerType: typeof(DummyContactModel),
|
||||
modelAccessor: null,
|
||||
modelType: typeof(string),
|
||||
propertyName: propertyName);
|
||||
|
||||
|
|
@ -789,7 +694,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadata = new ModelMetadata(
|
||||
this,
|
||||
containerType: typeof(DummyContactModel),
|
||||
modelAccessor: null,
|
||||
modelType: typeof(string),
|
||||
propertyName: keyValuePair.Key)
|
||||
{
|
||||
|
|
@ -803,31 +707,21 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public int GetMetadataForPropertiesCalls { get; private set; }
|
||||
|
||||
public ModelMetadata GetMetadataForParameter(
|
||||
Func<object> modelAccessor,
|
||||
[NotNull] MethodInfo methodInfo,
|
||||
[NotNull] string parameterName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerable<ModelMetadata> GetMetadataForProperties(object container, [NotNull] Type containerType)
|
||||
public IEnumerable<ModelMetadata> GetMetadataForProperties([NotNull] Type containerType)
|
||||
{
|
||||
Assert.Null(container);
|
||||
Assert.Equal(typeof(object), containerType);
|
||||
GetMetadataForPropertiesCalls++;
|
||||
|
||||
return _properties;
|
||||
}
|
||||
|
||||
public ModelMetadata GetMetadataForProperty(
|
||||
Func<object> modelAccessor,
|
||||
[NotNull] Type containerType,
|
||||
[NotNull] string propertyName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ModelMetadata GetMetadataForType(Func<object> modelAccessor, [NotNull] Type modelType)
|
||||
public ModelMetadata GetMetadataForType([NotNull] Type modelType)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
IEnumerable<object> callbackAttributes = null;
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(null, typeof(PropertyModel), "LocalAttributes");
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(typeof(PropertyModel), "LocalAttributes");
|
||||
var provider = new Mock<TestableAssociatedValidatorProvider> { CallBase = true };
|
||||
provider.Setup(p => p.AbstractGetValidators(metadata, It.IsAny<IEnumerable<object>>()))
|
||||
.Callback<ModelMetadata, IEnumerable<object>>((m, attributes) => callbackAttributes = attributes)
|
||||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
IEnumerable<object> callbackAttributes = null;
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(null, typeof(PropertyModel), "MetadataAttributes");
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(typeof(PropertyModel), "MetadataAttributes");
|
||||
var provider = new Mock<TestableAssociatedValidatorProvider> { CallBase = true };
|
||||
provider.Setup(p => p.AbstractGetValidators(metadata, It.IsAny<IEnumerable<object>>()))
|
||||
.Callback<ModelMetadata, IEnumerable<object>>((m, attributes) => callbackAttributes = attributes)
|
||||
|
|
@ -60,7 +60,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
IEnumerable<object> callbackAttributes = null;
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(null, typeof(PropertyModel), "MixedAttributes");
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(typeof(PropertyModel), "MixedAttributes");
|
||||
var provider = new Mock<TestableAssociatedValidatorProvider> { CallBase = true };
|
||||
provider.Setup(p => p.AbstractGetValidators(metadata, It.IsAny<IEnumerable<object>>()))
|
||||
.Callback<ModelMetadata, IEnumerable<object>>((m, attributes) => callbackAttributes = attributes)
|
||||
|
|
|
|||
|
|
@ -17,12 +17,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = metadataProvider.GetMetadataForProperty(() => null, typeof(PropertyDisplayNameModel), "MyProperty");
|
||||
var metadata = metadataProvider.GetMetadataForProperty(typeof(PropertyDisplayNameModel), "MyProperty");
|
||||
|
||||
var attribute = new CompareAttribute("OtherProperty");
|
||||
var adapter = new CompareAttributeAdapter(attribute);
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
|
||||
var context = new ClientModelValidationContext(metadata, metadataProvider, requestServices);
|
||||
var adapter = new CompareAttributeAdapter(attribute);
|
||||
|
||||
// Act
|
||||
var rules = adapter.GetClientValidationRules(context);
|
||||
|
|
@ -38,7 +41,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = metadataProvider.GetMetadataForProperty(() => null, typeof(PropertyNameModel), "MyProperty");
|
||||
var metadata = metadataProvider.GetMetadataForProperty(typeof(PropertyNameModel), "MyProperty");
|
||||
var attribute = new CompareAttribute("OtherProperty");
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
|
|
@ -58,7 +61,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = metadataProvider.GetMetadataForProperty(() => null, typeof(PropertyNameModel), "MyProperty");
|
||||
var metadata = metadataProvider.GetMetadataForProperty( typeof(PropertyNameModel), "MyProperty");
|
||||
var attribute = new CompareAttribute("OtherProperty")
|
||||
{
|
||||
ErrorMessage = "Hello '{0}', goodbye '{1}'."
|
||||
|
|
@ -87,7 +90,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Arrange
|
||||
var metadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = metadataProvider.GetMetadataForProperty(() => null, typeof(PropertyNameModel), "MyProperty");
|
||||
var metadata = metadataProvider.GetMetadataForProperty(typeof(PropertyNameModel), "MyProperty");
|
||||
var attribute = new CompareAttribute("OtherProperty")
|
||||
{
|
||||
ErrorMessageResourceName = "CompareAttributeTestResource",
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
provider2.Setup(p => p.GetValidators(It.IsAny<ModelMetadata>()))
|
||||
.Returns(new[] { validator3 });
|
||||
var compositeModelValidator = new CompositeModelValidatorProvider(new[] { provider1.Object, provider2.Object });
|
||||
var modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(
|
||||
modelAccessor: null,
|
||||
modelType: typeof(string));
|
||||
var modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(string));
|
||||
|
||||
// Act
|
||||
var result = compositeModelValidator.GetValidators(modelMetadata);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Arrange
|
||||
var provider = new DataAnnotationsModelValidatorProvider();
|
||||
var mockValidatable = Mock.Of<IValidatableObject>();
|
||||
var metadata = _metadataProvider.GetMetadataForType(() => null, mockValidatable.GetType());
|
||||
var metadata = _metadataProvider.GetMetadataForType(mockValidatable.GetType());
|
||||
|
||||
// Act
|
||||
var validators = provider.GetValidators(metadata);
|
||||
|
|
@ -39,8 +39,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelValidatorProvider();
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => null,
|
||||
typeof(DummyRequiredAttributeHelperClass),
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(typeof(DummyRequiredAttributeHelperClass),
|
||||
"WithAttribute");
|
||||
|
||||
// Act
|
||||
|
|
@ -143,7 +142,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelValidatorProvider();
|
||||
var metadata = _metadataProvider.GetMetadataForType(() => null, typeof(DummyClassWithDummyValidationAttribute));
|
||||
var metadata = _metadataProvider.GetMetadataForType(typeof(DummyClassWithDummyValidationAttribute));
|
||||
|
||||
// Act
|
||||
IEnumerable<IModelValidator> validators = provider.GetValidators(metadata);
|
||||
|
|
@ -171,7 +170,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Arrange
|
||||
var provider = new DataAnnotationsModelValidatorProvider();
|
||||
var mockValidatable = new Mock<IValidatableObject>();
|
||||
var metadata = _metadataProvider.GetMetadataForType(() => null, mockValidatable.Object.GetType());
|
||||
var metadata = _metadataProvider.GetMetadataForType(mockValidatable.Object.GetType());
|
||||
|
||||
// Act
|
||||
var validators = provider.GetValidators(metadata);
|
||||
|
|
@ -189,11 +188,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Arrange
|
||||
var provider = new DataAnnotationsModelValidatorProvider();
|
||||
var model = new ObservableModel();
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => model.TheProperty, typeof(ObservableModel), "TheProperty");
|
||||
var context = new ModelValidationContext(null, null, null, metadata, null);
|
||||
|
||||
var modelExplorer = _metadataProvider
|
||||
.GetModelExplorerForType(typeof(ObservableModel), model)
|
||||
.GetExplorerForProperty("TheProperty");
|
||||
|
||||
var context = new ModelValidationContext(
|
||||
rootPrefix: null,
|
||||
validatorProvider: null,
|
||||
modelState: null,
|
||||
modelExplorer: modelExplorer);
|
||||
|
||||
// Act
|
||||
var validators = provider.GetValidators(metadata).ToArray();
|
||||
var validators = provider.GetValidators(modelExplorer.Metadata).ToArray();
|
||||
var results = validators.SelectMany(o => o.Validate(context)).ToArray();
|
||||
|
||||
// Assert
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void ValuesSet()
|
||||
{
|
||||
// Arrange
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
|
||||
var attribute = new RequiredAttribute();
|
||||
|
||||
// Act
|
||||
|
|
@ -42,13 +41,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
yield return new object[]
|
||||
{
|
||||
_metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length"),
|
||||
_metadataProvider.GetModelExplorerForType(typeof(string), "Hello").GetExplorerForProperty("Length"),
|
||||
"Length"
|
||||
};
|
||||
|
||||
yield return new object[]
|
||||
{
|
||||
_metadataProvider.GetMetadataForType(() => new object(), typeof(SampleModel)),
|
||||
_metadataProvider.GetModelExplorerForType(typeof(SampleModel), 15),
|
||||
"SampleModel"
|
||||
};
|
||||
}
|
||||
|
|
@ -57,8 +56,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
#if ASPNET50
|
||||
[Theory]
|
||||
[MemberData(nameof(ValidateSetsMemberNamePropertyDataSet))]
|
||||
public void ValidateSetsMemberNamePropertyOfValidationContextForProperties(ModelMetadata metadata,
|
||||
string expectedMemberName)
|
||||
public void ValidateSetsMemberNamePropertyOfValidationContextForProperties(
|
||||
ModelExplorer modelExplorer,
|
||||
string expectedMemberName)
|
||||
{
|
||||
// Arrange
|
||||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
|
|
@ -71,7 +71,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
.Returns(ValidationResult.Success)
|
||||
.Verifiable();
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validationContext = CreateValidationContext(metadata);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
var results = validator.Validate(validationContext);
|
||||
|
|
@ -85,11 +85,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void ValidateWithIsValidTrue()
|
||||
{
|
||||
// Arrange
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
|
||||
var modelExplorer = _metadataProvider
|
||||
.GetModelExplorerForType(typeof(string), "Hello")
|
||||
.GetExplorerForProperty("Length");
|
||||
|
||||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
attribute.Setup(a => a.IsValid(metadata.Model)).Returns(true);
|
||||
attribute.Setup(a => a.IsValid(modelExplorer.Model)).Returns(true);
|
||||
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validationContext = CreateValidationContext(metadata);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
var result = validator.Validate(validationContext);
|
||||
|
|
@ -102,11 +106,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void ValidateWithIsValidFalse()
|
||||
{
|
||||
// Arrange
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
|
||||
var modelExplorer = _metadataProvider
|
||||
.GetModelExplorerForType(typeof(string), "Hello")
|
||||
.GetExplorerForProperty("Length");
|
||||
|
||||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
attribute.Setup(a => a.IsValid(metadata.Model)).Returns(false);
|
||||
attribute.Setup(a => a.IsValid(modelExplorer.Model)).Returns(false);
|
||||
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validationContext = CreateValidationContext(metadata);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
var result = validator.Validate(validationContext);
|
||||
|
|
@ -121,13 +129,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void ValidatateWithValidationResultSuccess()
|
||||
{
|
||||
// Arrange
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
|
||||
var modelExplorer = _metadataProvider
|
||||
.GetModelExplorerForType(typeof(string), "Hello")
|
||||
.GetExplorerForProperty("Length");
|
||||
|
||||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
attribute.Protected()
|
||||
.Setup<ValidationResult>("IsValid", ItExpr.IsAny<object>(), ItExpr.IsAny<ValidationContext>())
|
||||
.Returns(ValidationResult.Success);
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validationContext = CreateValidationContext(metadata);
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
var result = validator.Validate(validationContext);
|
||||
|
|
@ -141,13 +152,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
const string errorMessage = "Some error message";
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
|
||||
|
||||
var modelExplorer = _metadataProvider
|
||||
.GetModelExplorerForType(typeof(string), "Hello")
|
||||
.GetExplorerForProperty("Length");
|
||||
|
||||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
attribute.Protected()
|
||||
.Setup<ValidationResult>("IsValid", ItExpr.IsAny<object>(), ItExpr.IsAny<ValidationContext>())
|
||||
.Returns(new ValidationResult(errorMessage, memberNames: null));
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validationContext = CreateValidationContext(metadata);
|
||||
|
||||
var validationContext = CreateValidationContext(modelExplorer);
|
||||
|
||||
// Act
|
||||
var results = validator.Validate(validationContext);
|
||||
|
|
@ -163,11 +179,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
const string errorMessage = "A different error message";
|
||||
var metadata = _metadataProvider.GetMetadataForType(() => new object(), typeof(object));
|
||||
|
||||
var metadata = _metadataProvider.GetModelExplorerForType(typeof(object), new object());
|
||||
|
||||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
attribute.Protected()
|
||||
.Setup<ValidationResult>("IsValid", ItExpr.IsAny<object>(), ItExpr.IsAny<ValidationContext>())
|
||||
.Returns(new ValidationResult(errorMessage, new[] { "FirstName" }));
|
||||
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validationContext = CreateValidationContext(metadata);
|
||||
|
||||
|
|
@ -184,11 +203,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void ValidateReturnsMemberNameIfItIsDifferentFromDisplayName()
|
||||
{
|
||||
// Arrange
|
||||
var metadata = _metadataProvider.GetMetadataForType(() => new SampleModel(), typeof(SampleModel));
|
||||
var metadata = _metadataProvider.GetModelExplorerForType(typeof(SampleModel), new SampleModel());
|
||||
|
||||
var attribute = new Mock<ValidationAttribute> { CallBase = true };
|
||||
attribute.Protected()
|
||||
.Setup<ValidationResult>("IsValid", ItExpr.IsAny<object>(), ItExpr.IsAny<ValidationContext>())
|
||||
.Returns(new ValidationResult("Name error", new[] { "Name" }));
|
||||
|
||||
var validator = new DataAnnotationsModelValidator(attribute.Object);
|
||||
var validationContext = CreateValidationContext(metadata);
|
||||
|
||||
|
|
@ -207,12 +228,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Arrange
|
||||
var attribute = new FileExtensionsAttribute();
|
||||
var validator = new DataAnnotationsModelValidator<FileExtensionsAttribute>(attribute);
|
||||
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(
|
||||
modelAccessor: null,
|
||||
containerType: typeof(string),
|
||||
propertyName: nameof(string.Length));
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
|
||||
var context = new ClientModelValidationContext(metadata, _metadataProvider, requestServices);
|
||||
|
||||
// Act
|
||||
|
|
@ -228,12 +251,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Arrange
|
||||
var attribute = new TestableAttribute();
|
||||
var validator = new DataAnnotationsModelValidator<TestableAttribute>(attribute);
|
||||
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(
|
||||
modelAccessor: null,
|
||||
containerType: typeof(string),
|
||||
propertyName: nameof(string.Length));
|
||||
|
||||
var serviceCollection = new ServiceCollection();
|
||||
var requestServices = serviceCollection.BuildServiceProvider();
|
||||
|
||||
var context = new ClientModelValidationContext(metadata, _metadataProvider, requestServices);
|
||||
|
||||
// Act
|
||||
|
|
@ -249,18 +274,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
[Fact]
|
||||
public void IsRequiredTests()
|
||||
{
|
||||
// Arrange
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => 15, typeof(string), "Length");
|
||||
|
||||
// Act & Assert
|
||||
// Arrange & Act & Assert
|
||||
Assert.False(new DataAnnotationsModelValidator(new RangeAttribute(10, 20)).IsRequired);
|
||||
Assert.True(new DataAnnotationsModelValidator(new RequiredAttribute()).IsRequired);
|
||||
Assert.True(new DataAnnotationsModelValidator(new DerivedRequiredAttribute()).IsRequired);
|
||||
}
|
||||
|
||||
private static ModelValidationContext CreateValidationContext(ModelMetadata metadata)
|
||||
private static ModelValidationContext CreateValidationContext(ModelExplorer modelExplorer)
|
||||
{
|
||||
return new ModelValidationContext(null, null, null, metadata, null);
|
||||
return new ModelValidationContext(null, null, null, modelExplorer);
|
||||
}
|
||||
|
||||
private class DerivedRequiredAttribute : RequiredAttribute
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataMemberModelValidatorProvider();
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => null, typeof(ClassWithoutAttributes), "TheProperty");
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(typeof(ClassWithoutAttributes), "TheProperty");
|
||||
|
||||
// Act
|
||||
var validators = provider.GetValidators(metadata);
|
||||
|
|
@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataMemberModelValidatorProvider();
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => null, typeof(ClassWithDataMemberIsRequiredTrue), "TheProperty");
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(typeof(ClassWithDataMemberIsRequiredTrue), "TheProperty");
|
||||
|
||||
// Act
|
||||
var validators = provider.GetValidators(metadata);
|
||||
|
|
@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataMemberModelValidatorProvider();
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => null, typeof(ClassWithDataMemberIsRequiredFalse), "TheProperty");
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(typeof(ClassWithDataMemberIsRequiredFalse), "TheProperty");
|
||||
|
||||
// Act
|
||||
var validators = provider.GetValidators(metadata);
|
||||
|
|
@ -77,7 +77,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataMemberModelValidatorProvider();
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(() => null, typeof(ClassWithDataMemberIsRequiredTrueWithoutDataContract), "TheProperty");
|
||||
var metadata = _metadataProvider.GetMetadataForProperty(typeof(ClassWithDataMemberIsRequiredTrueWithoutDataContract), "TheProperty");
|
||||
|
||||
// Act
|
||||
var validators = provider.GetValidators(metadata);
|
||||
|
|
|
|||
|
|
@ -213,17 +213,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public void ExpectedValidationErrorsRaised(object model, Type type, Dictionary<string, string> expectedErrors)
|
||||
{
|
||||
// Arrange
|
||||
var testValidationContext = GetModelValidationContext(model, type);
|
||||
var context = GetModelValidationContext(model, type);
|
||||
|
||||
// Act (does not throw)
|
||||
new DefaultObjectValidator(
|
||||
testValidationContext.ExcludeFiltersProvider,
|
||||
testValidationContext.ModelMetadataProvider)
|
||||
.Validate(testValidationContext.ModelValidationContext);
|
||||
var validator = new DefaultObjectValidator(context.ExcludeFiltersProvider, context.ModelMetadataProvider);
|
||||
|
||||
// Act
|
||||
validator.Validate(context.ModelValidationContext);
|
||||
|
||||
// Assert
|
||||
var actualErrors = new Dictionary<string, string>();
|
||||
foreach (var keyStatePair in testValidationContext.ModelValidationContext.ModelState)
|
||||
foreach (var keyStatePair in context.ModelValidationContext.ModelState)
|
||||
{
|
||||
foreach (var error in keyStatePair.Value.Errors)
|
||||
{
|
||||
|
|
@ -483,44 +482,46 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
private TestModelValidationContext GetModelValidationContext(
|
||||
object model, Type type, string key = "", List<Type> excludedTypes = null)
|
||||
object model,
|
||||
Type type,
|
||||
string key = "",
|
||||
List<Type> excludedTypes = null)
|
||||
{
|
||||
var modelStateDictionary = new ModelStateDictionary();
|
||||
|
||||
var providers = new IModelValidatorProvider[]
|
||||
{
|
||||
new DataAnnotationsModelValidatorProvider(),
|
||||
new DataMemberModelValidatorProvider()
|
||||
};
|
||||
|
||||
var modelMetadataProvider = new DataAnnotationsModelMetadataProvider();
|
||||
var excludedValidationTypesPredicate =
|
||||
new List<IExcludeTypeValidationFilter>();
|
||||
|
||||
|
||||
var excludedValidationTypesPredicate = new List<IExcludeTypeValidationFilter>();
|
||||
if (excludedTypes != null)
|
||||
{
|
||||
var mockExcludeTypeFilter = new Mock<IExcludeTypeValidationFilter>();
|
||||
mockExcludeTypeFilter.Setup(o => o.IsTypeExcluded(It.IsAny<Type>()))
|
||||
.Returns<Type>(excludedType =>
|
||||
excludedTypes.Any(t => t.IsAssignableFrom(excludedType)));
|
||||
mockExcludeTypeFilter
|
||||
.Setup(o => o.IsTypeExcluded(It.IsAny<Type>()))
|
||||
.Returns<Type>(excludedType => excludedTypes.Any(t => t.IsAssignableFrom(excludedType)));
|
||||
|
||||
excludedValidationTypesPredicate.Add(mockExcludeTypeFilter.Object);
|
||||
}
|
||||
|
||||
var mockValidationExcludeFiltersProvider = new Mock<IValidationExcludeFiltersProvider>();
|
||||
mockValidationExcludeFiltersProvider.SetupGet(o => o.ExcludeFilters)
|
||||
.Returns(excludedValidationTypesPredicate);
|
||||
mockValidationExcludeFiltersProvider
|
||||
.SetupGet(o => o.ExcludeFilters)
|
||||
.Returns(excludedValidationTypesPredicate);
|
||||
|
||||
var modelExplorer = modelMetadataProvider.GetModelExplorerForType(type, model);
|
||||
|
||||
return new TestModelValidationContext
|
||||
{
|
||||
ModelValidationContext = new ModelValidationContext(
|
||||
key,
|
||||
new CompositeModelValidatorProvider(providers),
|
||||
modelStateDictionary,
|
||||
new ModelMetadata(
|
||||
provider: modelMetadataProvider,
|
||||
containerType: typeof(object),
|
||||
modelAccessor: () => model,
|
||||
modelType: type,
|
||||
propertyName: null),
|
||||
containerMetadata: null),
|
||||
modelExplorer),
|
||||
ModelMetadataProvider = modelMetadataProvider,
|
||||
ExcludeFiltersProvider = mockValidationExcludeFiltersProvider.Object
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new MaxLengthAttribute(10);
|
||||
var adapter = new MaxLengthAttributeAdapter(attribute);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var propertyName = "Length";
|
||||
var message = "{0} must be at most {1}";
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), propertyName);
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), propertyName);
|
||||
var attribute = new MaxLengthAttribute(5) { ErrorMessage = message };
|
||||
var adapter = new MaxLengthAttributeAdapter(attribute);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new MinLengthAttribute(6);
|
||||
var adapter = new MinLengthAttributeAdapter(attribute);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var propertyName = "Length";
|
||||
var message = "Array must have at least {1} items.";
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), propertyName);
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), propertyName);
|
||||
var attribute = new MinLengthAttribute(2) { ErrorMessage = message };
|
||||
var adapter = new MinLengthAttributeAdapter(attribute);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new RangeAttribute(typeof(decimal), "0", "100");
|
||||
var adapter = new RangeAttributeAdapter(attribute);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Arrange
|
||||
var expected = ValidationAttributeUtil.GetRequiredErrorMessage("Length");
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new RequiredAttribute();
|
||||
var adapter = new RequiredAttributeAdapter(attribute);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new StringLengthAttribute(8);
|
||||
var adapter = new StringLengthAttributeAdapter(attribute);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
|
@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var provider = new DataAnnotationsModelMetadataProvider();
|
||||
var metadata = provider.GetMetadataForProperty(() => null, typeof(string), "Length");
|
||||
var metadata = provider.GetMetadataForProperty(typeof(string), "Length");
|
||||
var attribute = new StringLengthAttribute(10) { MinimumLength = 3 };
|
||||
var adapter = new StringLengthAttributeAdapter(attribute);
|
||||
var serviceCollection = new ServiceCollection();
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue