DynamicRules Request DTO

I used x mixin to mixin the db validation rules. I then used the below source code to register some validation rules in the database.

namespace digitaluapi
{
    public class ConfigureValidation : IConfigureServices, IConfigureAppHost
    {
        public void Configure(IServiceCollection services)
        {
            // Add support for dynamically generated db rules
            services.AddSingleton<IValidationSource>(c =>
                new OrmLiteValidationSource(c.Resolve<IDbConnectionFactory>()));
        }

        public void Configure(IAppHost appHost)
        {
            appHost.Plugins.Add(new ValidationFeature());
            appHost.Resolve<IValidationSource>().InitSchema();

            var validationSource = appHost.Resolve<IValidationSource>();
            validationSource.SaveValidationRulesAsync(new List<ValidationRule> {
            new ValidationRule { Type  = nameof(DynamicRules), Validator = "IsAuthenticated" },
            new ValidationRule { Type  = nameof(DynamicRules), Validator = "NotNull",
                                 Field = nameof(DynamicRules.LastName) },
            new ValidationRule { Type  = nameof(DynamicRules), Validator = "InclusiveBetween(13,100)",
                                 Field = nameof(DynamicRules.Age) },
            });
        }
    }
}

However, it seems as if the DynamicRules Request DTO does not exist and I don’t know where to find it.

That’s an example of your Request DTO that the validation rule applies to, I.e. use your own Request DTO instead.

Do you have a sample of that for me please or maybe a test I can look at.

If you are starting a new project from a template, you will have the Hello request DTO used in the MyService.cs file in the ServiceInterface project.

A working example would be to change the DynamicRules example to a request DTO class of your own. You could use the Hello request DTO in the following way.

var validationSource = appHost.Resolve<IValidationSource>();
validationSource.SaveValidationRulesAsync(new List<ValidationRule>
{
    new ValidationRule { Type = nameof(Hello), Validator = "IsAuthenticated" },
    new ValidationRule
    {
        Type = nameof(Hello), Validator = "NotNull",
        Field = nameof(Hello.Name)
    }
});

Generally the OrmLiteValidation source would be used with ServiceStack Studio as a way to manage the dynamic validation rules for your existing DTOs.

I went into Servicestack Studio and see that I can set dynamic validation rules. How would I apply the dynamic rules from the database to my DTO’s in a dynamic way. So I can see my DTO’s in ServiceStack Studio, and I can see the validation rules, but how do I use it or apply it, or is it automatic.

It’s automatic and takes effect immediately.

I managed to get it working through Servicestack studio. I tested some of the validators and they work fine. I am trying to do a confirm password validator, but it does not seem to work. How do I debug it. So I set the ConfirmPassword to be Equal to the Password, but it does not seem to pick it up. The message I get is attached below and below that my Property Validation Rules. I also see that if you mark a services is IsAuthenticated with the Type Validation Rules, it does not show a key (Protected) when you go to the metadata page. Normally when you add an [Authenticate], it will put a key to show it is a protected resource.

A Field Validation Rule applies to a single property only, if you need more complex validation you can use Custom Script Validation, e.g:

Script Conditions are valid if they return a truthy value and have access to the following arguments within their Expression:

  • Request : IRequest
  • dto : Request DTO
  • field : Property Name
  • it : Property Value

Alternatively you can mix n’ match DB Validation Rules with a Fluent Validation Rule for your Request DTO:

public class PartnerRegisterValidator<TUser> : AbstractValidator<PartnerRegister>
{
    public PartnerRegisterValidator()
    {
        RuleSet(ApplyTo.Post, () => {
            RuleFor(x => x.Password).NotEmpty();
            RuleFor(x => x.ConfirmPassword)
                .Equal(x => x.Password)
                .When(x => x.ConfirmPassword != null)
                .WithErrorCode(nameof(ErrorMessages.PasswordsShouldMatch))
                .WithMessage(ErrorMessages.PasswordsShouldMatch);
        });
    }
}

To test you could write an integration test that inserts DB Validation Rules then executes the Service to verify the correct behavior, although as it uses the same implementation as generic Declarative Validation attributes you can maintain a test service for adding/testing declarative validation logic, e.g:

[Validate(Condition = "it == dto.Password")]
public string ConfirmPassword { get; set; }

When you set [Authenticate] on a service, it shows with a key in the metadata. If you however set Authenticate using the DB Validation Rule, the key does not show up. Is that a bug?

No it only shows statically defined metadata not dynamic rules from external data sources.

To avoid having to decorate multiple Request DTOs you can just add the [Authenticate] class once on your Services implementation, e.g:

[Authenticate]
public class SecureServices : Service
{
   //all services require auth
}

Thanks, but I was thinking of doing all of that using the Dynamic Rules instead of setting it statically at the top of the Services. Would have been nice is Dynamic Database rules would show up correctly in the metadata. Any plans to add that.

It would be the first external infrastructure dependency that querying the metadata services would have to rely on, but I can look into it.

The /metadata pages should now incorporate dynamic source Auth Validation Rules from the latest v5.12+ that’s now available on MyGet.