diff --git a/src/CloudNative.CloudEvents/CloudEventAttributes.cs b/src/CloudNative.CloudEvents/CloudEventAttributes.cs index 49a46fb..a140db6 100644 --- a/src/CloudNative.CloudEvents/CloudEventAttributes.cs +++ b/src/CloudNative.CloudEvents/CloudEventAttributes.cs @@ -211,12 +211,21 @@ namespace CloudNative.CloudEvents void ICollection>.Add(KeyValuePair item) { object value = item.Value; + // Note: can't throw ArgumentNullException as the null value is only part of the argument. + if (value is null) + { + throw new InvalidOperationException(Strings.ErrorCannotAddNullAttributeValue); + } ValidateAndNormalize(item.Key, ref value); dict.Add(item.Key, value); } void IDictionary.Add(string key, object value) { + if (value is null) + { + throw new ArgumentNullException(nameof(value), Strings.ErrorCannotAddNullAttributeValue); + } ValidateAndNormalize(key, ref value); dict.Add(key, value); } @@ -266,7 +275,7 @@ namespace CloudNative.CloudEvents return dict.TryGetValue(key, out value); } - internal virtual bool ValidateAndNormalize(string key, ref object value) + private bool ValidateAndNormalize(string key, ref object value) { if (key.Equals(TypeAttributeName(this.SpecVersion), StringComparison.InvariantCultureIgnoreCase)) { @@ -297,7 +306,7 @@ namespace CloudNative.CloudEvents } else if (key.Equals(TimeAttributeName(this.SpecVersion), StringComparison.InvariantCultureIgnoreCase)) { - if (value is null || value is DateTime) + if (value is DateTime) { return true; } @@ -343,7 +352,7 @@ namespace CloudNative.CloudEvents } else if (key.Equals(DataSchemaAttributeName(this.SpecVersion), StringComparison.InvariantCultureIgnoreCase)) { - if (value is null || value is Uri) + if (value is Uri) { return true; } @@ -361,7 +370,7 @@ namespace CloudNative.CloudEvents } else if (key.Equals(DataContentTypeAttributeName(this.SpecVersion), StringComparison.InvariantCultureIgnoreCase)) { - if (value is null || value is ContentType) + if (value is ContentType) { return true; } diff --git a/src/CloudNative.CloudEvents/Strings.Designer.cs b/src/CloudNative.CloudEvents/Strings.Designer.cs index a56c94d..87ad78e 100644 --- a/src/CloudNative.CloudEvents/Strings.Designer.cs +++ b/src/CloudNative.CloudEvents/Strings.Designer.cs @@ -60,6 +60,15 @@ namespace CloudNative.CloudEvents { } } + /// + /// Looks up a localized string similar to Null values cannot be added as attributes. + /// + internal static string ErrorCannotAddNullAttributeValue { + get { + return ResourceManager.GetString("ErrorCannotAddNullAttributeValue", resourceCulture); + } + } + /// /// Looks up a localized string similar to The 'contenttype' attribute value must be a content-type expression compliant with RFC2046. /// diff --git a/src/CloudNative.CloudEvents/Strings.resx b/src/CloudNative.CloudEvents/Strings.resx index 209b1e4..35946d5 100644 --- a/src/CloudNative.CloudEvents/Strings.resx +++ b/src/CloudNative.CloudEvents/Strings.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Null values cannot be added as attributes + The 'contenttype' attribute value must be a content-type expression compliant with RFC2046 diff --git a/test/CloudNative.CloudEvents.UnitTests/CloudEventAttributesTest.cs b/test/CloudNative.CloudEvents.UnitTests/CloudEventAttributesTest.cs index e696a1b..c85e3fc 100644 --- a/test/CloudNative.CloudEvents.UnitTests/CloudEventAttributesTest.cs +++ b/test/CloudNative.CloudEvents.UnitTests/CloudEventAttributesTest.cs @@ -29,5 +29,22 @@ namespace CloudNative.CloudEvents.UnitTests string attributeName = CloudEventAttributes.SpecVersionAttributeName(); Assert.Throws(() => attributes[attributeName] = null); } + + [Fact] + public void Dictionary_Add_NullValue() + { + IDictionary attributes = new CloudEventAttributes(CloudEventsSpecVersion.Default, emptyExtensions); + string attributeName = CloudEventAttributes.TypeAttributeName(); + Assert.Throws(() => attributes.Add(attributeName, null)); + } + + [Fact] + public void Collection_Add_NullValue() + { + ICollection> attributes = new CloudEventAttributes(CloudEventsSpecVersion.Default, emptyExtensions); + string attributeName = CloudEventAttributes.TypeAttributeName(); + var pair = KeyValuePair.Create(attributeName, default(object)); + Assert.Throws(() => attributes.Add(pair)); + } } }