Control format of Guid using xml serializer - c#

I have a problem controlling how the xml serializer formats a Guid.
is there anyway to force the property of the first example to exclude the dashes, using the XmlSerialzer?
example:
public class Example{
[XmlElement]
public Guid Value {get; set;}
}
when serializing the above class i would get: (36 characters)
<Example>
<Value>3164fc09-1dc5-4629-b04c-e9cdc5e85de4</Value>
</Example>
but i want the value not to include dashes (32 characters)
<Example>
<Value>06102471381242609d0176b269120082</Value>
</Example>
normally i would not care about the difference, but in this particular case i don't have a choice as i have to follow a standard provided by a third party that includes a set of xsd's.
I know i can do something like this to solve the problem, but it is messy and i would like to avoid it:
public class Example
{
[XmlIgnore]
public Guid Value { get; set; }
[XmlElement(nameof(Value))]
public string ValueString {
get => Value.ToString("N");
set
{
if (Guid.TryParse(value, out var uuid))
Value = uuid;
else
throw new InvalidOperationException();
}
}
}
Provided xsd
the xsd provided by this company define the custom type to be a string with a range of 1 to 35 characters, but their documentation states that the value should always be a uuid version 4 with no dashes and 32 characters long.
the documentation provided only have a danish version.
See page 5 sekt 01.07.2016 UUID i EpisodeOfCareIdentifier for the specific problem.
about the standard (optional reading):
This standard is part of a message service between counties, hospitals and other independent healthcare specialists, regarding patient treatments.
All in all there is quite a few software systems that have to implement this standard.

Related

Is there a way to validate that the xml serialization attributes on my classes and properties conform to an xsd schema?

Is there a built-in (or 3rd party) mechanism/library/analyzer that can be used to validate that the xml serialization attributes on a class/property matches the schema.
I know that you can't do full schema validation without an actual materialized document, but in theory you should be able to validate:
element names match
namespace names match
property types match
property types have the correct nullability
property types have RequiredAttribute or new required accessor if the property is required
property types have the correct data annotations (min/max values for numeric types for example)
enum types have valid values and names
array types have valid maxOccures (>=2 or unbounded)
This is by no means a complete list, but just some examples. I am also looking for something similar for json serializable types.
The reason I would like this ability is that we have several systems we integrate with that built custom xsd's that dont work well with any of the code-generators. While I could do standard schema validation, I would need to materialize a ton of different xml documents (null vs not null, too many records in an array, etc). What I am hoping to do is:
[Fact]
public void FooRequest_ConformsToXsdSchema() {
SchemaSet schemas = LoadSchemaSet("FooRequest.xsd");
XmlTypeValidator validator = LoadValidator(schemas);
var result = validator.ValidateTypeConformsToSchema<FooRequest>();
result.ConformsToSchema.Should().BeTrue();
}
[Serializable]
[XmlRoot("FooRequest", Namespace = "urn:FooRequest")]
class FooRequest {
[XmlElement("FooName"), Required, MinLength(3), MaxLength(50)]
required public string Name { get; init; }
[XmlElement("FooDescription"), MinLength(10), MaxLength(200)]
public string? Description { get; set; }
[XmlArray("Items"), [XmlArrayItem("Item"), Required]
public ICollection<FooItem> Items { get; set; } = new List<FooItem>();
}
[Serializable]
[XmlType("Item")]
class FooItem {
[XmlElement("name"), Required, MinLength(3), MaxLength(50)]
required public string Name { get; init; }
}
Another great option would be a Roslyn Analyzer.
Anything that can give us build or test errors letting us know if the .NET types do or don't conform the the schema.
Thanks!

XmlDeserialize cdata and its siblings

I'm in the process of deserializing into C# objects a custom inflexible XML schema to traverse and migrate the data within.
A brief example:
<Source>
...
<Provider>
<![CDATA[read 1]]>
<Identifier><![CDATA[read 2]]></Identifier>
<IdentificationScheme><![CDATA[read 3]]></IdentificationScheme>
</Provider>
...
</Source>
I'm looking the deserialize the Provider element with the first CDATA element value, read 1, and it's sibling element values too, read 2 and read 3.
Using http://xmltocsharp.azurewebsites.net/ it produces the following objects:
[XmlRoot(ElementName = "Provider")]
public class Provider
{
[XmlElement(ElementName = "Identifier")]
public string Identifier { get; set; }
[XmlElement(ElementName = "IdentificationScheme")]
public string IdentificationScheme { get; set; }
}
[XmlRoot(ElementName = "Source")]
public class Source
{
[XmlElement(ElementName = "Provider")]
public Provider Provider { get; set; }
}
But it fails to account for the the CDATA value, in fact I think deserializing it like this the value would not be reachable.
I think this maybe also be related to the XmlDeserializer to use, I was planning on RestSpharp's (as it's a library to the website already) or System.Xml.Link.XDocument, but I'm not sure whether either can handle this scenario?
In my searches I couldn't find an example either, but stack did suggest this <!{CDATA[]]> and <ELEMENT> in a xml element that is precisely the same schema option.
Thanks so much for any help in advance,
EDIT 1
As far as I can tell the [XmlText] is the solution required, as pointed out in Marc Gravell's answer below, but it does not work/is implemented on RestSharp's XmlDeserializer, but further testing would be required to ascertain that for sure.
The CDATA is essentially just escaping syntax and is handled by most readers. What you are looking for is:
[XmlText]
public string WhateverThisIs { get; set; }
on the object that has raw content. By adding that to Provider, WhateverThisIs gets the value of "read 1". The other 2 properties already deserialize correctly as "read 2" and "read 3" without you having to do anything.
For reference, everything here would behave almost the same without the CDATA (there are some whitespace issues):
<Provider>
read 1
<Identifier>read 2</Identifier>
<IdentificationScheme>read 3</IdentificationScheme>
</Provider>

