I’ve had to build several enterprise size applications over the years, and one of the biggest mistakes I ever made was to re-use the business objects as my data contracts.
I just didn’t know any better, and it was an easy mistake to make.
Recently, however, I found this amazing blog entry that I think really explains why you should never use your business objects are your data contract:
http://codinglight.blogspot.ca/2009/06/why-you-should-never-make-your-business.html
In short, the author points out that you may start with a very nice clean business object (his example):
public class NiceCleanBusinessObject
{
public string Value { get; set; }
public string LastUpdatedBy { get; set; }
public DateTime? LastUpdatedOn { get; set; }
}
And due to many requirement changes during the process of development, ends up with this monstrosity (his example):
[DataContract]
[KnownType(typeof(NiceCleanBusinessObject))]
public class NiceCleanParentObject
{
public NiceCleanParentObject()
{
NiceCleanObjects = new List<NiceCleanBusinessObject>();
}
[DataMember]
public string Value { get; set; }
[DataMember]
public List<NiceCleanBusinessObject> NiceCleanObjects { get; set; }
}
[DataContract]
public class NiceCleanBusinessObject
{
private string _value;
[DataMember]
public string Value
{
get { return _value; }
set
{
_value = value;
LastUpdatedBy = null;
LastUpdatedOn = null;
RunSomethingComplicated();
}
}
[DataMember]
public string Value2 { get; set; }
[DataMember]
public string LastUpdatedBy { get; set; }
[DataMember]
public DateTime? LastUpdatedOn { get; set; }
public NiceCleanParentObject Parent { get; set; }
private void RunSomethingComplicated()
{
Value2 = Parent.Value;
}
}
This is a mess, and it should never be done. So, what should you do?
ASP.NET MVC, WebApi to JavaScript
In my development, I’ve mostly focused on having server-side objects that I need to transfer to JavaScript from ASP.NET. There are a few things to note here.
First, NewtonSoft Json.NET (http://james.newtonking.com/json). You should always use this, because it’s much faster than the default .NET data contract serializer. Fortunately, in WebApi, it is used by default. In MVC, it is not. There are many articles on how to use it in MVC, for example:
http://stackoverflow.com/questions/7109967/using-json-net-as-default-json-serializer-in-asp-net-mvc-3-is-it-possible
So I won’t go into that.
Second, JavaScript works with camelCase, not PascalCase, so you can’t rely on automatic C# contracts. You’ll have to hand-create each one (or write an application to produce C# class file contracts from your business objects), and then attribute them with things like:
[DataMember(EmitDefaultValue = false, Name = "someProperty")]
public string SomeProperty { get; set; }
Doing this of course means you need to copy all the properties back-and-forth every time you ship or receive the object, which can be very tedious. One easy way to solve this is to use a tool, such as auto-mapper:
https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
This publically available library allows you to create mappings with conversion-specification (if required) to map properties back and forth. This is very important, because some objects are not JavaScript friendly (like Dictionary<>
), and will need to be a different type when going across the wire.
Third, enums. In C#, enums are a thing. In JavaScript, they are not. By default, what will be serialized is the value of the enum, which will be 0..N if you don’t explicitly define it when you define the enum in C#:
public enum SomeType
{
First = 0,
Second = 10,
}
The issue here is that if you ever change the numbers, any JS code that was specifically setting the enum value will fail. A better option is to instead, use the string name of the enum, and then in JS, create an object which can be used as a helper:
mystuff.SomeType = {
FIRST: "First",
SECOND: "Second",
}
This way, API users can freely use mystuff.SomeType.FIRST
in their code to set properties which will go back to the server, and it won’t break even if the numbers change (which is much more common than the string, as the string is a breaking-API change in C#).
To force Json.NET to use this serializer by default, this code can be used (in Application_Start, or wherever you setup your WebApi):
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(
new StringEnumConverter());
Also, don’t forget that flags enums will be converted to comma separated string values. For example, if an enum is set to a | b, you will receive "a, b" in JavaScript.