在WCF客户端上使用DTO的最佳方法

时间:2019-04-19 22:34:55

标签: c# wpf wcf dto

我想了解实现以下情况的正确方法的一些建议。

我有三个解决方案:使用实体框架与SQL数据库进行通信的WCF服务,托管服务的WPF服务器和使用服务的WPF客户端。我在考虑什么是实现DTO的正确方法。

目前,对于每个EF实体,我都有一个DTO,用于与客户端进行通信。因此,客户端从服务请求某些内容,服务从数据库获取信息并对其进行一些逻辑处理,然后将返回对象映射到DTO(使用AutoMapper)并发送给客户端。

在客户端,我必须为这些DTO添加一些扩展,例如,我需要添加一些自动计算的属性和方法。

我最后有两个主意

第一个想法是为我需要添加逻辑的每个DTO创建一个局部类。

我看到的优点是:我不必重写整个DTO,只需添加我需要的其他属性和方法,并且只需要映射一次EFEntity => ServiceDTO和ServiceDTO => EFEntity

缺点:我想将某些属性设置为私有,使其他属性为只读。但是无论我在Service DTO上编写的访问级别或设置器如何,它总是在客户端上生成为public .... { get; set; }

这是这种方法的一个例子

//AT THE WCF SERVICE: DTO
[DataContract]
public class BajaRoturaDTO
{
    [DataMember] public int Id { get; set; }
    [DataMember] public int NoVale { get; set; }
    [DataMember] public DateTime Fecha { get; set; }
    [DataMember] public UsuarioDTO Usuario { get; set; }
    [DataMember] public string Comentario { get; set; }
    [DataMember] public DepartamentoDTO Departamento { get; set; }
    [DataMember] private List<Instance> _instances { get; set; } //I would like to make this private but it's autogenerated public on the Client

    [DataContract]
    public class Instance
    {
        [DataMember] public int ValidationState { get; set; }
        [DataMember] public int Cantidad { get; set; }
        [DataMember] public ProductoInstanceDTO TargetInstance { get; set; }
    }
}

//AT THE WPF CLIENT: DTO PARTIAL CLASS
public partial class BajaRoturaDTO
{
    public BajaRoturaDTO()
    {
        _instances = new List<Instance>();
    }

    public BajaRoturaDTO(DateTime defaultDate)
    {
        Fecha = defaultDate;
        _instances = new List<Instance>();

    }
    [Magic] public List<Instance> Instances { get => new List<Instance>(_instances); }

    [Magic] public decimal ImporteCosto { get => _instances.Sum(x => x.ImporteVenta); }

    [Magic] public decimal ImporteVenta { get => _instances.Sum(x => x.ImporteCosto); }

    [Magic] public string TotalProductos { get => _instances.Count() + " producto(s)"; }

    public partial class Instance
    {
        [Magic] public decimal ImporteCosto { get => Cantidad * TargetInstance.Producto.PrecioCosto; }

        [Magic] public decimal ImporteVenta { get => Cantidad * TargetInstance.Producto.PrecioVenta; }

        public async Task Validate(DateTime targetDate)
        {
            ValidationState = await TargetInstance.Validate(targetDate, Cantidad);
        }
    }

    //METHODS
    public async Task AddInstance(Instance target)
    {
        var matchInList = _instances.FirstOrDefault(x =>
            x.TargetInstance.Producto.Id == target.TargetInstance.Producto.Id
            && x.TargetInstance.Departamento.Id == target.TargetInstance.Departamento.Id);

        if (matchInList is null)
        {
            _instances.Add(target);
            await target.Validate(Fecha);
        }
        else
        {
            matchInList.Cantidad += target.Cantidad;
            await matchInList.Validate(Fecha);
        }

        RaisePropertyChanged("Instances");
        RaisePropertyChanged("ImporteCosto");
        RaisePropertyChanged("ImporteVenta");
        RaisePropertyChanged("TotalProductos");
    }
//More methods

PD:[Magic]装饰器是我安装的用于自动化INotifyPropertyChange的扩展。

另一个想法是为WPF客户端上的每个DTO创建一个全新的类,并再次使用AutoMapper从ServiceDTO映射到ClientClass

我看到的优势:我可以定义自动计算的属性,私有字段,方法以及我想要的一切

缺点,我发现:我必须再次重新创建每个DTO并执行更多映射(EFEntity => ServiceDTO => CientClass和ClientClass => ServiceDTO => EFEntity)

对于您对这两种方法的看法或是否有更好的方法,我需要您的意见。

感谢您的时间,如果我有一些拼写错误,请原谅我的英语

0 个答案:

没有答案