WCF DataMember Serializing questions
Ok, so I was part way through the long winded process of creating DTOs for sending my model over the wire and I don't feel like I'm going down the right route.
My issue is that most of the entities in my model are not much more that DTOs anyway. I basically have an anaemic domain model, which is fine but it also make me wonder if I need to model DTOs for these entities.
So my first question is what issues might I hit if just serialize my entities and pass these about over the wire?
Secondly, a more specific question is given a property signature like so:
public virtual Unit Unit { get; set; }
Is it possible for me just to send over the wire the UnitId and not the serialized unit object?
Edit: Sorry I wasn't clear enough with my question, as you guys have posted I know that I can specify only the Id property of unit but this wont work for me.
The reason is that this prope开发者_运维百科rty (above) is on a "Country" class and I want the UnitID only returning when I call "CountryService.GetCountry(Id)" or simmilar. BUT on the floowing service call "UnitService.GetUnit(Id)" I want more properties to be serialized and sent over the wire. Hope this makes sense.
Thanks, Chris.
Secondly, a more specific question is given a property signature like so:
public virtual Unit Unit { get; set; }
Is it possible for me just to send over the wire the UnitId and not the serialized unit object?
Sure - make sure to
- not mark your
Unit
property with a[DataMember]
- create a second property called
UnitId
which you do mark as data member - make sure your clients can always somehow reconstruct the
Unit
class from only it'sUnitId
UPDATE:
The reason is that this property (above) is on a "Country" class and I want the UnitID only returning when I call "CountryService.GetCountry(Id)" or simmilar. BUT on the floowing service call "UnitService.GetUnit(Id)" I want more properties to be serialized and sent over the wire. Hope this makes sense.
In that case, you need two separate DataContracts - one for the CountryService.GetCountry(Id)
call with just the UnitId
in it, and another one for the UnitService.GetUnit(Id)
call with all the properties of Unit
that you want in it.
You cannot conditionally send some properties - or not - depending on a runtime decision. DataContracts are modelled in XML schema, and that is pretty static. If you have two sets of properties that you need, you need two separate DataContracts.
You can downsize the object that will be passed over the wire by adding the NonSerializedAttribute (msdn). You will still get Unit, but only with the UnitId.
I don't think there would be a problem in just serializing your DTO's. Do you use all of the information in your DTO's? Are you crossing domain boundaries? I would create new entities in every domain and make mappers for them.
From what I can understand, your problem stems from the fact that you have a local explicitly declared object graph made from your DTOs. What I mean is that you have declared public Unit Unit { get; set; }
on your Country
model (not sure why you're declaring them virtual
but that's not directly related to the issue at hand) rather than trying an approach that guarantees simplicity of the object graph into the degenerate case of a single object graph node.
For example, consider defining every "reference" property on your model in the form public UnitID Unit { get; set; }
where UnitID
might actually be int
or Guid
or whatever you use to uniquely identify and distinguish Unit
models from each other. Wherever you have a reference or set of references to another model, replace it with its identifier type instead of its actual type. This strategy lends itself well to a persisted set of models e.g. from/to a database with identity keys for each model. Doing this gets you simplicity of serialization without having to worry about circular references because they are now impossible. Technically, there are no more references (i.e. direct references; they are now indirect references). We're now just adding a layer of indirection in your domain model design. Now let's accommodate for that layer of indirection.
Since you've claimed that you're fine with the anemic domain model approach then this should fit well with that. You pay the minor (IMHO) cost of indirection in your model design and trade it up for the major (IMHO) benefits of an interface-based approach to data retrieval:
public interface IUnitRepository {
Unit GetUnit(UnitID id);
IEnumerable<Unit> GetUnits(IEnumerable<UnitID> ids);
// etc.
}
In your consumer code (i.e. the code that consumes this interface and your Unit
domain models), it only looks slightly more complex to traverse the implied object graph by performing interface calls to get the underlying models pointed to by the indirect references.
BEFORE:
Country ct = ...; // I assume you have this reference already
Unit ut = ct.Unit;
AFTER:
// Somewhere earlier in your code, i.e. not *every* time this type of code appears
IUnitsRepository repo = new SomeUnitsRepositoryImpl();
Country ct = ...; // I assume you have this reference already
Unit ut = repo.GetUnit(ct.UnitID);
If this bothers you syntactically, you can define a set of extension methods typed on Country
of the form:
public static Unit Unit(this Country c, IUnitsRepository repo) {
return repo.GetUnit(c.UnitID);
}
AFTER EXTENSION METHODS:
IUnitsRepository repo = new SomeUnitsRepositoryImpl();
Country ct = ...; // I assume you have this reference already
Unit ut = ct.Unit(repo);
The interface-based approach gets you the classical set of benefits such as separation of concerns, testability, consumer-producer insulation, and many more. Furthermore, you now get more direct control over object lifetime via the implementation type of your interface. What I mean is that you shouldn't have to assume naivety of implementation of your Unit GetUnit(UnitID id)
method. This method could now perform some local in-memory caching utilizing a Dictionary<UnitID, Unit>
tied with the instance of SomeUnitsRepositoryImpl
.
A bit long-winded, but I hope it helps. As if it weren't obvious from the amount of detail provided, I am currently toying with this design at my place of employment for dealing with our system of record database. :) I am really loving all the flexibility it gives me all at the simple cost of adding one level of indirection in the design of the domain models.
精彩评论