Aspnet Mvc decimal serialization error

I have a post method that accepts object containing decimal property as below
[HttpPost]
public async Task<IActionResult> Create(CreateDto createDto)
{
...do stuff here
}
public class CreateDto
{
[Required]
public string Id{ get; set; }
[Required]
public decimal? Rate{ get; set; }
}
when a value containing leading 0 being passed in for Rate field, eg: 0015, it is always coming in as 10.
Would appreciate if somebody could explain this phenomena.
The issue lies within aspnet core mvc JSON parser which allows leading zeros before numbers that are all in the range [0-7], and treats them as octal, to match the sort of results one would get using eval in javascript.
This behaviour contradicts with guildlines stated in on http://json.org:
"A number is very much like a C or Java number, except that the octal
and hexadecimal formats are not used."
and the syntax graph does not allow a number to have a leading non-significant zero.
RFC 4627 Section 2.4. agrees:
"Octal and hex forms are not allowed. Leading zeros are not allowed."
So in short, the only way is to use JSON parser that implements the Json specs correctly.
Reference: Override Json deserializing a number with a leading zero as a decimal and not an octal value

Why is The XML Serializer appending characters to my XmlAttribute?

Here is my property:
/// <summary>
/// The Business Unit
/// </summary>
[XmlAttribute("ows_Business_x0020_Unit")]
public string BusinessUnit { get; set; }
When I call Serialize on the object that has BusinessUnit I get:
ows_Business_x005F_x0020_Unit=\"Hi\"
Where does the _x005F come from?
It's an escape sequence. The _x0020 is actually another escape sequence for a space, so it's trying to escape the escape sequence so it doesn't get confused that you literally want the escape sequence, not the unescape value. So your attribute should look like this:
public class MyClass
{
[XmlAttribute("ows_Business Unit")]
public string BusinessUnit { get; set; }
}
That will serialize the attribute as ows_Business_x0020_Unit.
Microsoft encodes certain characters as _xZZZ_, so any names that look like _xZZZ_ get escaped. They chose to handle this by searching for "_x" and encoding the underscore as _x005F.
Your life will be easier if you avoid including "_x" in any of your names.

Read validation attribute from Object

I have an object which has properties decorated with Validation attributes. My validation is working correctly, however I need an additional method which performs string manipulation based on those attributes.
Consider the following object:
public class Pupil
{
/// <summary>
///
/// </summary>
public Pupil()
{
}
[NotNullValidator]
[StringLengthValidator(0, 54, MessageTemplate = "Invalid value '{0}' for {1}, Max length: {5}")]
public string Name{ get; set; }
[NotNullValidator]
[StringLengthValidator(0, 2, MessageTemplate = "Invalid value '{0}' for {1}, Max length: {5}")]
public string Gender{ get; set; }
}
I want to be able to manipulate the "Name" based on the StringLengthValidator attribute and its arguments. For example:
///Takes a Pupil object in
public static void DoManipulation(object value)
{
foreach(var property in value.GetType().GetProperties())
{
if(property.Name == "Name")
{
var att = property.GetCustomAttributes(typeof(StringLengthValidator), false);
var length = ((StringLengthValidator)att[0]).UpperBound;
}
}
}
The value of "length" is coming up as null, rather than 54. How do I get the value out?
Hopefully this makes sense, thanks.
A
This works for me, are you getting the same StringLengthValidator attribute that you think you are? (is this your custom class or the one from Enterprise Lib?
In my case, I created a custom class StringLengthValidator
The idea behind all this is that the value 54 can be changed, right? Otherwise you could just hard code 54.
Take a look on how to contol validation in the web.config with the tag so you can add the 54 to the web.config and read it from your application
Here is an example, look for the first approach, Rule sets in Configuration
As I was looking for it today with my co-worker and we did not find a proper solution to our problem, here is the answer, for the next one who is in trouble.
The attribute name is StringLengthValidator, but if you check at the class name it is StringLengthValidatorAttribute, so in order to get the proper attribute, you need to call the function GetCustomAttributes this way :
property.GetCustomAttributes(typeof(StringLengthValidatorAttribute), false)
This will fetch correctly the attribute and then you will be able to get the value of UpperBound

Categories

Resources