Should business objects be able to create their own DTOs?

雨燕双飞 提交于 2019-12-01 06:04:17

I would generally say no, they shouldn't, because DTOs are specific to a service or application, whereas the domain model is your "innermost" layer and should have no dependencies. DTOs are an implementation detail of something other than the domain model, and therefore, it's breaking the abstraction for your domain model to know about them.

Have you considered looking at AutoMapper for this? You'll end up writing a lot less code that way. In this case, I think you'd be able to get away with simply:

Mapper.CreateMap<RegionOfInterest, RegionOfInterestData>();
Mapper.CreateMap<Camera, CameraData>();

And later on:

CameraData cd = Mapper.Map<Camera, CameraData>(camera);

This not only reduces the code churn but compartmentalizes the mapping code in its own "mapping layer" - you have one or several modules that register these mappings that you can put in whichever assembly really uses the DTOs.

And of course you can always create extension methods to simplify the actual mapping:

public static class CameraExtensions
{
    public static CameraData ToCameraData(this Camera camera)
    {
        return Mapper.Map<Camera, CameraData>(camera);
    }
}

Which makes the whole thing as simple as writing camera.ToCameraData(), but without creating a hard dependency between the domain object (Camera) and the DTO (CameraData). You have basically all of the ease-of-use of your original version, but without the coupling.

If you're creating these dependencies because you're trying to create the CameraData object from private Camera data which isn't exposed publicly then my immediate reaction would be, something's not quite right about this design. Why not expose read-only properties on the Camera object? If you're giving the outside world access to them anyway, through the ToData method, then you're clearly not hiding this information, you're just making it more cumbersome to get to.

What if you decide 3 months down the road that you need a different kind of DTO? You shouldn't have to modify your domain-centric Camera object every time you want to support a new use case. Better, in my opinion, to put a few read-only public properties in the class so that mappers can get access to the attributes they need.

I usually go about it this way: The business objects are "pure" in the business layer DLL(s). I then add a Camera.MapToCameraDataContract extension method in the WCF layer. I also typcially have the reverse extension method (CameraDataContract.MapToCamera) on the service layer as well.

So in essence, I do it the first way, but the ToData method is an extension method that only the WCF layer knows about.

The first (exposing a DTO) is much preferable to me. It's simpler, will run faster, will be easier to understand and maintain. Since the DTO really has no dependency on the database object it still easily achieves the objective of reducing dependencies.

I put the to/from methods on my DTOs themselves:

[DataContract]
public class CameraData
{
    ...
    public Camera ToCamera() { ... }

    public static CameraData FromCamera(Camera c) { ... }
}

That way my domain objects do not have to know about my DTOs.

Are your services WCF to WCF?

If they are then you could choose to use your business objects as DTOs (as long as your business objects are persistence ignorant). If you did this I'd recommend changing your CameraData class to ICameraData interface and make Camera implement ICameraData. Keep the attributes (DataContract etc) on the interface.

Then you can pass the business object from client to server. Be aware of any logic that is specifically client or server side.

The first image in my blog post here shows how easy it is to Re-Use your business objects objects client side (the dialog box is what is shown when you do 'add service reference'). The blog post has some info on one of the gotchas of re-using biz objects.

I can't tell what you're trying to achieve with ExposeToReporter but you are right, it doesn't look right, personally I'd put a method on IReporter that takes an ICameraData parameter, then set the details on reporter within that.

An awesome source of learning for this stuff is dnrtv. Watch everything with WCF in the title but especially Extreme WCF by Miguel Castro!

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!