re-using ServiceStack validation in Winforms offli

2019-07-24 04:38发布

问题:

We have a working website using ServiceStack as the back end that amounts to a complex data-entry form.

My users have requested an "offline editor" for the forms. To use the offline program, the user will have to connect to the ServiceStack service, create empty instances of the forms, and then I will save the POCOs from the service to disk using ServiceStack's JSON serializer. From there the user can log off the service and edit the POCOs. When they're done, they reconnect to the service, and post/put the edited POCO object.

This all works great. My question involves validation. The validation logic is built into my Service.Interface library, which isn't available offline. The winforms program references only the POCO library and the ServiceStack "common" libraries, which do not look like they include the ServiceStack.Validation namespace.

Is there a way I can rearrange my project so that both the service and the Winforms client can run Validation against the POCOs, so that they can have data validation while offline?

UPDATE: getting closer, I think - I moved all of the Validation classes into their own project. From my Winforms project, I can now manually set up a validator for a POCO class like this:

 ServiceStack.FluentValidation.IValidator<SomePOCO> IValidator;
 IValidator = new Tonto.Svc.Validation.SomePOCOValidator();

 ServiceStack.FluentValidation.Results.ValidationResult vr = 
    IValidator.Validate(_rpt);

I can see the validator constructor being set up and the rules being initialized, but the .Validate method doesn't seem to do anything. (object comes back as valid, and breakpoints into custom validator code never get there).

UPDATE #2

I discovered my validator code wasn't running from Winforms because my validators all specify a servicestack ApplyTo Put/Post only (see sample code below). When I remove the entire Ruleset clause, though, then validation happens in my service on GETs - something I never want.

Can anyone think of a way to configure the validator rules to run for POST/PUT only when called from ServiceStack, but to also always run when NOT in servicestack? So close!

public class SomePOCOValidator : AbstractValidator<SomePOCO>    
    {
        public SomePOCO()
        {
            RuleSet(ApplyTo.Put | ApplyTo.Post, () =>
            {
               (rules)
            });
        }
    }

回答1:

If your validation is doing anything interesting, then it probably HAS to be done "online".

Maybe just allow your client to save the POCOs locally until they go back online, at which point you send them up to your server. Any transactions that are okay, get processed normally, and any that fail, get returned for the user to edit (so your client will need some smarts to have a working set of POCOs for editing)...

If you don't want ANY extra stuff on the client, just have the transactions that fail to validate get stuffed into a "needs_corrections" table on the server, and then code up a supervisor-sort of screen to manage that table.



回答2:

The validation framework that ServiceStack uses is named FluentValidation. There is no WinForms support in it. Jeremy Skinner the creator of FluentValidation answerd a question about this back in 2010 on his forum here.

Personally I don't use FV with WinForms - the vast majority of my projects are web-based with the occasional WPF project.

However, if I was going to do this then I probably wouldn't validate the controls directly, but instead use a ViewModel which is bound to the controls. I'd use a fairly strict convention where the names of the controls would match the names of the properties that they're bound to. Then, after validation completes I'd walk the control hierarchy to find the control with the name that matches the property that failed validation (I'm not sure how you'd do this in WinForms, but in WPF I'd use LogicalTreeHelper.FindLogicalNode) and then use the ErrorProvider to set the appropriate error.

Jeremy



回答3:

I was able to work out a solution that allowed me to use ServiceStack validation libraries on both a ServiceStack client and an offline client. Here are the details.

  1. Move all AbstractValidators to their own project: Proj.Svc.Validation.

  2. get rid of all RuleSets in your AbstractValidators.

  3. Reference Proj.Svc.Validation from Proj.Svc.Interface and Proj.OfflineWinformsClient projects.

  4. Turn OFF the ValidationFeature() plugin in your service. All validation will have to be done manually. This means no iOC injected validators in your service classes.

  5. When it's time to validate, either from your service or the offline client, manually declare the validator and use it like this.

    IValidator validator = new Tonto.Svc.Validation.SomePOCOValidator(); ServiceStack.FluentValidation.Results.ValidationResult vr = validator.Validate(poco);

    if (!vr.IsValid) (throw exception or notify user somehow);