I'm working on a project with SignalR, and I've got some objects that I'm going to be passing along through it. These objects are only explicitly created in my back-end code, and I'd really like to be able to enforce immutability and invariants on them. I'm running into the issue that SignalR requires me (well, really NewtonSoft.Json), to have a default, no-args constructor and public setters on my properties in order for it to serialize and deserialize them over the wire.
Here's a contrived example:
public class Message{
public string Text {get;set;}
public int Awesomeness {get;set;}
}
What I'd like, is something more along these lines (it should probably have readonly private fields and getter-only properties to be fully immutable, but for something that is just a POCO with no 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 that, though, my object can't get deserialized by the SignalR .NET client library. I can just chuck a default constructor in there, and make my setters public, but then I have to remember to not use them in my code, and make sure no one else on the team uses them without understanding.
I've kicked around the idea of doing this, to mark the default constructor as something that should never be explicitly used:
[Obsolete("Bad! don't do this!")
public Message(){}
But I can't use the Obsolete attribute on just the setter of a property.
If I really wanted to, I could separate out the "real" object from a DTO representation and convert between them, but I'm not really psyched up to write a bunch of boilerplate to do that and introduce another layer.
Is there something I'm overlooking, or do I just need to bite the bullet and deal with it?
See Question&Answers more detail:
os