Add HtmlAttributeNameAttribute for TagHelpers.
- Added the ability to override the HTML attribute name for TagHelper properties. - Tested functionality of overriding the attribute name target and inheriting the attribute name. #121
This commit is contained in:
parent
a2a05e7153
commit
e5a21520e5
|
|
@ -94,6 +94,22 @@ namespace Microsoft.AspNet.Razor.Runtime
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("TagNameAttribute_AdditionalTagsCannotContainNull"), p0);
|
return string.Format(CultureInfo.CurrentCulture, GetString("TagNameAttribute_AdditionalTagsCannotContainNull"), p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value cannot be null or empty.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ArgumentCannotBeNullOrEmpty
|
||||||
|
{
|
||||||
|
get { return GetString("ArgumentCannotBeNullOrEmpty"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value cannot be null or empty.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatArgumentCannotBeNullOrEmpty()
|
||||||
|
{
|
||||||
|
return GetString("ArgumentCannotBeNullOrEmpty");
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -134,4 +134,7 @@
|
||||||
<data name="TagNameAttribute_AdditionalTagsCannotContainNull" xml:space="preserve">
|
<data name="TagNameAttribute_AdditionalTagsCannotContainNull" xml:space="preserve">
|
||||||
<value>Parameter {0} must not contain null tag names.</value>
|
<value>Parameter {0} must not contain null tag names.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
|
||||||
|
<value>The value cannot be null or empty.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used to override an <see cref="ITagHelper"/> property's HTML attribute name.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
|
||||||
|
public sealed class HtmlAttributeNameAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Instantiates a new instance of the <see cref="HtmlAttributeNameAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">HTML attribute name for the associated property.</param>
|
||||||
|
public HtmlAttributeNameAttribute(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HTML attribute name of the associated property.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -68,11 +68,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
return attributeDescriptors;
|
return attributeDescriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make the HTML attribute name support names from a AttributeNameAttribute:
|
|
||||||
// https://github.com/aspnet/Razor/issues/121
|
|
||||||
private static TagHelperAttributeDescriptor ToAttributeDescriptor(PropertyInfo property)
|
private static TagHelperAttributeDescriptor ToAttributeDescriptor(PropertyInfo property)
|
||||||
{
|
{
|
||||||
return new TagHelperAttributeDescriptor(property.Name, property);
|
var attributeNameAttribute = property.GetCustomAttribute<HtmlAttributeNameAttribute>(inherit: false);
|
||||||
|
var attributeName = attributeNameAttribute != null ?
|
||||||
|
attributeNameAttribute.Name :
|
||||||
|
property.Name;
|
||||||
|
|
||||||
|
return new TagHelperAttributeDescriptor(attributeName, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ContentBehavior GetContentBehavior(Type type)
|
private static ContentBehavior GetContentBehavior(Type type)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ using Microsoft.Internal.Web.Utils;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
{
|
{
|
||||||
public class CompleteTagHelperDescriptorComparer : TagHelperDescriptorComparer
|
public class CompleteTagHelperDescriptorComparer : TagHelperDescriptorComparer, IEqualityComparer<TagHelperDescriptor>
|
||||||
{
|
{
|
||||||
public new static readonly CompleteTagHelperDescriptorComparer Default =
|
public new static readonly CompleteTagHelperDescriptorComparer Default =
|
||||||
new CompleteTagHelperDescriptorComparer();
|
new CompleteTagHelperDescriptorComparer();
|
||||||
|
|
@ -17,14 +17,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public new bool Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
|
bool IEqualityComparer<TagHelperDescriptor>.Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
|
||||||
{
|
{
|
||||||
return base.Equals(descriptorX, descriptorY) &&
|
return base.Equals(descriptorX, descriptorY) &&
|
||||||
descriptorX.Attributes.SequenceEqual(descriptorY.Attributes,
|
descriptorX.Attributes.SequenceEqual(descriptorY.Attributes,
|
||||||
CompleteTagHelperAttributeDescriptorComparer.Default);
|
CompleteTagHelperAttributeDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
public new int GetHashCode(TagHelperDescriptor descriptor)
|
int IEqualityComparer<TagHelperDescriptor>.GetHashCode(TagHelperDescriptor descriptor)
|
||||||
{
|
{
|
||||||
return HashCodeCombiner.Start()
|
return HashCodeCombiner.Start()
|
||||||
.Add(base.GetHashCode())
|
.Add(base.GetHashCode())
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,85 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
{
|
{
|
||||||
public class TagHelperDescriptorFactoryTest
|
public class TagHelperDescriptorFactoryTest
|
||||||
{
|
{
|
||||||
|
[Fact]
|
||||||
|
public void CreateDescriptor_OverridesAttributeNameFromAttribute()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var validProperty1 = typeof(OverriddenAttributeTagHelper).GetProperty(
|
||||||
|
nameof(OverriddenAttributeTagHelper.ValidAttribute1));
|
||||||
|
var validProperty2 = typeof(OverriddenAttributeTagHelper).GetProperty(
|
||||||
|
nameof(OverriddenAttributeTagHelper.ValidAttribute2));
|
||||||
|
var expectedDescriptors = new[] {
|
||||||
|
new TagHelperDescriptor(
|
||||||
|
"OverriddenAttribute",
|
||||||
|
typeof(OverriddenAttributeTagHelper).FullName,
|
||||||
|
ContentBehavior.None,
|
||||||
|
new[] {
|
||||||
|
new TagHelperAttributeDescriptor("SomethingElse", validProperty1),
|
||||||
|
new TagHelperAttributeDescriptor("Something-Else", validProperty2)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(OverriddenAttributeTagHelper));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateDescriptor_DoesNotInheritOverridenAttributeName()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var validProperty1 = typeof(InheritedOverriddenAttributeTagHelper).GetProperty(
|
||||||
|
nameof(InheritedOverriddenAttributeTagHelper.ValidAttribute1));
|
||||||
|
var validProperty2 = typeof(InheritedOverriddenAttributeTagHelper).GetProperty(
|
||||||
|
nameof(InheritedOverriddenAttributeTagHelper.ValidAttribute2));
|
||||||
|
var expectedDescriptors = new[] {
|
||||||
|
new TagHelperDescriptor(
|
||||||
|
"InheritedOverriddenAttribute",
|
||||||
|
typeof(InheritedOverriddenAttributeTagHelper).FullName,
|
||||||
|
ContentBehavior.None,
|
||||||
|
new[] {
|
||||||
|
new TagHelperAttributeDescriptor(nameof(InheritedOverriddenAttributeTagHelper.ValidAttribute1),
|
||||||
|
validProperty1),
|
||||||
|
new TagHelperAttributeDescriptor("Something-Else", validProperty2)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(InheritedOverriddenAttributeTagHelper));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreateDescriptor_AllowsOverridenAttributeNameOnUnimplementedVirtual()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var validProperty1 = typeof(InheritedNotOverriddenAttributeTagHelper).GetProperty(
|
||||||
|
nameof(InheritedNotOverriddenAttributeTagHelper.ValidAttribute1));
|
||||||
|
var validProperty2 = typeof(InheritedNotOverriddenAttributeTagHelper).GetProperty(
|
||||||
|
nameof(InheritedNotOverriddenAttributeTagHelper.ValidAttribute2));
|
||||||
|
var expectedDescriptors = new[] {
|
||||||
|
new TagHelperDescriptor(
|
||||||
|
"InheritedNotOverriddenAttribute",
|
||||||
|
typeof(InheritedNotOverriddenAttributeTagHelper).FullName,
|
||||||
|
ContentBehavior.None,
|
||||||
|
new[] {
|
||||||
|
new TagHelperAttributeDescriptor("SomethingElse", validProperty1),
|
||||||
|
new TagHelperAttributeDescriptor("Something-Else", validProperty2)
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(InheritedNotOverriddenAttributeTagHelper));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CreateDescriptor_BuildsDescriptorsFromSimpleTypes()
|
public void CreateDescriptor_BuildsDescriptorsFromSimpleTypes()
|
||||||
{
|
{
|
||||||
|
|
@ -19,7 +98,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(descriptors);
|
var descriptor = Assert.Single(descriptors);
|
||||||
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -41,7 +120,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(descriptors);
|
var descriptor = Assert.Single(descriptors);
|
||||||
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -62,7 +141,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(descriptors);
|
var descriptor = Assert.Single(descriptors);
|
||||||
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -84,7 +163,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(descriptors);
|
var descriptor = Assert.Single(descriptors);
|
||||||
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -107,7 +186,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(descriptors);
|
var descriptor = Assert.Single(descriptors);
|
||||||
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -124,7 +203,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(descriptors);
|
var descriptor = Assert.Single(descriptors);
|
||||||
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -142,7 +221,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(descriptors);
|
var descriptor = Assert.Single(descriptors);
|
||||||
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -171,7 +250,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(MultiTagTagHelper));
|
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(MultiTagTagHelper));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(descriptors, expectedDescriptors, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -192,7 +271,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var descriptor = Assert.Single(descriptors);
|
var descriptor = Assert.Single(descriptors);
|
||||||
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -208,7 +287,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(DuplicateTagNameTagHelper));
|
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(DuplicateTagNameTagHelper));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(descriptors, expectedDescriptors, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -225,7 +304,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(OverrideNameTagHelper));
|
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(OverrideNameTagHelper));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(descriptors, expectedDescriptors, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -242,7 +321,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(MultipleAttributeTagHelper));
|
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(MultipleAttributeTagHelper));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(descriptors, expectedDescriptors, CompleteTagHelperDescriptorComparer.Default);
|
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
[ContentBehavior(ContentBehavior.Append)]
|
[ContentBehavior(ContentBehavior.Append)]
|
||||||
|
|
@ -283,5 +362,23 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||||
private class InheritedSingleAttributeTagHelper : SingleAttributeTagHelper
|
private class InheritedSingleAttributeTagHelper : SingleAttributeTagHelper
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class OverriddenAttributeTagHelper
|
||||||
|
{
|
||||||
|
[HtmlAttributeName("SomethingElse")]
|
||||||
|
public virtual string ValidAttribute1 { get; set; }
|
||||||
|
|
||||||
|
[HtmlAttributeName("Something-Else")]
|
||||||
|
public string ValidAttribute2 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InheritedOverriddenAttributeTagHelper : OverriddenAttributeTagHelper
|
||||||
|
{
|
||||||
|
public override string ValidAttribute1 { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InheritedNotOverriddenAttributeTagHelper : OverriddenAttributeTagHelper
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue