Set `ModelMetadata.TemplateHint` based on data annotations
- add `CachedDataAnnotationsMetadataAttributes.UIHint` - set `ModelMetadata.TemplateHint` using `UIHintAttribute` or `HiddenInputAttribute` - add doc comments for `TemplateHint`-related properties and methods - add unit tests and use these attributes in functional tests nits: - cache and seal `CachedModelMetadata.IsCollectionType` - correct doc comments for `ModelMetadata.RealModelType` - add doc comments for `IsCollectionType`-related properties and methods - add doc comments for `IsComplexType`-related properties and methods - move `CachedModelMetadata.IsComplexType` right below `IsCollectionType` - same for related fields and methods
This commit is contained in:
parent
451db6fb16
commit
0549769fd0
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// 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.
|
// 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.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -20,6 +19,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
HiddenInput = attributes.OfType<HiddenInputAttribute>().FirstOrDefault();
|
HiddenInput = attributes.OfType<HiddenInputAttribute>().FirstOrDefault();
|
||||||
Required = attributes.OfType<RequiredAttribute>().FirstOrDefault();
|
Required = attributes.OfType<RequiredAttribute>().FirstOrDefault();
|
||||||
ScaffoldColumn = attributes.OfType<ScaffoldColumnAttribute>().FirstOrDefault();
|
ScaffoldColumn = attributes.OfType<ScaffoldColumnAttribute>().FirstOrDefault();
|
||||||
|
UIHint = attributes.OfType<UIHintAttribute>().FirstOrDefault();
|
||||||
|
|
||||||
BinderMetadata = attributes.OfType<IBinderMetadata>().FirstOrDefault();
|
BinderMetadata = attributes.OfType<IBinderMetadata>().FirstOrDefault();
|
||||||
PropertyBindingPredicateProviders = attributes.OfType<IPropertyBindingPredicateProvider>();
|
PropertyBindingPredicateProviders = attributes.OfType<IPropertyBindingPredicateProvider>();
|
||||||
BinderModelNameProvider = attributes.OfType<IModelNameProvider>().FirstOrDefault();
|
BinderModelNameProvider = attributes.OfType<IModelNameProvider>().FirstOrDefault();
|
||||||
|
|
@ -82,7 +83,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public HiddenInputAttribute HiddenInput { get; protected set; }
|
public HiddenInputAttribute HiddenInput { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets (or sets in subclasses) <see cref="IEnumerable{IPropertyBindingPredicateProvider}"/> found in
|
/// Gets (or sets in subclasses) <see cref="IEnumerable{IPropertyBindingPredicateProvider}"/> found in
|
||||||
/// collection passed to the <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{object})"/>
|
/// collection passed to the <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{object})"/>
|
||||||
/// constructor, if any.
|
/// constructor, if any.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -91,5 +92,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public RequiredAttribute Required { get; protected set; }
|
public RequiredAttribute Required { get; protected set; }
|
||||||
|
|
||||||
public ScaffoldColumnAttribute ScaffoldColumn { get; protected set; }
|
public ScaffoldColumnAttribute ScaffoldColumn { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets (or sets in subclasses) <see cref="UIHintAttribute"/> found in collection passed to the
|
||||||
|
/// <see cref="CachedDataAnnotationsMetadataAttributes(IEnumerable{object})"/> constructor, if any.
|
||||||
|
/// </summary>
|
||||||
|
public UIHintAttribute UIHint { get; protected set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ using System.Reflection;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
// Class does not override ComputeIsComplexType() because value calculated in ModelMetadata's base implementation
|
// Class does not override ComputeIsCollectionType() or ComputeIsComplexType() because values calculated in
|
||||||
// is correct.
|
// ModelMetadata's base implementation are correct. No data annotations override those calculations.
|
||||||
public class CachedDataAnnotationsModelMetadata : CachedModelMetadata<CachedDataAnnotationsMetadataAttributes>
|
public class CachedDataAnnotationsModelMetadata : CachedModelMetadata<CachedDataAnnotationsMetadataAttributes>
|
||||||
{
|
{
|
||||||
private static readonly string HtmlName = DataType.Html.ToString();
|
private static readonly string HtmlName = DataType.Html.ToString();
|
||||||
|
|
@ -333,6 +333,31 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
: base.ComputeShowForEdit();
|
: base.ComputeShowForEdit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate the <see cref="ModelMetadata.TemplateHint"/> value based on presence of a
|
||||||
|
/// <see cref="UIHintAttribute"/> and its <see cref="UIHintAttribute.UIHint"/> value or presence of a
|
||||||
|
/// <see cref="HiddenInputAttribute"/> when no <see cref="UIHintAttribute"/> exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// Calculated <see cref="ModelMetadata.TemplateHint"/> value. <see cref="UIHintAttribute.UIHint"/> if a
|
||||||
|
/// <see cref="UIHintAttribute"/> exists. <c>"HiddenInput"</c> if a <see cref="HiddenInputAttribute"/> exists
|
||||||
|
/// and no <see cref="UIHintAttribute"/> exists. <c>null</c> otherwise.
|
||||||
|
/// </returns>
|
||||||
|
protected override string ComputeTemplateHint()
|
||||||
|
{
|
||||||
|
if (PrototypeCache.UIHint != null)
|
||||||
|
{
|
||||||
|
return PrototypeCache.UIHint.UIHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PrototypeCache.HiddenInput != null)
|
||||||
|
{
|
||||||
|
return "HiddenInput";
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.ComputeTemplateHint();
|
||||||
|
}
|
||||||
|
|
||||||
private static void ValidateDisplayColumnAttribute(DisplayColumnAttribute displayColumnAttribute,
|
private static void ValidateDisplayColumnAttribute(DisplayColumnAttribute displayColumnAttribute,
|
||||||
PropertyInfo displayColumnProperty, Type modelType)
|
PropertyInfo displayColumnProperty, Type modelType)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
private bool _hasNonDefaultEditFormat;
|
private bool _hasNonDefaultEditFormat;
|
||||||
private bool _hideSurroundingHtml;
|
private bool _hideSurroundingHtml;
|
||||||
private bool _htmlEncode;
|
private bool _htmlEncode;
|
||||||
private bool _isReadOnly;
|
private bool _isCollectionType;
|
||||||
private bool _isComplexType;
|
private bool _isComplexType;
|
||||||
|
private bool _isReadOnly;
|
||||||
private bool _isRequired;
|
private bool _isRequired;
|
||||||
private string _nullDisplayText;
|
private string _nullDisplayText;
|
||||||
private int _order;
|
private int _order;
|
||||||
private bool _showForDisplay;
|
private bool _showForDisplay;
|
||||||
private bool _showForEdit;
|
private bool _showForEdit;
|
||||||
|
private string _templateHint;
|
||||||
private IBinderMetadata _binderMetadata;
|
private IBinderMetadata _binderMetadata;
|
||||||
private string _binderModelName;
|
private string _binderModelName;
|
||||||
private IPropertyBindingPredicateProvider _propertyBindingPredicateProvider;
|
private IPropertyBindingPredicateProvider _propertyBindingPredicateProvider;
|
||||||
|
|
@ -46,13 +48,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
private bool _hasNonDefaultEditFormatComputed;
|
private bool _hasNonDefaultEditFormatComputed;
|
||||||
private bool _hideSurroundingHtmlComputed;
|
private bool _hideSurroundingHtmlComputed;
|
||||||
private bool _htmlEncodeComputed;
|
private bool _htmlEncodeComputed;
|
||||||
private bool _isReadOnlyComputed;
|
private bool _isCollectionTypeComputed;
|
||||||
private bool _isComplexTypeComputed;
|
private bool _isComplexTypeComputed;
|
||||||
|
private bool _isReadOnlyComputed;
|
||||||
private bool _isRequiredComputed;
|
private bool _isRequiredComputed;
|
||||||
private bool _nullDisplayTextComputed;
|
private bool _nullDisplayTextComputed;
|
||||||
private bool _orderComputed;
|
private bool _orderComputed;
|
||||||
private bool _showForDisplayComputed;
|
private bool _showForDisplayComputed;
|
||||||
private bool _showForEditComputed;
|
private bool _showForEditComputed;
|
||||||
|
private bool _templateHintComputed;
|
||||||
private bool _isBinderMetadataComputed;
|
private bool _isBinderMetadataComputed;
|
||||||
private bool _isBinderModelNameComputed;
|
private bool _isBinderModelNameComputed;
|
||||||
private bool _isBinderTypeComputed;
|
private bool _isBinderTypeComputed;
|
||||||
|
|
@ -320,6 +324,35 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed override bool IsCollectionType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_isCollectionTypeComputed)
|
||||||
|
{
|
||||||
|
_isCollectionType = ComputeIsCollectionType();
|
||||||
|
_isCollectionTypeComputed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _isCollectionType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed override bool IsComplexType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_isComplexTypeComputed)
|
||||||
|
{
|
||||||
|
_isComplexType = ComputeIsComplexType();
|
||||||
|
_isComplexTypeComputed = true;
|
||||||
|
}
|
||||||
|
return _isComplexType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public sealed override bool IsReadOnly
|
public sealed override bool IsReadOnly
|
||||||
{
|
{
|
||||||
|
|
@ -358,20 +391,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public sealed override bool IsComplexType
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (!_isComplexTypeComputed)
|
|
||||||
{
|
|
||||||
_isComplexType = ComputeIsComplexType();
|
|
||||||
_isComplexTypeComputed = true;
|
|
||||||
}
|
|
||||||
return _isComplexType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public sealed override string NullDisplayText
|
public sealed override string NullDisplayText
|
||||||
{
|
{
|
||||||
|
|
@ -495,6 +514,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public sealed override string TemplateHint
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_templateHintComputed)
|
||||||
|
{
|
||||||
|
_templateHint = ComputeTemplateHint();
|
||||||
|
_templateHintComputed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _templateHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_templateHint = value;
|
||||||
|
_templateHintComputed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public sealed override Type BinderType
|
public sealed override Type BinderType
|
||||||
{
|
{
|
||||||
|
|
@ -605,6 +645,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
return base.HtmlEncode;
|
return base.HtmlEncode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate the <see cref="IsCollectionType"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Calculated <see cref="IsCollectionType"/> value.</returns>
|
||||||
|
protected virtual bool ComputeIsCollectionType()
|
||||||
|
{
|
||||||
|
return base.IsCollectionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate the <see cref="IsComplexType"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Calculated <see cref="IsComplexType"/> value.</returns>
|
||||||
|
protected virtual bool ComputeIsComplexType()
|
||||||
|
{
|
||||||
|
return base.IsComplexType;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual bool ComputeIsReadOnly()
|
protected virtual bool ComputeIsReadOnly()
|
||||||
{
|
{
|
||||||
return base.IsReadOnly;
|
return base.IsReadOnly;
|
||||||
|
|
@ -615,11 +673,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
return base.IsRequired;
|
return base.IsRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool ComputeIsComplexType()
|
|
||||||
{
|
|
||||||
return base.IsComplexType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculate the <see cref="NullDisplayText"/> value.
|
/// Calculate the <see cref="NullDisplayText"/> value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -647,5 +700,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
return base.ShowForEdit;
|
return base.ShowForEdit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate the <see cref="TemplateHint"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Calculated <see cref="TemplateHint"/> value.</returns>
|
||||||
|
protected virtual string ComputeTemplateHint()
|
||||||
|
{
|
||||||
|
return base.TemplateHint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -142,11 +142,25 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual bool HideSurroundingHtml { get; set; }
|
public virtual bool HideSurroundingHtml { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the <see cref="ModelType"/> is a collection <see cref="Type"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <c>true</c> if the <see cref="ModelType"/> is not <see cref="string"/> and is assignable to
|
||||||
|
/// <see cref="System.Collections.IEnumerable"/>; <c>false</c> otherwise.
|
||||||
|
/// </remarks>
|
||||||
public virtual bool IsCollectionType
|
public virtual bool IsCollectionType
|
||||||
{
|
{
|
||||||
get { return TypeHelper.IsCollectionType(ModelType); }
|
get { return TypeHelper.IsCollectionType(ModelType); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the <see cref="ModelType"/> is a complex type.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <c>false</c> if the <see cref="ModelType"/> has a direct conversion to <see cref="string"/>; <c>true</c>
|
||||||
|
/// otherwise.
|
||||||
|
/// </remarks>
|
||||||
public virtual bool IsComplexType
|
public virtual bool IsComplexType
|
||||||
{
|
{
|
||||||
get { return !TypeHelper.HasStringConverter(ModelType); }
|
get { return !TypeHelper.HasStringConverter(ModelType); }
|
||||||
|
|
@ -238,8 +252,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
protected IModelMetadataProvider Provider { get; set; }
|
protected IModelMetadataProvider Provider { get; set; }
|
||||||
|
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// Gets <c>T</c> if <see cref="ModelType"/> is <see cref="Nullable{T}"/>;
|
/// Gets runtime <see cref="Type"/> of <see cref="Model"/> if <see cref="Model"/> is non-<c>null</c> and
|
||||||
/// <see cref="ModelType"/> otherwise.
|
/// <see cref="ModelType"/> is not <see cref="Nullable{T}"/>; <see cref="ModelType"/> otherwise.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public Type RealModelType
|
public Type RealModelType
|
||||||
{
|
{
|
||||||
|
|
@ -294,6 +308,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
set { _showForEdit = value; }
|
set { _showForEdit = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a hint that suggests what template to use for this model. Overrides <see cref="DataTypeName"/>
|
||||||
|
/// in that context but, unlike <see cref="DataTypeName"/>, this value is not used elsewhere.
|
||||||
|
/// </summary>
|
||||||
|
/// <value><c>null</c> unless set manually or through additional metadata e.g. attributes.</value>
|
||||||
public virtual string TemplateHint { get; set; }
|
public virtual string TemplateHint { get; set; }
|
||||||
|
|
||||||
internal EfficientTypePropertyKey<Type, string> CacheKey
|
internal EfficientTypePropertyKey<Type, string> CacheKey
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Null(cache.HiddenInput);
|
Assert.Null(cache.HiddenInput);
|
||||||
Assert.Null(cache.Required);
|
Assert.Null(cache.Required);
|
||||||
Assert.Null(cache.ScaffoldColumn);
|
Assert.Null(cache.ScaffoldColumn);
|
||||||
|
Assert.Null(cache.UIHint);
|
||||||
Assert.Null(cache.BinderMetadata);
|
Assert.Null(cache.BinderMetadata);
|
||||||
Assert.Null(cache.BinderModelNameProvider);
|
Assert.Null(cache.BinderModelNameProvider);
|
||||||
Assert.Empty(cache.PropertyBindingPredicateProviders);
|
Assert.Empty(cache.PropertyBindingPredicateProviders);
|
||||||
|
|
@ -51,6 +52,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{ new EditableAttribute(allowEdit: false), cache => cache.Editable },
|
{ new EditableAttribute(allowEdit: false), cache => cache.Editable },
|
||||||
{ new HiddenInputAttribute(), cache => cache.HiddenInput },
|
{ new HiddenInputAttribute(), cache => cache.HiddenInput },
|
||||||
{ new RequiredAttribute(), cache => cache.Required },
|
{ new RequiredAttribute(), cache => cache.Required },
|
||||||
|
{ new ScaffoldColumnAttribute(scaffold: true), cache => cache.ScaffoldColumn },
|
||||||
|
{ new UIHintAttribute("hintHint"), cache => cache.UIHint },
|
||||||
{ new TestBinderMetadata(), cache => cache.BinderMetadata },
|
{ new TestBinderMetadata(), cache => cache.BinderMetadata },
|
||||||
{ new TestModelNameProvider(), cache => cache.BinderModelNameProvider },
|
{ new TestModelNameProvider(), cache => cache.BinderModelNameProvider },
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void HiddenInputWorksOnProperty()
|
public void HiddenInputWorksOnProperty_ForHideSurroundingHtml()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new DataAnnotationsModelMetadataProvider();
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
|
@ -195,7 +195,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void HiddenInputWorksOnPropertyType()
|
public void HiddenInputWorksOnPropertyType_ForHideSurroundingHtml()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new DataAnnotationsModelMetadataProvider();
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
|
@ -209,6 +209,36 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.True(result);
|
Assert.True(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HiddenInputWorksOnProperty_ForTemplateHint()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
var metadata = provider.GetMetadataForType(modelAccessor: null, modelType: typeof(ClassWithHiddenProperties));
|
||||||
|
var property = metadata.Properties["DirectlyHidden"];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = property.TemplateHint;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("HiddenInput", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HiddenInputWorksOnPropertyType_ForTemplateHint()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
var metadata = provider.GetMetadataForType(modelAccessor: null, modelType: typeof(ClassWithHiddenProperties));
|
||||||
|
var property = metadata.Properties["OfHiddenType"];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = property.TemplateHint;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("HiddenInput", result);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetMetadataForProperty_WithNoBinderMetadata_GetsItFromType()
|
public void GetMetadataForProperty_WithNoBinderMetadata_GetsItFromType()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
new DisplayFormatAttribute { NullDisplayText = "value" }, metadata => metadata.NullDisplayText
|
new DisplayFormatAttribute { NullDisplayText = "value" }, metadata => metadata.NullDisplayText
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
new TestModelNameProvider() { Name = "value" }, metadata => metadata.BinderModelName
|
new TestModelNameProvider { Name = "value" }, metadata => metadata.BinderModelName
|
||||||
|
},
|
||||||
|
{
|
||||||
|
new UIHintAttribute("value"), metadata => metadata.TemplateHint
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -208,6 +211,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
metadata => metadata.HideSurroundingHtml,
|
metadata => metadata.HideSurroundingHtml,
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
new HiddenInputAttribute(),
|
||||||
|
metadata => string.Equals("HiddenInput", metadata.TemplateHint, StringComparison.Ordinal),
|
||||||
|
true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
new RequiredAttribute(),
|
new RequiredAttribute(),
|
||||||
metadata => metadata.IsRequired,
|
metadata => metadata.IsRequired,
|
||||||
|
|
@ -466,6 +474,28 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Null(metadata.EditFormatString);
|
Assert.Null(metadata.EditFormatString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TemplateHint_AttributesHaveExpectedPrecedence()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = "this is a hint";
|
||||||
|
var hidden = new HiddenInputAttribute();
|
||||||
|
var uiHint = new UIHintAttribute(expected);
|
||||||
|
var provider = new DataAnnotationsModelMetadataProvider();
|
||||||
|
var metadata = new CachedDataAnnotationsModelMetadata(
|
||||||
|
provider,
|
||||||
|
containerType: null,
|
||||||
|
modelType: typeof(object),
|
||||||
|
propertyName: null,
|
||||||
|
attributes: new Attribute[] { hidden, uiHint });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = metadata.TemplateHint;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Constructor_FindsBinderTypeProviders_Null()
|
public void Constructor_FindsBinderTypeProviders_Null()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
|
||||||
namespace MvcTagHelpersWebSite.Models
|
namespace MvcTagHelpersWebSite.Models
|
||||||
{
|
{
|
||||||
public class Person
|
public class Person
|
||||||
{
|
{
|
||||||
|
[HiddenInput(DisplayValue = false)]
|
||||||
[Range(1, 100)]
|
[Range(1, 100)]
|
||||||
public int Number
|
public int Number
|
||||||
{
|
{
|
||||||
|
|
@ -28,6 +30,7 @@ namespace MvcTagHelpersWebSite.Models
|
||||||
}
|
}
|
||||||
|
|
||||||
[EnumDataType(typeof(Gender))]
|
[EnumDataType(typeof(Gender))]
|
||||||
|
[UIHint("GenderUsingTagHelpers")]
|
||||||
public Gender Gender
|
public Gender Gender
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
}
|
}
|
||||||
@Html.DropDownListFor(m => m.Employee.OfficeNumber, offices)
|
@Html.DropDownListFor(m => m.Employee.OfficeNumber, offices)
|
||||||
</div>
|
</div>
|
||||||
@Html.HiddenFor(m => m.Employee.Number)
|
@Html.EditorFor(m => m.Employee.Number)
|
||||||
@Html.ValidationSummary()
|
@Html.ValidationSummary()
|
||||||
<input type="submit" />
|
<input type="submit" />
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue