Marcin Wolański
"It is not the critic who counts: not the man who points out how the strong man stumbles or where the doer of deeds could have done better. The credit belongs to the man who is actually in the arena [...]"

NHibernate.Validator: komunikaty przyjazne dla użytkownika

sobota, 16 stycznia 2010 roku

Jakiś czas temu przedstawiłem sposób użycia biblioteki NHibernate.Validator w aplikacji Windows Forms. Miał on jedną zasadniczą wadę: komunikaty walidatora były takie, jakie stworzyli autorzy biblioteki.

Przypomnę, że poprzednio stworzyliśmy użytkownika z właściwościami: imię, nazwisko i wiek. Założyliśmy, że imię i nazwisko nie mogą być puste i użytkownik musi mieć przynajmniej 18 lat:

public class User
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

public class UserValidationDef: ValidationDef<User>
{
    public UserValidationDef()
    {
        Define(x => x.FirstName)
            .NotNullableAndNotEmpty();
        Define(x => x.LastName)
            .NotNullableAndNotEmpty();
        Define(x => x.Age)
            .GreaterThanOrEqualTo(18);
    }
}

Niewypełnienie imienia i nazwiska skutkowało niskopoziomowym komunikatem: nie może być nieokreślony i pusty, natomiast wpisanie wieku mniejszego niż 18: musi być większe lub równe od 18.

Chciałbym, aby komunikaty były bardziej przyjazne dla użytkownikowa np. Imię jest wymagane czy też Wiek musi być większy lub równy 18. Można dostosować komunikaty dla każdej reguły:

public class UserValidationDef: ValidationDef<User>
{
    public UserValidationDef()
    {
        Define(x => x.FirstName)
            .NotNullableAndNotEmpty()
            .WithMessage("Imię jest wymagane.");
        Define(x => x.LastName)
            .NotNullableAndNotEmpty()
            .WithMessage("Nazwisko jest wymagane.");
        Define(x => x.Age)
            .GreaterThanOrEqualTo(18)
            .WithMessage("Wiek musi być większy lub równy 18.");
    }
}

Rozwiązanie jest zadowalające dla niewielkiej aplikacji. W bardziej skomplikowanej kosmetyczna zmiana jest wymagane na musi być wypełnione wymaga przejrzenia i aktualizacji kilku/kilkunastu/kilkudziesięciu klas. Autorzy przewidzieli taki przypadek: komunikaty można zdefiniować w zewnętrznym pliku zasobów.

Dodajmy plik zasobów do projektu:

Przykładowy projekt

Definiujemy komentarze przyjazne dla użytkownika:

Zasoby

Obrazek chyba nie wymaga wyjaśnień, może poza {Value} w komunikacie message.user.age.GreaterThanOrEqualTo. Jest to właściwość publiczna atrybutu MinAttribute wykorzystywanego w metodzie GreaterThanOrEqualTo. Dzięki temu argument wspomnianej metody będzie przekazywany do komunikatu. Jeśli zmieni się wartość dopuszczalnego wieku, wystarczy edycja reguły bez konieczności uaktualniania pliku z komunikatami.

Zmieńmy klasę UserValidationDef tak, aby wykorzystywała komunikaty z pliku zasobów:

public class UserValidationDef: ValidationDef<User>
{
    public UserValidationDef()
    {
        Define(x => x.FirstName)
            .NotNullableAndNotEmpty()
            .WithMessage("{message.user.firstname.NotNullableAndNotEmpty}");
        Define(x => x.LastName)
            .NotNullableAndNotEmpty()
            .WithMessage("{message.user.lastname.NotNullableAndNotEmpty}");
        Define(x => x.Age)
            .GreaterThanOrEqualTo(18)
            .WithMessage("{message.user.age.GreaterThanOrEqualTo}");
    }
}

Ostatni krok, to konfiguracja biblioteki tak, aby wykorzystywał plik zasobów ValidationMessages.resx:

Environment.SharedEngineProvider = new NHibernateSharedEngineProvider();

var config = new FluentConfiguration();
config.SetCustomResourceManager("NHVWinForms.Properties.ValidationMessages",
         typeof(Program).Assembly)
      .Register(typeof (UserValidationDef).Assembly.ValidationDefinitions())
      .SetDefaultValidatorMode(ValidatorMode.UseExternal);

var ve = Environment.SharedEngineProvider.GetEngine();
ve.Configure(config);

I mamy przyjazne i łatwo modyfikowalne komunikaty: Imię jest wymagane zamiast nie może być nieokreślony i pusty i Wiek musi być większy lub równy 18 zamiast musi być większe lub równe od 18.

z tagami .NET

blog comments powered by Disqus