DevTech
DevTech

Reputation: 138

ServiceStack Parse Xml Request to Dictionary

One of our requirements is to have a decoupled architecture where we need to map data from one system to another, and the intermediate mapping is handled by a ServiceStack service request. Our issue is that a vendor can only provide data via Xml that does not conform to the standard dictionary request that ServiceStack offers like below:

  <Lead xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <d2p1:KeyValueOfstringstring>
      <d2p1:Key>String</d2p1:Key>
      <d2p1:Value>String</d2p1:Value>
    </d2p1:KeyValueOfstringstring>
  </Lead>

Instead they need a mechanism like:

<Lead>
  <LeadId>Value</LeadId>
  <FirstName>First Name</FirstName>
  <LastName>Last Name</LastName>
  ...
</Lead>

Since the nodes in their xml request may change over time, and we're simply acting as a middle-man, is there a native way to accept a dynamic request or handle this as Dictionary with data similar to what's below?

Dictionary<string, string>
{
    { "LeadId", "Value" },
    { "FirstName", "First Name" },
    { "LastName", "Last Name" }
    ...
};

Upvotes: 2

Views: 227

Answers (1)

mythz
mythz

Reputation: 143319

The default XML Serialization doesn't provide any way that you could transparently infer an XML fragment into a string dictionary so you're going to need to manually parse the XML which you can do in ServieStack by telling ServiceStack to skip built-in Serialization by implementing IRequiresRequestStream which ServiceStack will inject with the Request Stream so you can deserialize it yourself, e.g:

public class Lead : IRequiresRequestStream
{
    public Stream RequestStream { get; set; }
}

In your Service you'd then manually parse the raw XML and convert it to the data collections you want, e.g:

public class RawServices : Service
{
    public object Any(Lead request)
    {
         var xml = request.RequestStream.ReadFully().FromUtf8Bytes();

         var map = new Dictionary<string, string>();
         var rootEl = (XElement)XDocument.Parse(xml).FirstNode;

         foreach (var node in rootEl.Nodes())
         {
             var el = node as XElement;
             if (el == null) continue;
             map[el.Name.LocalName] = el.Value;
         }

         return new LeadResponse {
             Results = map
         }
    }
}

Upvotes: 2

Related Questions