Skip to content

Instantly share code, notes, and snippets.

@tonysneed
Last active March 29, 2024 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tonysneed/d7f6533e12e5f7e1c0fc to your computer and use it in GitHub Desktop.
Save tonysneed/d7f6533e12e5f7e1c0fc to your computer and use it in GitHub Desktop.
Serialization Helper for ASP.NET Web API
using System;
using System.Net.Http.Formatting;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using WebApiContrib.Formatting;
namespace WebApiContrib
{
public static class SerializationHelper
{
/// <summary>
/// Configure serializer for Json formatter to handle cyclical references.
/// </summary>
/// <param name="jsonFormatter">Json media type formatter</param>
public static void ConfigJsonSerializer(this BaseJsonMediaTypeFormatter jsonFormatter)
{
jsonFormatter.SerializerSettings.PreserveReferencesHandling =
PreserveReferencesHandling.All;
}
/// <summary>
/// Configure serializer for Xml formatter to handle cyclical references.
/// </summary>
/// <param name="xmlFormatter">Web API Xml Formatter.</param>
/// <param name="types">Types returned from controller actions.</param>
public static void ConfigXmlSerializer
(this XmlMediaTypeFormatter xmlFormatter, params Type[] types)
{
foreach (var type in types)
{
var serializer = new DataContractSerializer(type,
null, int.MaxValue, false, true, null);
xmlFormatter.SetSerializer(type, serializer);
}
}
/// <summary>
/// Configure ProtoBuf formatter to handle cyclical references.
/// </summary>
/// <param name="types"></param>
public static void ConfigProtoBufFormatter(params Type[] types)
{
foreach (var type in types)
{
var meta = ProtoBufFormatter.Model.Add(type, false);
var props = type.GetProperties();
for (var i = 0; i < props.Length; i++)
{
meta.Add(i + 1, props[i].Name);
}
meta.AsReferenceDefault = true;
}
}
}
}
@tonysneed
Copy link
Author

Three serialization helper methods for configuring json, xml and protobuf media type formatters to handle cyclical references. Note that the DataContractSerializer is configured on a per-type basis and requires concrete types returned by Api controller actions, for example, List instead of just T. The ProtoBuf formatter also requires per-type configuration, but configures entity types (T rather than List).

To use them you'll need the following NuGet packages:
Newtonsoft.Json
Microsoft.AspNet.WebApi.Client
WebApiContrib.Formatting.ProtoBuf

@tonysneed
Copy link
Author

Here is a sample WebApiConfig class that uses the serialization helper:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Handle cyclical references for xml
        config.Formatters.XmlFormatter.ConfigXmlSerializer
            (typeof(Category), typeof(List<Product>));

        // Handle cyclical references for json
        config.Formatters.JsonFormatter.ConfigJsonSerializer();

        // Handle cyclical references for bson
        var bsonFormatter = new BsonMediaTypeFormatter();
        bsonFormatter.ConfigJsonSerializer();
        config.Formatters.Add(bsonFormatter);

        // Handle cyclical references for protobuf
        SerializationHelper.ConfigProtoBufFormatter
            (typeof(Category), typeof(Product));
        var protoFormatter = new ProtoBufFormatter();
        config.Formatters.Add(protoFormatter);

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment