XML Serialization in practice: Preparing The Central Bank Service

In the second part of our article, we will get acquainted with XML serialization and look at using the Central Bank's XML service in real practice. In part 1 of the article, you can learn what serialization, deserialization, and Binary serialization are.

At XML serialization, the class must have an empty constructor, and the class members to be serialized must be specified with the public access modifier.

PS  Download the source code from here. Please star it if you like.

XMLSerializer class is used during XML serialization. This class resides in tystem.Xml.Serialization namespace. The XmlSerializer class accepts the class of the object to serialize as an argument from the constructor. Example: If we are going to serialize the Person class, then we should write like this:

[Serializable]
public class User
{
    [XmlElement(AttributeName = "Identifier")]
    public int Id { get; set; }
    [XmlElement(ElementName = "User_Name")]
    public string UserName { get; set; }

    [XmlElement]
    public string Email { get; set; }
    [XmlElement(ElementName = "Parol")]
    public string Password { get; set; }


    public bool IsLocked { get; set; }

    public override string ToString()
    {
        return $"{Id} {UserName} {Password} {IsLocked}";
    }
}

During serialization, the public properties of the class are converted to XML elements by default. If we do not specify any attribute on the properties of the class, the [XmlElement] attribute is given by default. Suppose we want to distinguish between the properties of the class and the names of the XML elements. In that case, we need to write the XmlElement attribute on each property that needs to be distinguished and name the property using AttributeName.

//instanciate the class
User user = new User
{
    Email = "[email protected]",
    Id = 1,
    IsLocked = false,
    Password = "23423rd@#$s",
    UserName = "Midoriya"
};

//serialize the object...
XmlSerializer serializer = new XmlSerializer(typeof(User));
using(FileStream fs = new FileStream("demo.xml",FileMode.OpenOrCreate))
{
    serializer.Serialize(fs, user);
}

And the result is :

"1.0"?>
<User xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Identifier>1Identifier>
  <User_Name>MidoriyaUser_Name>
  <Email>[email protected]>
  <Parol>23423rd@#$sParol>
  <IsLocked>falseIsLocked>
User>

URLwe wants the result of any property in the given class to be converted into an XML attribute, then we should use an attribute called XmlAttribute.

public class User
{
    [XmlAttribute(AttributeName = "Identifier")]
    public int Id { get; set; }
    ..........
}

Here is the serialization code

The result will be:

 "1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema" Identifier="3" Age="45">
  <Name>TodorokiName>
  <Email>[email protected]>
Person>

To implement XmlSerialization in actual practice, we will use the real service provided by the central bank of Azerbaijan. (CbarService project at our github address) Through this service, you can get currency data for a given date.

For example, if we want to get currency data for 09.06.2019, we should use https://www.cbar.az/currencies/06.09.2019.xml. After the date is given in the program that we will write, the information corresponding to that date will be reflected on the screen.

To perform Xml Serialization, we first access the URL address and get information about the XML structure. The picture below shows a small fragment of that service.

The class hierarchy we will model is directly related to the XML coming to us from the URL. Therefore, you need to be very careful when modeling classes.

After viewing the URL, we create a class structure like this.

[Serializable]
public class Valute
 {
     [XmlAttribute]
     public string Code { get; set; }
     public string Nominal { get; set; }
     public string Name { get; set; }
     public decimal Value { get; set; }
     public override string ToString()
     {
         return $"{Name}   --   {Value} ";
     }
 }

[Serializable]
public class ValuteType
{
     [XmlAttribute]
     public string Type { get; set; }

     [XmlElement(ElementName ="Valute")]
     public Valute[] Valutes { get; set; }
}

[Serializable]
[XmlRoot(ElementName ="ValCurs")]
public class ValuteCur
{
     [XmlAttribute]
     public string Date { get; set; }
     [XmlAttribute]
     public string Name { get; set; }
     [XmlAttribute]
     public string Description { get; set; }

     [XmlElement(ElementName ="ValType")]
     public ValuteType[] ValTypes { get; set; }

}

Since we have the ValuteCur class as the head element of the XML Structure, we mark it with the XmlRoot attribute. With this attribute, we can also rename a class at serialization time.

public class ServiceUrlBuilder
{
    private StringBuilder _url;
    public ServiceUrlBuilder()
    {
        _url = new StringBuilder();
    }
    public ServiceUrlBuilder AddBaseUrl(string baseUrl)
    {
        _url.Append(baseUrl);
        return this;
    }

    public ServiceUrlBuilder AddUrlSegment(string formatted)
    {
       string path = Path.Combine(_url.ToString(), formatted);
        _url.Clear();
        _url.Append(path);
        return this;
    }

    public ServiceUrlBuilder AddServiceExtension(string extension)
    {
        _url.Append($".{extension}");
        return this;
    }
    public string Build()
    {
        return _url.ToString();
    }
}

We allocate a specific class to set the service URL dynamically. (You can also enter the URL directly, you don't have to write such code)

Our ServiceUrlBuilder class will allow us to create our convenience URL. Considering that the model will change in the future, we write our service in a generic form.

public class CbarExchangeService : IExchangeService where T:class
{
   
    public async Task GetExchangeDatasByDate(DateTime dateTime)
    {
        T c = default;

        //building url for cbar
        string url = new ServiceUrlBuilder()
                            .AddBaseUrl(ConfigurationManager.AppSettings["baseUrl"])
                             .AddUrlSegment(dateTime.ToString("dd.MM.yyyy"))
                              .AddServiceExtension("xml")
                                 .Build();

        //preparing to serialize..
        XmlSerializer _xmlSerializer = new XmlSerializer(typeof(T));
        using (var serviceData = await new HttpClient().GetStreamAsync(url))
        {
            c = (T)_xmlSerializer.Deserialize(serviceData);
        }
        return c;
      
    }
}

In the end, our project will look like this:


Similar Articles