C# 干净体系结构中的值对象是否可以依赖于接口
我决定用干净的体系结构编写我的新项目,我对它不太熟悉。我正在使用这个模板 我有一个实体C# 干净体系结构中的值对象是否可以依赖于接口,c#,clean-architecture,value-objects,C#,Clean Architecture,Value Objects,我决定用干净的体系结构编写我的新项目,我对它不太熟悉。我正在使用这个模板 我有一个实体drawing.cs,它有一个BTCAddress ReceiveAddress属性: public class Withdrawal { ///ctor... public Guid Id { get; private set; } public decimal FiatAmountRequested { get; private set; } public Currenc
drawing.cs
,它有一个BTCAddress ReceiveAddress
属性:
public class Withdrawal
{
///ctor...
public Guid Id { get; private set; }
public decimal FiatAmountRequested { get; private set; }
public Currency FiatCurrency { get; private set; }
public BTCAddress ReceiveAddress { get; private set; }
}
我将BTCAddress
提取到ValueObject中,因为BTC地址不是普通字符串,所以需要验证逻辑
btcadress.cs
public class BTCAddress
{
public BTCAddress(string address)
{
Address = address;
}
public string Address { get; private set; }
public override string ToString()
{
return Address;
}
}
如您所见,我尚未对地址实施任何验证。我必须使用外部库才能进行验证。我的问题是我是否可以在btcadAddress
中添加一个依赖项,比如说IBTCAddressValidator
,并在基础架构层实现该接口,或者它不允许依赖域层中的接口
如果不是,我想我应该在每个必须创建btcadAddress
对象的用例(例如CreateDrawalRequestUseCase)中都具有该接口的依赖性。或者创建一个createbtcadressusecase
,让其他用例依赖于它,这对我来说并不合适。或者创建某种帮助器类来创建此值对象
在我的值对象中添加外部库验证的正确方法是什么
编辑:
这是我的requestdrawalcommand
using System;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using DepositWithdraw.Application.Common.Interfaces;
using DepositWithdraw.Domain.Entities;
using DepositWithdraw.Domain.ValueObjects;
using FluentValidation;
using MediatR;
namespace DepositWithdraw.Application.Withdrawals.Commands.RequestWithdrawal
{
public class RequestWithdrawalCommand : IRequest, IMapTo<Withdrawal>
{
public string ExternalId { get; set; }
public DateTime ExternalDateTime { get; set; }
public Client Client { get; set; }
public decimal FiatAmountRequested { get; set; }
public FiatCurrency FiatCurrency { get; set; }
public URL CallbackUrl { get; set; }
public BTCAddress ReceiveAddress { get; set; }
public class RequestWithdrawalCommandValidator : AbstractValidator<RequestWithdrawalCommand>
{
public RequestWithdrawalCommandValidator(IBTCAddressValidator btcAddressValidator)
{
RuleFor(p => p.FiatAmountRequested)
.GreaterThan(0)
.WithMessage("Requested fiat amount must be positive.");
RuleFor(p => p.ReceiveAddress)
.Must(address => address != null && btcAddressValidator.IsValid(address.ToString()))
.WithMessage("Invalid BTC address.");
}
}
public class RequestWithdrawalCommandHandler : AsyncRequestHandler<RequestWithdrawalCommand>
{
private readonly IApplicationDbContext _db;
private readonly IRatesRepository _ratesRepository;
private readonly IBTCWalletService _BTCWalletService;
private readonly IMapper _mapper;
public RequestWithdrawalCommandHandler(
IApplicationDbContext db,
IRatesRepository ratesRepository,
IBTCWalletService BTCWalletService,
IMapper mapper)
{
_db = db;
_ratesRepository = ratesRepository;
_BTCWalletService = BTCWalletService;
_mapper = mapper;
}
protected override async Task Handle(RequestWithdrawalCommand request, CancellationToken cancellationToken)
{
var btcRate = _ratesRepository.GetBtcRate(request.Client.Id, request.FiatCurrency.ToString());
var btcAmount = request.FiatAmountRequested / btcRate.BuyRate;
var withdrawal = _mapper.Map<Withdrawal>(request);
await _BTCWalletService.SendBTC(request.ReceiveAddress, btcAmount);
}
}
}
}
使用系统;
使用系统线程;
使用System.Threading.Tasks;
使用自动制版机;
使用.Application.Common.Interfaces;
使用depositdraw.Domain.Entities;
使用DepositRetrach.Domain.ValueObjects;
使用FluentValidation;
使用MediatR;
命名空间DepositDraw.Application.Drawals.Commands.RequestDrawing
{
公共类请求撤回命令:IRequest,IMapTo
{
公共字符串外部ID{get;set;}
公共日期时间外部日期时间{get;set;}
公共客户端{get;set;}
请求的公共十进制fiatamount{get;set;}
公共FiatCurrency FiatCurrency{get;set;}
公共URL回调URL{get;set;}
公共BTCAddress接收地址{get;set;}
公共类RequestDrawalCommandValidator:AbstractValidator
{
公共请求撤回命令验证程序(IBTCAddressValidator BTCADressValidator)
{
规则(p=>p.FiatAmountRequested)
.大于(0)
.WithMessage(“请求的法定金额必须为正”);
规则(p=>p.ReceiveAddress)
.Must(address=>address!=null&&btcAddressValidator.IsValid(address.ToString()))
.WithMessage(“无效BTC地址”);
}
}
公共类RequestDruchAlCommandHandler:AsyncRequestHandler
{
私有只读IApplicationDbContext_db;
私有只读IRatesRepository _ratesRepository;
专用只读IBTCWalletService_BTCWalletService;
专用只读IMapper\u映射器;
公共请求撤回命令处理程序(
IApplicationDbContext数据库,
伊拉特储备率为负,
IBTCWalletService BTCWalletService,
IMapper(映射器)
{
_db=db;
_ratesRepository=ratesRepository;
_BTCWalletService=BTCWalletService;
_映射器=映射器;
}
受保护的覆盖异步任务句柄(RequestDrawalCommand请求、CancellationToken CancellationToken)
{
var btcRate=_ratesresposition.GetBtcRate(request.Client.Id,request.FiatCurrency.ToString());
var btcAmount=request.FiatAmountRequested/btcRate.BuyRate;
var撤销=_mapper.Map(请求);
wait_BTCWalletService.SendBTC(request.ReceiveAddress,btcAmount);
}
}
}
}
此代码按预期工作,验证了
ReceiveAddress
,但我不喜欢在使用btcadress.cs
的任何地方都必须重复此验证过程。在这种情况下,我看不到在ValueObject中提取它的好处,我可以实现同样的效果,将ReceiveAddress
保留为字符串。类似的事情可能会变得非常固执己见。您可以始终将验证器分开,并在使用它的位置验证值对象。通过这种方式,它可以分离关注点。您能否提供有关此用例的更多细节,以及它将如何使用验证器,以便我们更清楚地了解全局情况。@Nkosi客户调用我的API,请求将一些比特币提取到给定的地址。在createDrawcalRequestUseCase
中,我想在向他发送比特币之前验证他给我的地址。如果你愿意,我可以更详细地说,但简而言之,就这些。在我的理解中,最好是btcadAddress
知道它什么时候有效,什么时候无效。但是验证逻辑又长又复杂,我想使用一个外部库来更新显示的代码,使用您刚才解释的内容。但是验证逻辑又长又复杂。更有理由让它为自己服务