I have a class that represents credit card details. To represent valid from and expiration months and years I am using four properties of type int:
public int ValidFromMonth { get; set; } public int ValidFromYear { get; set; } public int ExpiresEndMonth { get; set; } public int ExpiresEndYear { get; set; }
I am XML Serializing this class for consumption by a third party. That third party requires my month and year values to be prefixed with a leading zero if the value is less than 10
<validFromMonth>02</validFromMonth> <validFromYear>09</validFromYear> <expiresEndMonth>10</expiresEndMonth> <expiresEndYear>14</expiresEndYear>
Does .NET support any attribution (or is it possible for me to create a custom attribute) that will enforce this rule, possibly using a format string (e.g. {0:00})?
Note: I know that I could add my own string properties that do the formatting internally, and add an [XmlIgnore] attribute to my int properties, but this feels like a second-rate solution.
Edit: After some consideration I am wondering if this is actually just not feasible. Serialization would be no problem, but in order for deserialization to work you would need to un-format the serialized string. In the trivial example above this would be easy, but I am not sure that it could be made to work in the more general case.
Edit2: The XML Schema that defines the two-digit requirement is below.
Simple type definitions:
<xs:simpleType name='CreditCardMonthType'> <xs:annotation> <xs:documentation>Two digit month</xs:documentation> </xs:annotation> <xs:restriction base='xs:string'> <xs:minLength value='2' /> <xs:maxLength value='2' /> </xs:restriction> </xs:simpleType> <xs:simpleType name='CreditCardYearType'> <xs:annotation> <xs:documentation>Two digit year</xs:documentation> </xs:annotation> <xs:restriction base='xs:string'> <xs:minLength value='2' /> <xs:maxLength value='2' /> </xs:restriction> </xs:simpleType>
Credit card definition that uses these types:
<xs:attribute name='ExpiryMonth' type='CreditCardMonthType' use='required'> <xs:annotation> <xs:documentation>Credit/debt card's expiry month.</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name='ExpiryYear' type='CreditCardYearType' use='required'> <xs:annotation> <xs:documentation>Credit/debt card's expiry year.</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name='StartMonth' type='CreditCardMonthType' use='optional'> <xs:annotation> <xs:documentation>Switch card's start month.</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name='StartYear' type='CreditCardYearType' use='optional'> <xs:annotation> <xs:documentation>Switch card's start year.</xs:documentation> </xs:annotation> </xs:attribute>
OK, ignore my previous code sample (I’ll leave it up since it might help somebody else, though). I just remembered you can do this using XmlEnumAttribute:
and then change your usage to the enum:
This is actually a very nice way since you now have an enum for the month (which is really what you should’ve done from the beginning).