I'm working in ServiceStack and using FluentValidation to handle incoming DTOs on requests. I've broken these out as follows, but my unit tests don't seem to be able to target specific rule sets. My code is as follows:
DTO / REQUEST CLASSES
public class VendorDto
{
public int Id { get; set; }
public string Name { get; set; }
}
public class DvrDto
{
public int Id { get; set; }
public string Name { get; set; }
public VendorDto Vendor { get; set; }
}
public class DvrRequest : IReturn<DvrResponse>
{
public DvrDto Dvr { get; set; }
}
VALIDATOR CLASSES
public class VendorValidator : AbstractValidator<VendorDto>
{
public VendorValidator()
{
RuleFor(v => v.Name).NotEmpty();
}
}
public class DvrValidator : AbstractValidator<DvrDto>
{
public DvrValidator()
{
RuleFor(dvr => dvr.Name).NotEmpty();
RuleFor(dvr => dvr.Vendor).NotNull().SetValidator(new VendorValidator());
}
}
public class DvrRequestValidator : AbstractValidator<DvrRequest>
{
public DvrRequestValidator()
{
RuleSet(HttpMethods.Post, () =>
{
RuleFor(req => req.Dvr).SetValidator(new DvrValidator());
});
RuleSet(HttpMethods.Patch, () =>
{
RuleFor(req => req.Dvr).SetValidator(new DvrValidator());
RuleFor(req => req.Dvr.Id).GreaterThan(0);
});
}
}
UNIT TEST
[TestMethod]
public void FailWithNullDtoInRequest()
{
// Arrange
var dto = new DvrRequest();
var validator = new DvrRequestValidator();
// Act
var result = validator.Validate(msg, ruleSet: HttpMethods.Post);
// Assert
Assert.IsTrue(result.IsValid);
}
I would prefer to be able to control what gets called depending on what the HttpMethod is that's being called. My thought here was, I want to validate all fields on the DvrDto (and child VendorDto) for both POST and PATCH, but only require a valid Id be set on PATCH. I am setting up my DvrRequestValidator to handle this. However, my unit test as written above (targeting the RuleSet for the POST verb) always finds the request to be valid, even though the validator should fail the request.
In fiddling with it, if I make the following changes:
VALIDATOR
public class DvrRequestValidator : AbstractValidator<DvrRequest>
{
public DvrRequestValidator()
{
RuleFor(req => req.Dvr).SetValidator(new DvrValidator());
RuleSet(HttpMethods.Patch, () =>
{
RuleFor(req => req.Dvr.Id).GreaterThan(0);
});
}
}
TEST CALL (removing the targeted verb)
// Act
var result = validator.Validate(msg); // , ruleSet: HttpMethods.Post);
The validator then works as I expect for a POST, but the PATCH rule set doesn't get executed. As a result, I seem to lose the granularity of what I want validated on a particular verb. It would appear to me that this is supported in examples I've seen both on StackOverflow and in the FluentValidation docs. Am I doing something wrong here? Or is this not possible?