diff --git a/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs
index 6416da158b..5e61f5058a 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs
@@ -234,6 +234,22 @@ namespace Microsoft.AspNet.Razor.Runtime
return GetString("TagHelperDescriptorFactory_Tag");
}
+ ///
+ /// Invalid tag helper bound property '{0}.{1}'. An '{2}' must not be associated with a property with no public setter unless its type implements '{3}'.
+ ///
+ internal static string TagHelperDescriptorFactory_InvalidAttributeNameAttribute
+ {
+ get { return GetString("TagHelperDescriptorFactory_InvalidAttributeNameAttribute"); }
+ }
+
+ ///
+ /// Invalid tag helper bound property '{0}.{1}'. An '{2}' must not be associated with a property with no public setter unless its type implements '{3}'.
+ ///
+ internal static string FormatTagHelperDescriptorFactory_InvalidAttributeNameAttribute(object p0, object p1, object p2, object p3)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributeNameAttribute"), p0, p1, p2, p3);
+ }
+
///
/// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with {2} '{3}' because {2} contains a '{4}' character.
///
@@ -283,19 +299,67 @@ namespace Microsoft.AspNet.Razor.Runtime
}
///
- /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null unless property type implements '{4}'.
+ /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a null or empty name.
///
- internal static string TagHelperDescriptorFactory_InvalidAttributePrefix
+ internal static string TagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty
{
- get { return GetString("TagHelperDescriptorFactory_InvalidAttributePrefix"); }
+ get { return GetString("TagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty"); }
+ }
+
+ ///
+ /// Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a null or empty name.
+ ///
+ internal static string FormatTagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty(object p0, object p1)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty"), p0, p1);
+ }
+
+ ///
+ /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null or empty if property has no public setter.
+ ///
+ internal static string TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty
+ {
+ get { return GetString("TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty"); }
+ }
+
+ ///
+ /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null or empty if property has no public setter.
+ ///
+ internal static string FormatTagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty(object p0, object p1, object p2, object p3)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty"), p0, p1, p2, p3);
+ }
+
+ ///
+ /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'.
+ ///
+ internal static string TagHelperDescriptorFactory_InvalidAttributePrefixNull
+ {
+ get { return GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNull"); }
+ }
+
+ ///
+ /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'.
+ ///
+ internal static string FormatTagHelperDescriptorFactory_InvalidAttributePrefixNull(object p0, object p1, object p2, object p3, object p4)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNull"), p0, p1, p2, p3, p4);
}
///
/// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null unless property type implements '{4}'.
///
- internal static string FormatTagHelperDescriptorFactory_InvalidAttributePrefix(object p0, object p1, object p2, object p3, object p4)
+ internal static string TagHelperDescriptorFactory_InvalidAttributePrefixNotNull
{
- return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributePrefix"), p0, p1, p2, p3, p4);
+ get { return GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNotNull"); }
+ }
+
+ ///
+ /// Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null unless property type implements '{4}'.
+ ///
+ internal static string FormatTagHelperDescriptorFactory_InvalidAttributePrefixNotNull(object p0, object p1, object p2, object p3, object p4)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorFactory_InvalidAttributePrefixNotNull"), p0, p1, p2, p3, p4);
}
///
diff --git a/src/Microsoft.AspNet.Razor.Runtime/Resources.resx b/src/Microsoft.AspNet.Razor.Runtime/Resources.resx
index 3d845ce34e..c59fd6e955 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/Resources.resx
+++ b/src/Microsoft.AspNet.Razor.Runtime/Resources.resx
@@ -159,6 +159,9 @@
Tag
+
+ Invalid tag helper bound property '{0}.{1}'. An '{2}' must not be associated with a property with no public setter unless its type implements '{3}'.
+
Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with {2} '{3}' because {2} contains a '{4}' character.
@@ -168,7 +171,16 @@
Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a whitespace {2}.
-
+
+ Invalid tag helper bound property '{0}.{1}'. Tag helpers cannot bind to HTML attributes with a null or empty name.
+
+
+ Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null or empty if property has no public setter.
+
+
+ Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must not be null if property has no public setter and its type implements '{4}'.
+
+
Invalid tag helper bound property '{0}.{1}'. '{2}.{3}' must be null unless property type implements '{4}'.
diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/HtmlAttributeNameAttribute.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/HtmlAttributeNameAttribute.cs
index f22fb4b40f..07e0649a6b 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/HtmlAttributeNameAttribute.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/HtmlAttributeNameAttribute.cs
@@ -13,23 +13,41 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
private string _dictionaryAttributePrefix;
+ ///
+ /// Instantiates a new instance of the class with
+ /// equal to null.
+ ///
+ ///
+ /// Associated property must not have a public setter and must be compatible with
+ /// where TKey is
+ /// .
+ ///
+ public HtmlAttributeNameAttribute()
+ {
+ }
+
///
/// Instantiates a new instance of the class.
///
- /// HTML attribute name for the associated property.
+ ///
+ /// HTML attribute name for the associated property. Must be null or empty if associated property does
+ /// not have a public setter and is compatible with
+ /// where TKey is
+ /// . Otherwise must not be null or empty.
+ ///
public HtmlAttributeNameAttribute(string name)
{
- if (string.IsNullOrEmpty(name))
- {
- throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(name));
- }
-
Name = name;
}
///
/// HTML attribute name of the associated property.
///
+ ///
+ /// null or empty if and only if associated property does not have a public setter and is compatible
+ /// with where TKey is
+ /// .
+ ///
public string Name { get; }
///
@@ -42,9 +60,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// .
///
///
+ ///
/// If associated property is compatible with
/// , default value is Name + "-".
+ /// must not be null or empty in this case.
+ ///
+ ///
/// Otherwise default value is null.
+ ///
///
public string DictionaryAttributePrefix
{
diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorFactory.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorFactory.cs
index e6ce710d9e..df6e13d3a9 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorFactory.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorFactory.cs
@@ -256,45 +256,72 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
bool designTime,
ErrorSink errorSink)
{
- var accessibleProperties = type.GetRuntimeProperties().Where(IsAccessibleProperty);
var attributeDescriptors = new List();
// Keep indexer descriptors separate to avoid sorting the combined list later.
var indexerDescriptors = new List();
+ var accessibleProperties = type.GetRuntimeProperties().Where(IsAccessibleProperty);
foreach (var property in accessibleProperties)
{
var attributeNameAttribute = property.GetCustomAttribute(inherit: false);
- var descriptor = ToAttributeDescriptor(property, attributeNameAttribute, designTime);
- if (ValidateTagHelperAttributeDescriptor(descriptor, type, errorSink))
+ var hasExplicitName =
+ attributeNameAttribute != null && !string.IsNullOrEmpty(attributeNameAttribute.Name);
+ var attributeName = hasExplicitName ? attributeNameAttribute.Name : ToHtmlCase(property.Name);
+
+ TagHelperAttributeDescriptor mainDescriptor = null;
+ if (property.SetMethod?.IsPublic == true)
{
- bool isInvalid;
- var indexerDescriptor = ToIndexerAttributeDescriptor(
- property,
- attributeNameAttribute,
- parentType: type,
- errorSink: errorSink,
- defaultPrefix: descriptor.Name + "-",
- designTime: designTime,
- isInvalid: out isInvalid);
-
- if (indexerDescriptor != null &&
- !ValidateTagHelperAttributeDescriptor(indexerDescriptor, type, errorSink))
+ mainDescriptor = ToAttributeDescriptor(property, attributeName, designTime);
+ if (!ValidateTagHelperAttributeDescriptor(mainDescriptor, type, errorSink))
{
- isInvalid = true;
- }
-
- if (isInvalid)
- {
- // HtmlAttributeNameAttribute was not valid. Ignore this property completely.
+ // HtmlAttributeNameAttribute.Name is invalid. Ignore this property completely.
continue;
}
+ }
+ else if (hasExplicitName)
+ {
+ // Specified HtmlAttributeNameAttribute.Name though property has no public setter.
+ errorSink.OnError(
+ SourceLocation.Zero,
+ Resources.FormatTagHelperDescriptorFactory_InvalidAttributeNameNotNullOrEmpty(
+ type.FullName,
+ property.Name,
+ typeof(HtmlAttributeNameAttribute).FullName,
+ nameof(HtmlAttributeNameAttribute.Name)));
+ continue;
+ }
- attributeDescriptors.Add(descriptor);
- if (indexerDescriptor != null)
- {
- indexerDescriptors.Add(indexerDescriptor);
- }
+ bool isInvalid;
+ var indexerDescriptor = ToIndexerAttributeDescriptor(
+ property,
+ attributeNameAttribute,
+ parentType: type,
+ errorSink: errorSink,
+ defaultPrefix: attributeName + "-",
+ designTime: designTime,
+ isInvalid: out isInvalid);
+ if (indexerDescriptor != null &&
+ !ValidateTagHelperAttributeDescriptor(indexerDescriptor, type, errorSink))
+ {
+ isInvalid = true;
+ }
+
+ if (isInvalid)
+ {
+ // The property type or HtmlAttributeNameAttribute.DictionaryAttributePrefix (or perhaps the
+ // HTML-casing of the property name) is invalid. Ignore this property completely.
+ continue;
+ }
+
+ if (mainDescriptor != null)
+ {
+ attributeDescriptors.Add(mainDescriptor);
+ }
+
+ if (indexerDescriptor != null)
+ {
+ indexerDescriptors.Add(indexerDescriptor);
}
}
@@ -309,9 +336,26 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Type parentType,
ErrorSink errorSink)
{
- var nameOrPrefix = attributeDescriptor.IsIndexer ?
- Resources.TagHelperDescriptorFactory_Prefix :
- Resources.TagHelperDescriptorFactory_Name;
+ string nameOrPrefix;
+ if (attributeDescriptor.IsIndexer)
+ {
+ nameOrPrefix = Resources.TagHelperDescriptorFactory_Prefix;
+ }
+ else if (string.IsNullOrEmpty(attributeDescriptor.Name))
+ {
+ errorSink.OnError(
+ SourceLocation.Zero,
+ Resources.FormatTagHelperDescriptorFactory_InvalidAttributeNameNullOrEmpty(
+ parentType.FullName,
+ attributeDescriptor.PropertyName));
+
+ return false;
+ }
+ else
+ {
+ nameOrPrefix = Resources.TagHelperDescriptorFactory_Name;
+ }
+
return ValidateTagHelperAttributeNameOrPrefix(
attributeDescriptor.Name,
parentType,
@@ -329,8 +373,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
if (string.IsNullOrEmpty(attributeNameOrPrefix))
{
- // HtmlAttributeNameAttribute validates Name is non-null and non-empty. Both are valid for
- // DictionaryAttributePrefix. (Empty DictionaryAttributePrefix is a corner case which would bind every
+ // ValidateTagHelperAttributeDescriptor validates Name is non-null and non-empty. The empty string is
+ // valid for DictionaryAttributePrefix and null is impossible at this point because it means "don't
+ // create a descriptor". (Empty DictionaryAttributePrefix is a corner case which would bind every
// attribute of a target element. Likely not particularly useful but unclear what minimum length
// should be required and what scenarios a minimum length would break.)
return true;
@@ -388,13 +433,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private static TagHelperAttributeDescriptor ToAttributeDescriptor(
PropertyInfo property,
- HtmlAttributeNameAttribute attributeNameAttribute,
+ string attributeName,
bool designTime)
{
- var attributeName = attributeNameAttribute != null ?
- attributeNameAttribute.Name :
- ToHtmlCase(property.Name);
-
return ToAttributeDescriptor(
property,
attributeName,
@@ -413,6 +454,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
out bool isInvalid)
{
isInvalid = false;
+ var hasPublicSetter = property.SetMethod?.IsPublic == true;
var dictionaryTypeArguments = ClosedGenericMatcher.ExtractGenericInterface(
property.PropertyType,
typeof(IDictionary<,>))
@@ -426,13 +468,44 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
isInvalid = true;
errorSink.OnError(
SourceLocation.Zero,
- Resources.FormatTagHelperDescriptorFactory_InvalidAttributePrefix(
+ Resources.FormatTagHelperDescriptorFactory_InvalidAttributePrefixNotNull(
parentType.FullName,
property.Name,
nameof(HtmlAttributeNameAttribute),
nameof(HtmlAttributeNameAttribute.DictionaryAttributePrefix),
"IDictionary"));
}
+ else if (attributeNameAttribute != null && !hasPublicSetter)
+ {
+ // Associated an HtmlAttributeNameAttribute with a non-dictionary property that lacks a public
+ // setter.
+ isInvalid = true;
+ errorSink.OnError(
+ SourceLocation.Zero,
+ Resources.FormatTagHelperDescriptorFactory_InvalidAttributeNameAttribute(
+ parentType.FullName,
+ property.Name,
+ nameof(HtmlAttributeNameAttribute),
+ "IDictionary"));
+ }
+
+ return null;
+ }
+ else if (!hasPublicSetter &&
+ attributeNameAttribute != null &&
+ !attributeNameAttribute.DictionaryAttributePrefixSet)
+ {
+ // Must set DictionaryAttributePrefix when using HtmlAttributeNameAttribute with a dictionary property
+ // that lacks a public setter.
+ isInvalid = true;
+ errorSink.OnError(
+ SourceLocation.Zero,
+ Resources.FormatTagHelperDescriptorFactory_InvalidAttributePrefixNull(
+ parentType.FullName,
+ property.Name,
+ nameof(HtmlAttributeNameAttribute),
+ nameof(HtmlAttributeNameAttribute.DictionaryAttributePrefix),
+ "IDictionary"));
return null;
}
@@ -482,9 +555,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private static bool IsAccessibleProperty(PropertyInfo property)
{
- // Accessible properties are those with public getters and setters and without [HtmlAttributeNotBound].
+ // Accessible properties are those with public getters and without [HtmlAttributeNotBound].
return property.GetMethod?.IsPublic == true &&
- property.SetMethod?.IsPublic == true &&
property.GetCustomAttribute(inherit: false) == null;
}
diff --git a/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs b/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs
index 1345e2b627..b717e43638 100644
--- a/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs
+++ b/src/Microsoft.AspNet.Razor/Properties/RazorResources.Designer.cs
@@ -1286,22 +1286,6 @@ namespace Microsoft.AspNet.Razor
return string.Format(CultureInfo.CurrentCulture, GetString("TagHelpers_CannotHaveCSharpInTagDeclaration"), p0);
}
- ///
- /// A TagHelperChunkGenerator must only be used with TagHelperBlocks.
- ///
- internal static string TagHelpers_TagHelperCodeGeneartorMustBeAssociatedWithATagHelperBlock
- {
- get { return GetString("TagHelpers_TagHelperCodeGeneartorMustBeAssociatedWithATagHelperBlock"); }
- }
-
- ///
- /// A TagHelperChunkGenerator must only be used with TagHelperBlocks.
- ///
- internal static string FormatTagHelpers_TagHelperCodeGeneartorMustBeAssociatedWithATagHelperBlock()
- {
- return GetString("TagHelpers_TagHelperCodeGeneartorMustBeAssociatedWithATagHelperBlock");
- }
-
///
/// Directive '{0}' must have a value.
///
diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorFactoryTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorFactoryTest.cs
index 9d66a23d0d..b4c2170f18 100644
--- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorFactoryTest.cs
+++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperDescriptorFactoryTest.cs
@@ -958,7 +958,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
isStringProperty: false,
designTimeDescriptor: null),
new TagHelperAttributeDescriptor(
- name: "valid-prefix",
+ name: "valid-name-",
propertyName: nameof(SingleValidHtmlAttributePrefix.DictionaryProperty),
typeName: typeof(string).FullName,
isIndexer: true,
@@ -1048,6 +1048,20 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
isIndexer: true,
isStringProperty: false,
designTimeDescriptor: null),
+ new TagHelperAttributeDescriptor(
+ name: "get-only-dictionary-property-",
+ propertyName: nameof(MultipleValidHtmlAttributePrefix.GetOnlyDictionaryProperty),
+ typeName: typeof(int).FullName,
+ isIndexer: true,
+ isStringProperty: false,
+ designTimeDescriptor: null),
+ new TagHelperAttributeDescriptor(
+ name: "valid-prefix6",
+ propertyName: nameof(MultipleValidHtmlAttributePrefix.GetOnlyDictionaryPropertyWithAttributePrefix),
+ typeName: typeof(string).FullName,
+ isIndexer: true,
+ isStringProperty: true,
+ designTimeDescriptor: null),
},
new string[0]
},
@@ -1087,6 +1101,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
onError(
typeof(MultipleInvalidHtmlAttributePrefix).FullName,
nameof(MultipleInvalidHtmlAttributePrefix.DictionaryOfIntSubclassProperty)),
+ onError(
+ typeof(MultipleInvalidHtmlAttributePrefix).FullName,
+ nameof(MultipleInvalidHtmlAttributePrefix.GetOnlyDictionaryAttributePrefix)),
+ $"Invalid tag helper bound property '{ typeof(MultipleInvalidHtmlAttributePrefix).FullName }." +
+ $"{ nameof(MultipleInvalidHtmlAttributePrefix.GetOnlyDictionaryPropertyWithAttributeName) }'. " +
+ $"'{ typeof(HtmlAttributeNameAttribute).FullName }." +
+ $"{ nameof(HtmlAttributeNameAttribute.Name) }' must be null or empty if property has " +
+ "no public setter.",
}
},
};
@@ -1128,14 +1150,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
TagHelperAttributeDescriptorComparer.Default);
}
- public static TheoryData ValidAttributeNameOrPrefixData
+ public static TheoryData ValidAttributeNameData
{
get
{
return new TheoryData
{
- null,
- string.Empty,
"data",
"dataa-",
"ValidName",
@@ -1147,7 +1167,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
[Theory]
- [MemberData(nameof(ValidAttributeNameOrPrefixData))]
+ [MemberData(nameof(ValidAttributeNameData))]
public void ValidateTagHelperAttributeDescriptor_WithValidName_ReturnsTrue(string name)
{
// Arrange
@@ -1170,8 +1190,25 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Empty(errorSink.Errors);
}
+ public static TheoryData ValidAttributePrefixData
+ {
+ get
+ {
+ return new TheoryData
+ {
+ string.Empty,
+ "data",
+ "dataa-",
+ "ValidName",
+ "valid-name",
+ "--valid--name--",
+ ",,--__..oddly.valid::;;",
+ };
+ }
+ }
+
[Theory]
- [MemberData(nameof(ValidAttributeNameOrPrefixData))]
+ [MemberData(nameof(ValidAttributePrefixData))]
public void ValidateTagHelperAttributeDescriptor_WithValidPrefix_ReturnsTrue(string prefix)
{
// Arrange
@@ -1732,7 +1769,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private class SingleValidHtmlAttributePrefix : TagHelper
{
- [HtmlAttributeName("valid-name", DictionaryAttributePrefix = "valid-prefix")]
+ [HtmlAttributeName("valid-name")]
public IDictionary DictionaryProperty { get; set; }
}
@@ -1755,6 +1792,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
[HtmlAttributeName("valid-name6")]
public string StringProperty { get; set; }
+
+ public IDictionary GetOnlyDictionaryProperty { get; }
+
+ [HtmlAttributeName(DictionaryAttributePrefix = "valid-prefix6")]
+ public IDictionary GetOnlyDictionaryPropertyWithAttributePrefix { get; }
}
private class SingleInvalidHtmlAttributePrefix : TagHelper
@@ -1779,6 +1821,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
[HtmlAttributeName("valid-name5", DictionaryAttributePrefix = "valid-prefix5-")]
public DictionaryOfIntSubclass DictionaryOfIntSubclassProperty { get; set; }
+
+ [HtmlAttributeName(DictionaryAttributePrefix = "valid-prefix6")]
+ public IDictionary GetOnlyDictionaryAttributePrefix { get; }
+
+ [HtmlAttributeName("invalid-name7")]
+ public IDictionary GetOnlyDictionaryPropertyWithAttributeName { get; }
}
private class DictionarySubclass : Dictionary