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:
NTaylorMullen 2014-10-11 13:30:53 -07:00
parent a2a05e7153
commit e5a21520e5
6 changed files with 170 additions and 18 deletions

View File

@ -94,6 +94,22 @@ namespace Microsoft.AspNet.Razor.Runtime
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)
{
var value = _resourceManager.GetString(name);

View File

@ -134,4 +134,7 @@
<data name="TagNameAttribute_AdditionalTagsCannotContainNull" xml:space="preserve">
<value>Parameter {0} must not contain null tag names.</value>
</data>
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
<value>The value cannot be null or empty.</value>
</data>
</root>

View File

@ -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; }
}
}

View File

@ -68,11 +68,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
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)
{
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)

View File

@ -8,7 +8,7 @@ using Microsoft.Internal.Web.Utils;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
public class CompleteTagHelperDescriptorComparer : TagHelperDescriptorComparer
public class CompleteTagHelperDescriptorComparer : TagHelperDescriptorComparer, IEqualityComparer<TagHelperDescriptor>
{
public new static readonly CompleteTagHelperDescriptorComparer Default =
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) &&
descriptorX.Attributes.SequenceEqual(descriptorY.Attributes,
CompleteTagHelperAttributeDescriptorComparer.Default);
}
public new int GetHashCode(TagHelperDescriptor descriptor)
int IEqualityComparer<TagHelperDescriptor>.GetHashCode(TagHelperDescriptor descriptor)
{
return HashCodeCombiner.Start()
.Add(base.GetHashCode())

View File

@ -8,6 +8,85 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
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]
public void CreateDescriptor_BuildsDescriptorsFromSimpleTypes()
{
@ -19,7 +98,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -41,7 +120,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -62,7 +141,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -84,7 +163,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -107,7 +186,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -124,7 +203,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -142,7 +221,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -171,7 +250,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(MultiTagTagHelper));
// Assert
Assert.Equal(descriptors, expectedDescriptors, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -192,7 +271,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Assert
var descriptor = Assert.Single(descriptors);
Assert.Equal(descriptor, expectedDescriptor, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptor, descriptor, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -208,7 +287,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(DuplicateTagNameTagHelper));
// Assert
Assert.Equal(descriptors, expectedDescriptors, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -225,7 +304,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(OverrideNameTagHelper));
// Assert
Assert.Equal(descriptors, expectedDescriptors, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
}
[Fact]
@ -242,7 +321,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(typeof(MultipleAttributeTagHelper));
// Assert
Assert.Equal(descriptors, expectedDescriptors, CompleteTagHelperDescriptorComparer.Default);
Assert.Equal(expectedDescriptors, descriptors, CompleteTagHelperDescriptorComparer.Default);
}
[ContentBehavior(ContentBehavior.Append)]
@ -283,5 +362,23 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
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
{
}
}
}