I am working on a project with SignalR, and I have some objects that I am going to go through it. These objects are only explicitly created in my internal code, and I really would like to provide immutability and invariants on them. I am facing a problem that SignalR requires me (well, really, NewtonSoft.Json) to have default constructors, no-args and public setters for my properties so that it serializes and deserializes them over the wire.
Here is a contrived example:
public class Message{ public string Text {get;set;} public int Awesomeness {get;set;} }
What I would like is something more along these lines (it should probably only have full read-only fields, and getter-only properties are completely immutable, but for something that is just POCO without any methods good enough)
public class Message { public string Text {get;private set;} public int Awesomeness {get;private set;} public Message( string msg, int awesome){ if (awesome < 1 || awesome > 5){ throw new ArgumentOutOfRangeException("awesome"); } Text = msg; Awesomeness = awesome; } }
If I do this, my object cannot be deserialized by the SignalR.NET client library. I can just click on the default constructor there and make my setters public, but then I must remember that I did not use them in my code, and make sure that no one in the team uses them without understanding.
I started using this idea to mark the default constructor as something that should never be explicitly used:
[Obsolete("Bad! don't do this!") public Message(){}
But I can not use the Obsolete attribute only for the property installer.
If I really wanted to, I could select the “real” object from the DTO view and convert between them, but I'm really not crazy to write a bunch of templates to do this, and introduce another layer.
Is there something I'm missing out on, or do I just need to bite a bullet and deal with it?