xVal 1.0 not generating the correct xVal.AttachValidator script in view
- by bastijn
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?
EDIT
Adding the reference from the .NET tab fixed the problem somehow. While earlier adding from this tab resulted in a nullpointer error since it used the standard DataAnnotations delivered with the MVC1 framework instead of the freshly build one. Is it because I dropped the .dll in my bin dir that it now picks the correct one? Or why?