Skip to content

Wrong Exception Text for duplicate JsonConstructorAttribute #55321

@Tornhoof

Description

@Tornhoof

Description

If you apply the [JsonConstructorAttribute] to more than one constructor, the runtime exception is:

System.InvalidOperationException
  HResult=0x80131509
  Message=The type 'ConsoleApp11.Program+Invoice' cannot have more than one property that has the attribute 'System.Attribute'.
  Source=System.Text.Json
  StackTrace:
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute[TAttribute](Type classType)
   at System.Text.Json.Serialization.Converters.ObjectConverterFactory.GetDeserializationConstructor(Type type)
   at System.Text.Json.Serialization.Converters.ObjectConverterFactory.CreateConverter(Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonConverterFactory.GetConverterInternal(Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializerOptions.GetConverterInternal(Type typeToConvert)
   at System.Text.Json.JsonSerializerOptions.DetermineConverter(Type parentClassType, Type runtimePropertyType, MemberInfo memberInfo)
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo.GetConverter(Type type, Type parentClassType, MemberInfo memberInfo, Type& runtimeType, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializerOptions.<RootBuiltInConvertersAndTypeInfoCreator>g__CreateJsonTypeInfo|107_0(Type type, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializerOptions.GetClassFromContextOrCreate(Type type)
   at System.Text.Json.JsonSerializerOptions.GetOrAddClass(Type type)
   at System.Text.Json.JsonSerializerOptions.GetOrAddClassForRootType(Type type)
   at System.Text.Json.JsonSerializer.GetTypeInfo(Type runtimeType, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.Write[TValue](TValue& value, Type runtimeType, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options)

The Exception text is wrong:

  • The attribute is not applied to properties at all
  • The attribute type should reference the concrete type, not the base Attribute type.

The error message template should probably just be changed to say member instead of property.
The Throwhelper:

public static void ThrowInvalidOperationException_SerializationDuplicateTypeAttribute<TAttribute>(Type classType)
{
throw new InvalidOperationException(SR.Format(SR.SerializationDuplicateTypeAttribute, classType, typeof(Attribute)));
}

should be changed to use typeof(TAttribute) instead of typeof(Attribute) (I guess that was a typo).

This was found while looking at: #55318

Regression?

No, appears to happen in 5.0 too.

Other information

Repro:

	class Program
	{
		static void Main(string[] args)
		{
			var invoice = new Invoice(new List<InvoiceItem>());
			var serialized = JsonSerializer.Serialize(invoice);
			var deserialized = JsonSerializer.Deserialize<Invoice>(serialized);
		}

		public class Invoice
		{
			private List<InvoiceItem> items;

			public IReadOnlyCollection<InvoiceItem> Items => items;

			[JsonConstructor]
			public Invoice(List<InvoiceItem> items)
			{
				this.items = items;
			}

			[JsonConstructor]
			[Obsolete]
			public Invoice(IReadOnlyCollection<InvoiceItem> items)
			{
				this.items = items as List<InvoiceItem> ?? this.items.ToList();
			}


			public void AddItem(InvoiceItem invoiceItem)
			{
				//Some domain logic validation
				items.Add(invoiceItem);
			}
		}

		public class InvoiceItem
		{ }
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-System.Text.JsonenhancementProduct code improvement that does NOT require public API changes/additions

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions