views:

504

answers:

1

I will be attempting to create a C# library to serialize objects to GeoJSON using Json.NET ( for serialization ) and GeoAPI.NET ( for geometry definitions ).

I have thought about two different approaches for the serialization implementation and I am not clear which one would be the best approach. They are:

Approach 1 - Custom Attributes

The first approach involves creating several custom attributes that could be applied to any class to modify the serialization. For instance, a class might be decorated like so:

[GeoJsonFeature]
public class Building
{
   [GeoJsonId]
   public Guid Id { get; set; }
   [GeoJsonProperty]
   public string Name { get; set; }
   [GeoJsonProperty]
   public int Floorcount { get; set; }
   [GeoJsonGeometry]
   public GeoAPI.Geometries.IGeometry Geometry { get; set; }
}

Serializing the object would then be as simple as:

JsonNetResult jsonNetResult = new JsonNetResult();
jsonNetResult.Formatting = Formatting.Indented;
jsonNetResult.Data = building;
return jsonNetResult;

The advantage of this approach is that any business object could be turned into a GeoJSON object assuming it has the required properties (e.g., Geometry ). The disadvantage would be that I would need to create a number of custom attributes to support the serialization. Additionally, this has the affect of 'muddying' the business object.

Finally, I have not yet determined if this approach is even possible with JSON.NET, though it seems that it will be.

Approach 2 - Custom JsonConverter

The second approach involves creating custom converters for various types. For instance I might have a GeoJsonConverter that when passed an object of a given type, say Feature, the GeoJSON object is created. This might look like:

public class GeoJsonFeatureConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer)
    {  
        // serializing code here 
    }

    public override void ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
    {  
        // deserializing code here 
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(Feature).IsAssignableFrom(objectType);
    }
}

I would then be able to serialize to GeoJson like so:

JsonNetResult jsonNetResult = new JsonNetResult();
jsonNetResult.Formatting = Formatting.Indented;
jsonNetResult.SerializerSettings.Converters.Add(new GeoJsonFeatureConverter());
jsonNetResult.Data = building;

The advantage here is that this seems easier to create. I have proven that this approach is possible via a very simple prototype. Additionally, the Feature class is already defined if I link to NetTopologySuite.

The disadvantage would be that my business objects would need to be mapped to a Feature before being serialized. Though, this might be considered an advantage since this might provide a natural decoupling between the layers. There would definitely be tight coupling with the GeoAPI in both cases and NetTopologySuite in the later. I think I am okay with that.

I am aware of several other GeoJson serializers available such as GeoJson.NET however I would like an approach that is consistent with the Json.NET API as this is our serializer of choice.

Do you see any obvious reasons why one approach would be preferred over the other? Perhaps there is another approach that I am not aware of?

FYI, I am leaning towards the second approach. It seems that it would be easier to implement and that it would be cleaner overall. I also happen to like the natural boundary between domain objects and GeoJson objects that it would create.

+1  A: 

Personally I'd lean towards the first choice, for a simple reason. If you look at the .NET framework, there's an analog to your serialization in the System.Xml.Serialization namespace. There they do almost exactly what you're suggesting in your first approach.

However, if you don't particularly like that, I'd suggest a third approach: Write a custom serialization formatter, implementing System.Runtime.Serialization.IFormatter. This gives you the ability to use standard serialization notation and mechanisms for you objects (like [Serializable] and ISerializable), but you're following a well-recognized pattern, making use easy to recognize. Plus as an added bonus you can easily support other forms of serialization (binary, soap, other custom formats) down the road by swapping out your IFormatter implementation

Edit: here's an example: http://geekswithblogs.net/luskan/archive/2007/07/16/113956.aspx

Hounshell