2012-02-21 3 views
38

Mam następujące zasadywalidacji klienta dyskretny użyciu fluentvalidation i ASP.NET MVC LessThanOrEqualTo nie wypalanie

1st działa stosując dyskretne, walidacji po stronie klienta, drugi nie

jakieś pomysły dlaczego?

RuleFor(x => x.StartDate) 
    .LessThanOrEqualTo(x => x.EndDate.Value) 
    .WithLocalizedMessage(() => CommonRes.Less_Than_Or_Equal_To, filters => CommonRes.Start_Date, filters => CommonRes.End_Date); 

RuleFor(x => x.StartDate) 
    .GreaterThanOrEqualTo(x => x.AbsoluteStartDate) 
    .LessThanOrEqualTo(x => x.AbsoluteEndDate) 
    .WithLocalizedMessage(() => CommonRes.Between, filters => CommonRes.Start_Date, filters => filters.AbsoluteStartDate, filters => filters.AbsoluteEndDate); 
+0

Czy jesteś pewien, że pierwsze prace? 'LessThanOrEqualTo' nie jest jedną z zasad wymienionych w [dokumentacja] (http://fluentvalidation.codeplex.com/wikipage?title=mvc&referringTitle=Documentation) jako obsługiwanych przez walidację klienta. Którą wersję FV używasz? –

+0

o człowieku !! to było "LessThanOrEqualTo" czy jest jakaś praca nad tym? – iwayneo

Odpowiedz

75

Żaden z przepisów LessThanOrEqualTo lub GreaterThanOrEqualTo są obsługiwane przez walidacji po stronie klienta, jak wyjaśniono w documentation.

To oznacza, że ​​jeśli chcesz mieć sprawdzania poprawności po stronie klienta dla nich będzie trzeba napisać niestandardowy FluentValidationPropertyValidator i wdrożenie metody GetClientValidationRules który pozwoli Ci zarejestrować kartę niestandardową i wdrożenia logiki sprawdzania poprawności po stronie klienta za to w javascript .

Jeśli jesteś zainteresowany tym, jak można to osiągnąć, po prostu zadzwoń do mnie, a podam przykład.


UPDATE:

Jako wniosek, postaram się pokazać przykład, jak można zaimplementować sprawdzanie poprawności po stronie klienta korzystającego dla reguły LessThanOrEqualTo. Jest to tylko szczególny przypadek z nie-nullowanymi datami. Pisanie takiego niestandardowego walidatora po stronie klienta dla wszystkich możliwych przypadków jest oczywiście możliwe, ale będzie wymagało znacznie więcej wysiłku.

Więc zaczynamy z widokiem modelu i odpowiedniego walidator:

[Validator(typeof(MyViewModelValidator))] 
public class MyViewModel 
{ 
    [Display(Name = "Start date")] 
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] 
    public DateTime StartDate { get; set; } 

    public DateTime DateToCompareAgainst { get; set; } 
} 

public class MyViewModelValidator : AbstractValidator<MyViewModel> 
{ 
    public MyViewModelValidator() 
    { 
     RuleFor(x => x.StartDate) 
      .LessThanOrEqualTo(x => x.DateToCompareAgainst) 
      .WithMessage("Invalid start date"); 
    } 
} 

Następnie kontroler:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new MyViewModel 
     { 
      StartDate = DateTime.Now.AddDays(2), 
      DateToCompareAgainst = DateTime.Now 
     }; 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(MyViewModel model) 
    { 
     return View(model); 
    } 
} 

i widok:

@model MyViewModel 
@using (Html.BeginForm()) 
{ 
    @Html.Hidden("DateToCompareAgainst", Model.DateToCompareAgainst.ToString("yyyy-MM-dd")) 

    @Html.LabelFor(x => x.StartDate) 
    @Html.EditorFor(x => x.StartDate) 
    @Html.ValidationMessageFor(x => x.StartDate) 
    <button type="submit">OK</button> 
} 

Wszystko to jest standard rzeczy jak dotąd. Będzie działać, ale bez sprawdzania poprawności klienta.

Pierwszym krokiem jest napisanie FluentValidationPropertyValidator:

public class LessThanOrEqualToFluentValidationPropertyValidator : FluentValidationPropertyValidator 
{ 
    public LessThanOrEqualToFluentValidationPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator) 
     : base(metadata, controllerContext, rule, validator) 
    { 
    } 

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() 
    { 
     if (!this.ShouldGenerateClientSideRules()) 
     { 
      yield break; 
     } 

     var validator = Validator as LessThanOrEqualValidator; 

     var errorMessage = new MessageFormatter() 
      .AppendPropertyName(this.Rule.GetDisplayName()) 
      .BuildMessage(validator.ErrorMessageSource.GetString()); 

     var rule = new ModelClientValidationRule 
     { 
      ErrorMessage = errorMessage, 
      ValidationType = "lessthanorequaldate" 
     }; 
     rule.ValidationParameters["other"] = CompareAttribute.FormatPropertyForClientValidation(validator.MemberToCompare.Name); 
     yield return rule; 
    } 
} 

który zostanie zarejestrowany w Application_Start podczas konfigurowania naszego dostawcy FluentValidation:

FluentValidationModelValidatorProvider.Configure(x => 
{ 
    x.Add(typeof(LessThanOrEqualValidator), (metadata, context, rule, validator) => new LessThanOrEqualToFluentValidationPropertyValidator(metadata, context, rule, validator)); 
}); 

