I'm currently implementing xVal client-side validation. The server-side validation is working correctly at the moment.
I have referenced xVall.dll (from xVal1.0.zip) in my project as well as the System.ComponentModel.DataAnnotations and System.web.mvc.DataAnnotations from the Data Annotations Model Binder Sample found at http://aspnet.codeplex.com/releases/view/24471. I have modified the method BindProperty in the DataAnnotationsModelBinder class since it returned a nullpointer exception telling me the modelState object was null. Some blogposts described to modify the method and I did according to this SO post.
Next I put the following lines in my global.asax:
protected void Application_Start()
{
// kept same and added following line
RegisterModelBinders(ModelBinders.Binders); // Add this line
}
public void RegisterModelBinders(ModelBinderDictionary binders) // Add this whole method
{
binders.DefaultBinder = new Microsoft.Web.Mvc.DataAnnotations.DataAnnotationsModelBinder();
}
Now, I have made a partial class and a metadata class since I use the entity framework and you cannot create partial declarations as of yet so I have:
[MetadataType(typeof(PersonMetaData))]
public partial class Persons {
// ....
}
public class PersonMetaData {
private const string EmailRegEx = @"^(([^<>()[\]\\.,;:\s@\""]+"
+ @"(\.[^<>()[\]\\.,;:\s@\""]+)*)|(\"".+\""))@"
+ @"((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
+ @"\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+"
+ @"[a-zA-Z]{2,}))$";
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required(ErrorMessage="Please fill in your email")]
[RegularExpression(EmailRegEx,ErrorMessage="Please supply a valid email address")]
public string Email { get; set; }
}
And in my controller I have the POST edit method which currently still use a FormCollection instead of a Persons object as input. I have to change this later on but due to time constraints and some strange bug this isnt done as of yet :). It shouldnt matter though. Below it is my view.
//
// POST: /Jobs/Edit/5
//[CustomAuthorize(Roles = "admin,moderator")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit([Bind(Exclude = "Id")]FormCollection form) {
Persons person = this.GetLoggedInPerson();
person.UpdatedAt = DateTime.Now; // Update the updated time.
TryUpdateModel(person, null, null, new string[]{"Id"});
if (ModelState.IsValid) {
repository.SaveChanges();
return RedirectToAction("Index", "ControlPanel");
}
return View(person);
}
#endregion
My view contains a partial page containing the form. In my edit.aspx I have the following code:
<div class="content">
<% Html.RenderPartial("PersonForm", Model); %>
</div>
</div>
and in the .ascx partial page:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<WerkStageNu.Persons>" %>
<% if (!Model.AddressesReference.IsLoaded) { %
<% Model.AddressesReference.Load(); %
<% } %
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>General information</legend>
<table>
<tr>
<td><label for="FirstName">FirstName:</label></td><td><%= Html.TextBox("FirstName", Model.FirstName)%><%= Html.ValidationMessage("FirstName", "*")%></td>
</tr>
<tr>
<td><label for="LastName">LastName:</label></td><td><%= Html.TextBox("LastName", Model.LastName)%><%= Html.ValidationMessage("LastName", "*")%></td>
</tr>
<tr>
<td><label for="Email">Email:</label></td><td><%= Html.TextBox("Email", Model.Email)%><%= Html.ValidationMessage("Email", "*")%></td>
</tr>
<tr>
<td><label for="Telephone">Telephone:</label></td><td> <%= Html.TextBox("Telephone", Model.Telephone) %><%= Html.ValidationMessage("Telephone", "*") %></td>
</tr>
<tr>
<td><label for="Fax">Fax:</label></td><td><%= Html.TextBox("Fax", Model.Fax) %><%= Html.ValidationMessage("Fax", "*") %></td>
</tr>
</table>
<%--<p>
<label for="GenderID"><%= Html.Encode(Resources.Forms.gender) %>:</label>
<%= Html.DropDownList("GenderID", Model.Genders)%>
</p> --%>
</fieldset>
<fieldset>
<legend><%= Html.Encode(Resources.Forms.addressinformation) %></legend>
<table>
<tr>
<td><label for="Addresses.City"><%= Html.Encode(Resources.Forms.city) %>:</label></td><td><%= Html.TextBox("Addresses.City", Model.Addresses.City)%></td>
</tr>
<tr>
<td><label for="Addresses.Street"><%= Html.Encode(Resources.Forms.street) %>:</label></td><td><%= Html.TextBox("Addresses.Street", Model.Addresses.Street)%></td>
</tr>
<tr>
<td><label for="Addresses.StreetNo"><%= Html.Encode(Resources.Forms.streetNumber) %>:</label></td><td><%= Html.TextBox("Addresses.StreetNo", Model.Addresses.StreetNo)%></td>
</tr>
<tr>
<td><label for="Addresses.Country"><%= Html.Encode(Resources.Forms.county) %>:</label></td><td><%= Html.TextBox("Addresses.Country", Model.Addresses.Country)%></td>
</tr>
</table>
</fieldset>
<p>
<input type="image" src="../../Content/images/save_btn.png" />
</p>
<%= Html.ClientSideValidation(typeof(WerkStageNu.Persons)) %>
<% } %
Still nothing really stunning over here. In combination with the edited data annotation dlls this gives me server-side validation working (although i have to manually exclude the "id" property as done in the TryUpdateModel). The strange thing is that it still generates the following script in my View:
xVal.AttachValidator(null, {"Fields":[{"FieldName":"ID","FieldRules":
[{"RuleName":"DataType","RuleParameters":{"Type":"Integer"}}]}]}, {})
While all the found blogposts on this ( 1, 2 ) but all of those are old posts and all say it should be fixed from xVal 0.8 and up.
The last thing I found was this post but I did not really understand. I referenced using Visual Studio - add reference -- browse - selected from my bin dir where I stored the external compiled dlls (copied to the bin dir of my project).
Can anyone tell me where the problem originates from?