XmlSchemaClassGenerator icon indicating copy to clipboard operation
XmlSchemaClassGenerator copied to clipboard

Fixed values generate wrong C#

Open Ghostbird opened this issue 3 months ago • 4 comments

I've got an XSD with these lines in it:

…
<xs:element name="PROC-IDENT" type="xs:string" fixed="0013"/>
<xs:element name="PROC-FUNC" type="xs:string" fixed="01"/>
…

This generates:

	[XmlIgnoreAttribute()]
	private string procIdent = "0013";
	
	[RequiredAttribute(AllowEmptyStrings=true)]
	[XmlElementAttribute("PROC-IDENT", Form=XmlSchemaForm.Unqualified)]
	public string ProcIdent
	{
		get
		{
			return procIdent;
		}
		set
		{
			procIdent = value;
		}
	}
	
	[XmlIgnoreAttribute()]
	private string procFunc = "01";
	
	[RequiredAttribute(AllowEmptyStrings=true)]
	[XmlElementAttribute("PROC-FUNC", Form=XmlSchemaForm.Unqualified)]
	public string ProcFunc
	{
		get
		{
			return procFunc;
		}
		set
		{
			procFunc = value;
		}
	}

Whereas I would expect it to generate:

	[RequiredAttribute()]
	[XmlElementAttribute("PROC-IDENT", Form=XmlSchemaForm.Unqualified)]
	public string ProcIdent { get; } = "0013";

	[RequiredAttribute()]
	[XmlElementAttribute("PROC-FUNC", Form=XmlSchemaForm.Unqualified)]
	public string ProcFunc { get; } = "01";

Or if necessary for compatibility reasons, I'd expect it to generate:

	[RequiredAttribute()]
	[XmlElementAttribute("PROC-IDENT", Form=XmlSchemaForm.Unqualified)]
	public string ProcIdent { get => "0013"; set { } }

	[RequiredAttribute()]
	[XmlElementAttribute("PROC-FUNC", Form=XmlSchemaForm.Unqualified)]
	public string ProcFunc { get => "01"; set { } }

Is this caused by an error of mine, or is the fault on xscgen's side?

Ghostbird avatar Sep 17 '25 07:09 Ghostbird

I assume you're referring specifically to the private setter (or lack thereof). This may be an issue in xscgen but I'm not sure if XmlSerializer is happy with a private setter when deserializing. Have you checked that it works?

mganss avatar Sep 18 '25 11:09 mganss

I'm not sure whether this is the proper approach, but when I manually change the generated model to match the code below, it works without errors in case of a simple HTTP response deserialisation using new XmlSerializer(type).Deserialize(XmlReader.Create(await httpContent.ReadAsStreamAsync(cancellationToken)));

If I change one of the fixed values in the response XML, it still deserialises to the value of fixed in the XSD. That's fine by me, since I do not expect the remote system to violate the XSD specification they sent me. However, it might be desirable to throw in such a case instead.

[RequiredAttribute()]
[XmlElementAttribute("PROC-IDENT", Form=XmlSchemaForm.Unqualified)]
public string ProcIdent { get; } = "0013";

[RequiredAttribute()]
[XmlElementAttribute("PROC-FUNC", Form=XmlSchemaForm.Unqualified)]
public string ProcFunc { get; } = "01";

Alternative option to throw on violations (Note: The EnsureValue probably doesn't suffice for all use cases):

private void EnsureValue<T>(T fixedValue, T actualValue) {
	if (fixedValue is IEquatable<T> && !fixedValue.Equals(actualValue)) { throw new XmlException("Violation of fixed value!"); }
}

[RequiredAttribute()]
[XmlElementAttribute("PROC-IDENT", Form = XmlSchemaForm.Unqualified)]
public string ProcIdent { get => "0013"; set => EnsureValue(ProcIdent, value); }

[RequiredAttribute()]
[XmlElementAttribute("PROC-FUNC", Form = XmlSchemaForm.Unqualified)]
public string ProcFunc { get => "08"; set => EnsureValue(ProcFunc, value); }

[!NOTE] This is tested in .NET 9.0 I don't know whether the XmlSerializer in other versions behaves the same.

Ghostbird avatar Sep 19 '25 06:09 Ghostbird

What issue are you seeing with the original code? Does XmlSerializer set a different value?

mganss avatar Oct 02 '25 17:10 mganss

The information about the fixed value seems lost. But maybe I misunderstood, and the XML deserialisation is not meant to block deserialisation of invalid models?

It seems to me that I can deserialise a model which has invalid values for PROC-IDENT and PROC-FUNC and the fact that the model is not valid is lost.

Ghostbird avatar Oct 04 '25 12:10 Ghostbird