a ostatni bit jest adapter zwyczaj na kliencie . Więc dodajemy oczywiście 2 skrypty do naszej strony, aby umożliwić dyskretne walidacji po stronie klienta:

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script> 

i zasilacz niestandardowe:

(function ($) { 
    $.validator.unobtrusive.adapters.add('lessthanorequaldate', ['other'], function (options) { 
     var getModelPrefix = function (fieldName) { 
      return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); 
     }; 

     var appendModelPrefix = function (value, prefix) { 
      if (value.indexOf("*.") === 0) { 
       value = value.replace("*.", prefix); 
      } 
      return value; 
     } 

     var prefix = getModelPrefix(options.element.name), 
      other = options.params.other, 
      fullOtherName = appendModelPrefix(other, prefix), 
      element = $(options.form).find(":input[name=" + fullOtherName + "]")[0]; 

     options.rules['lessthanorequaldate'] = element; 
     if (options.message != null) { 
      options.messages['lessthanorequaldate'] = options.message; 
     } 
    }); 

    $.validator.addMethod('lessthanorequaldate', function (value, element, params) { 
     var parseDate = function (date) { 
      var m = date.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/); 
      return m ? new Date(parseInt(m[1]), parseInt(m[2]) - 1, parseInt(m[3])) : null; 
     }; 

     var date = parseDate(value); 
     var dateToCompareAgainst = parseDate($(params).val()); 

     if (isNaN(date.getTime()) || isNaN(dateToCompareAgainst.getTime())) { 
      return false; 
     } 

     return date <= dateToCompareAgainst; 
    }); 

})(jQuery); 
+0

@iwayneo, OK. Pierwsze pytanie, które mam, to czy właściwość, którą porównujesz w walidatorze LessThanOrEqualTo, ma odpowiednie pole w formie, tzn. Czy porównujesz wartość dynamiczną (która może zostać zmieniona przez użytkownika w polu wejściowym), czy też jest to wartość, którą ta właściwość miała w momencie renderowania widoku? –

+0

właściwość sprawdzana jest polem formularza - zaświadczenie, z którym się porównujemy jest statycznym polem nie podlegającym edycji znanym z chwili renderowania widoku - przechowujemy je w ukrytym polu w formie – iwayneo

+0

@iwayneo, przechowujesz wartość porównać w ukrytym polu ??? Poczekaj minutę. Co uniemożliwiłoby użytkownikowi użycie np. FireBug do zmodyfikowania wartości tego ukrytego do jakiejkolwiek daty, której chce, a następnie wprowadzenia dowolnej daty, którą chce w polu wejściowym, a tym samym zwarcia nawet po sprawdzeniu poprawności serwera? To duże zagrożenie bezpieczeństwa dla twojej aplikacji. Jak można porównać z wartością pochodzącą od klienta (ukryte pole w tym przypadku, ale łatwo można je zmienić)? –

5

przykład Darin ma pewne przestarzałe rzeczy w nim, więc tutaj jest bardziej zaktualizowanym przykładem, który mam, który porównuje liczby.Można łatwo dostosować go do aktualnych porównań choć:

Javascript:

(function ($) 
{ 
    $.validator.addMethod("lessthanorequal", function(value, element, param) 
    { 
     return this.optional(element) || parseFloat(value) <= parseFloat(param); 
    }, "Must be less than"); 

    $.validator.unobtrusive.adapters.add("lessthanorequal", ["field"], function (options) 
    { 
     options.rules["lessthanorequal"] = options.params.field; 
     if (options.message) options.messages["lessthanorequal"] = options.message; 
    }); 
})(jQuery); 

C#

public class LessThanOrEqualPropertyValidator : FluentValidationPropertyValidator 
{ 

    public LessThanOrEqualPropertyValidator(ModelMetadata metadata, ControllerContext controllerContext, PropertyRule rule, IPropertyValidator validator) 
     : base(metadata, controllerContext, rule, validator) 
    { 
    } 

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() 
    { 
     if (!ShouldGenerateClientSideRules()) yield break; 

     var formatter = new MessageFormatter().AppendPropertyName(Rule.PropertyName); 
     string message = formatter.BuildMessage(Validator.ErrorMessageSource.GetString()); 
     var rule = new ModelClientValidationRule 
     { 
      ValidationType = "lessthanorequal", 
      ErrorMessage = message 
     }; 

     rule.ValidationParameters["field"] = ((LessThanOrEqualValidator)Validator).ValueToCompare; 
     yield return rule; 
    } 
} 

Global.asax Application_Start:

FluentValidation.Mvc.FluentValidationModelValidatorProvider.Configure(x => 
{ 
    x.Add(typeof(LessThanOrEqualValidator), (metadata, context, description, validator) => new LessThanOrEqualPropertyValidator(metadata, context, description, validator)); 
}); 

Tak więc teraz każda reguła liczbowa, która używa LessThanOrEqual, będzie sprawdzana po stronie klienta.

+0

Sprawdzanie poprawności strony klienta działa dobrze, ale komunikat o błędzie nie jest dobrze "Formularz" "musi być mniejszy lub równy" {ComparisonValue} ".' – Willy

+0

Występuje również problem z formatem daty, używam wzorca dd/MM/rrrr, na przykład bieżąca data to 20/10/2014. Jeśli wypełni się 15/10/2014, wyświetli komunikat "Wartość" PurchaseOrderDate "musi być mniejsza lub równa" {ComparisonValue} "." – Willy

Powiązane problemy