I'm using FluentValidation in my API, and I've created four validators. The first one is for order level validation, the second one is for order detail level validation, and the other two are for withdraw and transfer operations on order details.
I can call the OrderValidator
from the application as shown below:
var validator = new OrderValidator();
foreach (var order in orders)
{
var vResult = validator.Validate(order);
}
The code above works for both the OrderValidator
and the OrderDetailValidator
. However, it doesn't work for the WithdrawInfoValidator
and TransferInfoValidator
because I haven't declared the WithdrawInfoValidator
yet.
The question is how to set up the WithdrawInfoValidator
within the OrderDetailValidator
.
This is my model
public class Order
{
public string AdvisorCode { get; set; }
public string AccountNo { get; set; }
public string AccountType { get; set; }
public List<OrderDetail> Details { get; set; }
}
public class OrderDetail
{
public int GroupNo { get; set; }
public int SubOrderNo { get; set; }
public string OrderType { get; set; }
public string FundSource { get; set; }
public string ProductCode { get; set; }
public string Currency { get; set; }
public decimal Amount { get; set; }
public decimal Units { get; set; }
public string DivOption { get; set; }
public int? SellAll { get; set; }
public WithdrawInfo WithdrawInfo { get; set; }
}
public class WithdrawInfo
{
public string WithdrawMode { get; set; }
public string WDCurrency { get; set; }
public decimal WDAmount { get; set; }
public TransferInfo TransferInfo { get; set; }
}
public class TransferInfo
{
public string BankName { get; set; }
public string AccountNo { get; set; }
public string Branch { get; set; }
public string AccHolderName { get; set; }
public string SwiftCode { get; set; }
public string IntBankName { get; set; }
public string IntSwiftCode { get; set; }
public string OtherInfoOrAddress { get; set; }
}
public class OrderErrorReference
{
public string OrderType { get; set; }
public int GroupNo { get; set; }
public int SubOrderNo { get; set; }
}
This is my validator
public class OrderValidator : AbstractValidator<Order>
{
public OrderValidator()
{
RuleFor(m => m.AdvisorCode)
.NotEmpty()
.WithMessage(
"AdvisorCode field cannot be empty."
);
RuleForEach(m => m.Details)
.SetValidator(new OrderDetailValidator())
.When(m => m.Details != null);
}
}
public class OrderDetailValidator : AbstractValidator<OrderDetail>
{
public OrderDetailValidator()
{
RuleFor(m => m.GroupNo)
.Cascade(CascadeMode.Stop)
.NotEmpty().WithMessage(
"GroupNo field cannot be empty."
).WithState(m => new OrderErrorReference
{
GroupNo = m.GroupNo,
SubOrderNo = m.SubOrderNo,
OrderType = m.OrderType
})
.Must(m => m > 0)
.WithMessage(
"GroupNo must be greater than zero."
).WithState(m => new OrderErrorReference
{
GroupNo = m.GroupNo,
SubOrderNo = m.SubOrderNo,
OrderType = m.OrderType
});
}
}
public class WithdrawInfoValidator : AbstractValidator<WithdrawInfo>
{
public WithdrawInfoValidator(OrderDetail orderDetail)
{
RuleFor(m => m.WithdrawMode)
.Cascade(CascadeMode.Stop)
.Must(mode => mode == "TT" || mode == "QC")
.When(m => m.WithdrawMode != null)
.WithMessage(
"Withdraw Mode must be either \"NA\"=No Withdrawal, \"TT\"=Telegraphic Transfer or \"QC\"=Quick Check Deposit."
).WithState(m => new OrderErrorReference
{
GroupNo = orderDetail.GroupNo,
SubOrderNo = orderDetail.SubOrderNo,
OrderType = orderDetail.OrderType
})
.NotEmpty()
.WithMessage(
"The WithdrawMode field cannot be empty."
).WithState(m => new OrderErrorReference
{
GroupNo = orderDetail.GroupNo,
SubOrderNo = orderDetail.SubOrderNo,
OrderType = orderDetail.OrderType
});
RuleFor(m => m.TransferInfo)
.Must(info => info != null)
.When(m => m.WithdrawMode == "TT" || m.WithdrawMode == "QC")
.WithMessage(
"TransferInfo cannot be empty if WithdrawMode is \"TT\" or \"QC\""
).WithState(m => new OrderErrorReference
{
GroupNo = orderDetail.GroupNo,
SubOrderNo = orderDetail.SubOrderNo,
OrderType = orderDetail.OrderType
})
.SetValidator(m => new TransferInfoValidator(orderDetail))
.When(m => m.WithdrawMode == "TT" || m.WithdrawMode == "QC");
}
}
public class TransferInfoValidator : AbstractValidator<TransferInfo>
{
public TransferInfoValidator(OrderDetail orderDetail)
{
RuleFor(m => m.OtherInfoOrAddress)
.NotEmpty()
.When(m => orderDetail.WithdrawInfo.WithdrawMode == "TT")
.WithMessage(
"OtherInfoOrAddress field cannot be empty if WithdrawMode is TT."
).WithState(m => new OrderErrorReference
{
GroupNo = orderDetail.GroupNo,
SubOrderNo = orderDetail.SubOrderNo,
OrderType = orderDetail.OrderType
});
}
}
I already tried many ways but it didn't work.
You should declare the validation rule for the WithdrawInfo
property by providing the WithdrawInfoValidator
instance with the orderDetail
object.
public class OrderDetailValidator : AbstractValidator<OrderDetail>
{
public OrderDetailValidator()
{
...
RuleFor(m => m.WithdrawInfo)
.SetValidator(m => new WithdrawInfoValidator(m));
}
}