Background
I like Jeffrey Palermo's Onion Architecture model (similar to Hexagonal Architecture) which prescribes that the Domain Model be at the 'center' and the concrete implementations of infrastructure, specifically Concrete Repositories be on the periphery.
So say I have a Domain Model:
//https://libphonenumber.codeplex.com/
using libphonenumber;
namespace MyApplication.Domain
{
public class Speaker
{
public virtual string Name {get;set;}
public virtual PhoneNumber PhoneNumber {get;set;}
}
}
Now I need to expose this Domain Model to other teams:
- The UI Team hypothetically wants to add several Data Validation attributes and custom JSON serialization attributes.
- The Infrastructure Team hypothetically wants to add XML Serialization attributes and some custom attributes from a 3rd party Database implementation.
- The Public API Team hypothetically wants to add WCF attributes.
I don't want to give every team carte blanche to add their Attributes to my Domain Model and I especially don't want them adding all of their "layer specific" dependencies to my model assembly.
And this case is made more complicated because I'm using 3rd party 'domain models' in my own (in this case using Google's LibPhoneNumber to handle the Phone Number).
Ideally, they'd each need to create their own wrapper class like:
using MyApplication.Domain;
namespace MyApplication.UI.DomainWrappers
{
public class UISpeaker
{
private Speaker _speaker;
public class UISpeaker(Speaker speaker = null)
{
_speaker = speaker ?? new Speaker();
}
[Required]
public virtual string Name {
get{ return _speaker.Name; }
set{ _speaker.Name = value; }
}
[Required]
public virtual PhoneNumber PhoneNumber {
get{ return _speaker.PhoneNumber ; }
set{ _speaker.PhoneNumber = value; }
}
//Conversion operators
public static implicit operator UISpeaker(Speaker s)
{
return new UISpeaker(s);
}
public static implicit operator Speaker(UISpeaker s)
{
return s._speaker;
}
}
}
Question
Writing and maintaining the UISpeaker
class is a pain and is boring boilerplate code.
Is there either a better way to add the Attributes each team wants to add without letting them directly edit the Domain Model? Or is there some tooling that can help generate these wrapper classes (I was thinking possibly a weaving tool like Fody or T4 Templates, but I'm not familiar enough with either to know if they could help in this use case).
Research
I looked around Stackoverflow and found some similar questions, but none that hit the full scope I'm looking for:
Avoid using the JsonIgnore attribute in a domain model - Concluded to just use .NET native attributes on the Domain Model so you didn't have to take a dependency on Json.Net
Add an attribute to another assembly's class - Discussed using
CustomReflectionContext
to add Attributes to an existing type. This looks really cool, but unfortunatly, the model would be handed off to 3rd party code (ORMs, EF, Json.Net, etc) for reflection so I don't think this will work here.Having Separate Domain Model and Persistence Model in DDD - Confirmed that each layer should have it's own version of the Domain Model, but didn't discuss if there's any tooling / strategies to make writing / maintaining that code any easier.