2017-02-21 3 views
2

Dans le projet MVC im travail que j'utilise Fluent validation pour la mise en œuvre des logiques de validation et de l'unité comme conteneur d'injection de dépendanceCourant Validator withMessage et instance singleton

Dans ma classe de validateur il y a des règles de validation des affaires complexes

public class ServicerRequestViewModelValidator : AbstractValidator<ServiceRequestViewModel> 
{ 
    public ServiceRequestViewModelValidator(ILocalizationService localizationService) 
    { 
    RuleFor(x => x.IdStato).NotNull().WithMessage(string.Format(localizationService.GetMessage("Validation.General.MandataryField"), localizationService.GetMessage("ServiceRequestDetail.State"))); 
     // other business validations rule with localized error message 
    } 
} 

la règle définit un message d'erreur localisée selon la langue de l'utilisateur

JeremySkinner dit:

L'instanciation des validateurs est un processus coûteux en raison de la compilation et de l'analyse de l'arborescence d'expressions dans les définitions RuleFor . Pour cette raison, il est recommandé d'utiliser les instances de validateur en tant que singletons. Une fois instanciées, elles doivent être mises en cache et réutilisées plutôt qu'être instanciées plusieurs fois.

Les validateurs ne contiennent aucun état partagé. Par conséquent, il doit également être sûr de les réutiliser dans des scénarios multithread. La meilleure approche pour mettre en cache les instances de validateur consiste à utiliser un conteneur IoC (par exemple, StructureMap) pour gérer les cycles de vie des instances.

Alors je me suis inscrit dans le récipient le validateur avec ContainerControlledLifetimeManager (singleton)

container.RegisterType<IValidator<ServiceRequestViewModel>, ServiceRequestViewModelValidator>(new ContainerControlledLifetimeManager()); 

Mais faire comme ça un problème se pose: première fois ServiceRequestViewModelValidator est résolu le constructeur est exécuté et le message d'erreur localisée le seront être mis en cache en fonction de la langue de l'utilisateur et les utilisateurs suivants recevront le message localisé en fonction de la langue de l'utilisateur qui a instancié la classe singleton.

Répondre

0

J'ai créé une nouvelle méthode d'extension WithMessage qui riceve un délégué insted d'une chaîne, en profitant de LazyStringSource classe

public static IRuleBuilderOptions<T, TProperty> WithMessage<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, Func<string> errorMessage) 
     { 
      return rule.Configure((Action<PropertyRule>)(config => 
      { 
       config.CurrentValidator.ErrorMessageSource = (IStringSource)new LazyStringSource(errorMessage); 
      })); 
     } 

Puis j'ai changé mon ServiceRequestValidator comme ça:

public class ServicerRequestViewModelValidator : AbstractValidator<ServiceRequestViewModel> 
{ 
     public ServiceRequestViewModelValidator(ILocalizationService localizationService) 
      { 
        RuleFor(x => x.IdStato).NotNull().WithMessage(()=>string.Format(localizationService.GetMessage("Validation.General.MandataryField"), localizationService.GetMessage("ServiceRequestDetail.State"))); 
      } 
     } 

Faire comme ça dans le constructeur est défini le délégué qui sera appelé pendant le processus de validation pour résoudre le message d'erreur localisé basé sur la langue de l'utilisateur et pas directement la chaîne de message d'erreur localisée.