ASP.NET MVC remote validation
A model validation az egyik kedvencem az ASP.NET MVC-ben. Egy helyre kerül minden, ami a validáláshoz kell, ráadásul a jQuery validationnek köszönhetően a beépített “validátorok” nagyon jól működnek kliens oldalon is.
Legyen mondjuk egy klasszikus Person modell osztályunk, amire könnyen felaggathatom a validálási szabályokat leíró attribútumokat:
public class Person { [DisplayName( "E-mail cím:" )] [Required( ErrorMessage = "Az e-mail cím megadása kötelező! ")] public string Email { get; set; } [DisplayName( "Felhasználónév:" )] [Required( ErrorMessage = "A felhasználónév megadása kötelező! " )] public string UserName { get; set; } [DisplayName( "Jelszó:" )] [Required( ErrorMessage = "A jelszó megadása kötelező! " )] public string Password { get; set; } }
A view-ba pedig csak @Html.ValidationMessageFor hívások kellenek a hibaüzenetek megjelenítéséhez (amiket egyébként a VS le is generál magától):
@using( Html.BeginForm() ) { @Html.ValidationSummary( true ) <fieldset> <legend>Regisztráció</legend> <div class="editor-label"> @Html.LabelFor( model => model.Email ) </div> <div class="editor-field"> @Html.EditorFor( model => model.Email ) @Html.ValidationMessageFor( model => model.Email ) </div> <div class="editor-label"> @Html.LabelFor( model => model.UserName ) </div> <div class="editor-field"> @Html.EditorFor( model => model.UserName ) @Html.ValidationMessageFor( model => model.UserName ) </div> <div class="editor-label"> @Html.LabelFor( model => model.Password ) </div> <div class="editor-field"> @Html.EditorFor( model => model.Password ) @Html.ValidationMessageFor( model => model.Password ) </div> <p> <input type="submit" value="Mehet" /> </p> </fieldset> }
A helyzet akkor kezd bonyolódni, amikor kliens oldalon szeretnénk validálni, de az input ellenőrzési logika vagy a hozzá szükséges egyéb adatok szerver oldalon vannak, például egy adatbázisban. Még kellemetlenebb a helyzet, ha ráadásul nem is egyetlen mező értékét kell ellenőriznünk, hanem több adat együttállását kell vizsgálnunk. Ezt megoldhatnánk egy postback után a controllerben, de sokkal felhasználóbarátabb, ha Ajaxosan oldjuk meg, hiszen így már az űrlap kitöltése közben tudjuk figyelmeztetni a felhasználót, hogy javítsa ki a beírt értékeket. Szerencsére erre a problémára van közvetlen megoldás az ASP.NET MVC-ben, úgy hívják, hogy remote validation. Így kell beizzítani:
A modellben adjunk egy Remote attribútumot a validálandó mezőhöz:
[Remote( "ValidateUserNameAndEmail", "Home", AdditionalFields = "Email" )] public string UserName { get; set; }
Itt meg kell adnunk, hogy melyik controller action lesz az Ajax hívás szerver oldali végpontja. Ha több mező értékére van szükségünk szerver oldalon, akkor használhatjuk az AdditionalFields paramétert. A fenti példában a validálás akkor fog megtörténni, amikor a UserName mező értéke megváltozik és a szerverhez el fog jutni az Email mező értéke is, az esetleges hibaüzenet pedig a UserName mező mellett fog megjelenni. Szerencsére semmi akadálya annak, hogy ugyanezt az attribútumot ráakasszuk az Email mezőre is, AdditionParameterkent a UserName mezőt adva meg.
Már csak a hivatkozott controller actiont kell megírnunk, például így:
[OutputCache( NoStore = true, Location = OutputCacheLocation.None )] public JsonResult ValidateUserNameAndEmail( string userName, string email ) { return this.IsValid( userName, email ) ? this.Json( true, JsonRequestBehavior.AllowGet ) : this.Json( "Ezzel a névvel és e-mail címmel már létezik regisztráció!", JsonRequestBehavior.AllowGet ); }
A valódi ellenőrző logikát áttettem egy IsValid függvénybe, hogy itt ne zavarjon. A lényeg:
- Klasszikus controller action azokkal a paraméterekkel, amiket ellenőrizni szeretnénk. Ha van a modellben AdditionalFields, akkor mindet.
- Válaszként egy JsonResult típussal kell visszatérnünk.
- Ha az adat helyes, akkor a válasz true, ha hibás, akkor a hibaüzenet.
- Meg kell adni a JsonRequestBehavior.AllowGet paramétert, anélkül nem fog menni.
- Célszerű az OutputCache-t kikapcsolni, hogy a böngésző ne gyorsítótárazza a választ.
A hibaüzenet a Html.ValidationMessageFor helyén fog megjelenni, tehát a view-n nem kell változtatnunk. Ha nem a Studio generálta a markupot, hanem mi írtuk, akkor arra érdemes figyelni, hogy legyen benne Html.BeginForm, mezei <form> elemre tapasztalataim szerint nem működik.
Mindössze ennyi, az Ajaxos bűvészkedést az ASP.NET megcsinálja helyettünk. Íme az eredmény:
Akit szeretné lerántani a leplet a varázslatról, az nézze meg a generált markupban a data-val-remote- attribútumokat és figyelje meg a HTTP forgalmat például Fiddlerrel. Érdemes!
MSDN Kompetencia Központ