Click here to Skip to main content
Click here to Skip to main content
Go to top

ASP.NET Web API Generic HttpContent Reader and Serialization Helper

, 21 Aug 2013
Rate this:
Please Sign up or sign in to vote.
A generic HttpContent Reader that can be used to replace FromBody parameter on Http Action

Introduction

ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mobile devices. ASP.NET Web API is an ideal platform for building RESTful applications on the .NET Framework.

Learn here: http://www.asp.net/web-api

Background

By default, Parameter Binding in Web API only allows single [FromBody] parameter. This leads you to create multiple actions or route just to have a workaround.

More information on Parameter Binding can be found here.

If you have used action-based HTTP Route, then this should be suitable for you. Your routing should look something like this one below:

config.Routes.MapHttpRoute(
                name: "DefaultActionRoute",
                routeTemplate: "api/{controller}/{action}",
                defaults: new { id = RouteParameter.Optional },
                constraints: new { action = "[^\\.]+" }
            );

For example, you need an API URL that will cater to all POST requests and should be able to accept different objects for whatever reason your project or client required it.

URL:

  • /api/main/post

Acception Content Objects (XML/JSON):

  • ObjectOne
  • ObjectTwo
  • ObjectThree

This will not work:

public HttpResponseMessage Post([FromBody] ObjectOne  id, 
[FromBody] ObjectTwo name, [FromBody] ObjectThree name) { ... }  

To solve this problem, here are some of the handy codes you will need to use to Serialize the object from XML or JSON and the generic method for reading the content.

 public static class SerializationHelper
{
    /// <summary>
    /// The empty XML serializer namespace
    /// </summary>
    public static readonly XmlSerializerNamespaces EmptyXmlSerializerNamespace = 
    new XmlSerializerNamespaces(new[] { new XmlQualifiedName("") });

    /// <summary>
    /// Deserializes the json.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="jsonString">The json string.</param>
    /// <returns></returns>
    /// <exception cref="System.ArgumentNullException">jsonString</exception>
    public static T DeserializeJson<T>(string jsonString)
    {
        if (string.IsNullOrEmpty(jsonString))
        {
            throw new ArgumentNullException("jsonString");
        }

        return DeserializeJson<T>(new MemoryStream(Encoding.UTF8.GetBytes(jsonString)));
    }

    /// <summary>
    /// Deserializes the json.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="jsonStream">The json stream.</param>
    /// <returns></returns>
    /// <exception cref="System.ArgumentNullException">jsonStream</exception>
    public static T DeserializeJson<T>(Stream jsonStream)
    {
        var jsonSerializer = new DataContractJsonSerializer(typeof(T));

        if (jsonStream == null)
        {
            throw new ArgumentNullException("jsonStream");
        }

        return (T)jsonSerializer.ReadObject(jsonStream);
    }

    /// <summary>
    /// Serializes to json string.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <returns></returns>
    public static string SerializeToJsonString(object obj)
    {
        var jsonSerializer = new DataContractJsonSerializer(obj.GetType());
        using (MemoryStream buffer = new MemoryStream())
        {
            jsonSerializer.WriteObject(buffer, obj);
            return Encoding.UTF8.GetString(buffer.ToArray());
        }
    }

    /// <summary>
    /// Deserializes the XML.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="xmlString">The XML string.</param>
    /// <returns></returns>
    /// <exception cref="System.ArgumentNullException">xmlString</exception>
    public static T DeserializeXml<T>(string xmlString)
    {
        if (string.IsNullOrEmpty(xmlString))
        {
            throw new ArgumentNullException("xmlString");
        }

        return DeserializeXml<T>(new MemoryStream(Encoding.UTF8.GetBytes(xmlString)));
    }

    /// <summary>
    /// Deserializes the XML.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="xmlStream">The XML stream.</param>
    /// <returns></returns>
    /// <exception cref="System.ArgumentNullException">xmlStream</exception>
    public static T DeserializeXml<T>(Stream xmlStream)
    {
        var xmlSerializer = new XmlSerializer(typeof(T));

        if (xmlStream == null)
        {
            throw new ArgumentNullException("xmlStream");
        }

        return (T)xmlSerializer.Deserialize(xmlStream);
    }

    /// <summary>
    /// Serializes to XML string.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <returns></returns>
    public static string SerializeToXmlString(object obj)
    {
        XmlSerializer xs = new XmlSerializer(obj.GetType());
        using (MemoryStream buffer = new MemoryStream())
        {
            xs.Serialize(buffer, obj, EmptyXmlSerializerNamespace);
            return Encoding.UTF8.GetString(buffer.ToArray());
        }
    }

} 

If you have a base ApiController, you can include this generic method ReadContentAs<T>().

public abstract class BaseApiController : ApiController
{
    protected T ReadContentAs<T>()
    {
        if (Request.Content != null)
        {
            try
            {
                if (Request.Content.IsXmlContent())
                {
                    return SerializationHelper.DeserializeXml<T>(
                        Request.Content.ReadAsStreamAsync().Result);
                }

                if (Request.Content.IsJsonContent())
                {
                    return SerializationHelper.DeserializeJson<T>(
                        Request.Content.ReadAsStreamAsync().Result);
                }
            }
            catch
            {
                return default(T);
            }
        }
        return default(T);
    }
} 

Using the Code

Using the methods is easy. In your action method, simply call the ReadContentAs<T>() and voila!

public HttpResponseMessage Post()
{
    var details = ReadContentAs<ObjectOne>();
    //code here....
}   

You might need an identifier from the URL to match the content.

public HttpResponseMessage Post([FromUri] string command)
{
    switch (command)
    {
        case "add-objectone":
            var details = ReadContentAs<ObjectOne>();
            //do something here...
        case "add-objecttwo":
            var details = ReadContentAs<ObjectTwo>();
            //do something here...
    }
}

Points of Interest

I've been working full time for almost a year now using ASP.NET Web API and there are a few tricks I have learned to meet requirements of clients. I have noticed there are few posts I see on the web so I decided to create this and maybe help someone. This is my first time, so forgive my writing skills.

History

  • 8-21-2013 | Draft

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

karlodegrano
Web Developer
Philippines Philippines
Web Developer at Anxa Ltd and Hapilabs.com for Research and Development in ASP.Net.
Follow on   Twitter

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web03 | 2.8.140926.1 | Last Updated 21 Aug 2013
Article Copyright 2013 by karlodegrano
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid