This morning I’ve released xVal 0.8 (Beta). It’s a fairly substantial update – it adds the following features:
- Support for NHibernate.Validator (in addition to the existing support for System.ComponentModel.DataAnnotations and Castle Validator)
- Internationalization of default client-side messages
- Much easier to implement custom validation logic (server-side and client-side)
- Fluent syntax for defining ad-hoc validation rules directly in a view
- Support for comparison validators (e.g., “PasswordConfirm” must equal “Password”)
- Works with ASP.NET MVC Release Candidate
- Better performance (rules are now cached per model type)
- A few bugfixes
To recap, xVal is a validation framework bridge for ASP.NET MVC. It lets you use whatever server-side validation technology you prefer (and there are plenty that work well with ASP.NET MVC), and then xVal makes client-side validation happen automatically. On the client, you can enable either jQuery.Validation or ASP.NET (WebForms-style) native validation, or you can write your own plugin.
This is a “beta” quality release, in that the feature set is more or less right for 1.0. The short term goal now is not to add any more major features, but instead to focus on providing proper documentation (instead of just blog posts) and make sure it works robustly in all circumstances.
Now I’ll quickly explain the new features in 0.8.
Support for NHibernate.Validator
If you’re using NHibernate, you might also be using NHibernate.Validator. It’s a server-side validation framework that plugs directly into NHibernate’s pipeline, so you can be sure objects never reach the database unless they satisfy your rules.
xVal can now detect NHibernate.Validator rules and translate many of them into client-side rules. To make this work, assuming you already have an application that uses NHibernate.Validator, add a reference to xVal.dll and xVal.RulesProviders.NHibernateValidator.dll and then enable it in your Global.asax.cs file:
protected void Application_Start() { RegisterRoutes(RouteTable.Routes); xVal.ActiveRuleProviders.Providers.Add(new NHibernateValidatorRulesProvider(ValidatorMode.OverrideXmlWithAttribute)); }
If you want to use jQuery.Validator on the client, then add the following references to your master page:
<head runat="server"> <asp:PlaceHolder runat="server"> <script type="text/javascript" src="<%= Url.Content("~/Scripts/jquery-1.3.2.min.js") %>"></script> <script type="text/javascript" src="<%= Url.Content("~/Scripts/jquery.validate.js") %>"></script> <script type="text/javascript" src="<%= Url.Content("~/Scripts/xVal.jquery.validate.js") %>"></script> </asp:PlaceHolder> </head>
Or, if you want to use ASP.NET Native validation on the client, then add the following references to your master page instead:
<head runat="server"> <asp:PlaceHolder runat="server"> <script type="text/javascript" src="<%= Page.ClientScript.GetWebResourceUrl(typeof(System.Web.UI.Page), "WebForms.js") %>"></script> <script type="text/javascript" src="<%= Page.ClientScript.GetWebResourceUrl(typeof(System.Web.UI.Page), "WebUIValidation.js") %>"></script> <script type="text/javascript" src="<%= ResolveUrl("~/Scripts/xVal.AspNetNative.js")%>"></script> </asp:PlaceHolder> </head>
Finally, apply client-side validation in any view by using Html.ClientSideValidation():
<%= Html.ClientSideValidation<member>() %>
Note that before Visual Studio will recognize Html.ClientSideValidation(), you must either add <%@ Import Namespace="xVal.Html" %> to the top of your view, or reference the namespace globally in your web.config file:
<system.web> <pages> <namespaces> <!-- leave rest as-is --> <add namespace="xVal.Html"/> </namespaces> </pages> </system.web>
So now, if your model classes define NHibernate.Validator rules, such as:
public class Member { public virtual int MemberID { get; internal set; } [NotNullNotEmpty] [Length(3, 50)] public virtual string Name { get; set; } [NotNullNotEmpty] [Email] [Length(200)] public virtual string EmailAddress { get; set; } }
… then those rules will be applied on the client:
Note that NHibernate.Validator support is pretty early at the moment. I’m interested to get any feedback about how the client-side interpretation of the rules could be improved (for example, should Date properties automatically be required?).
Internationalization of default client-side messages
It’s always been possible to internationalize the server-generated validation messages – just nominate the resource type and resource string name when defining a rule:
[Required(ErrorMessageResourceType = typeof(MyResourceType), ErrorMessageResourceName = "ValueRequired")]
But it’s inconvenient to have to type that out every time. Wouldn’t it be better if you could also internationalize the default client-generated messages too? Now you can.
To try this out, download the demo project and also the latest xVal release. Copy xVal.Messages.en-US.js from the xVal release into the demo project’s ~/Scripts/ folder, and then reference it from the master page:
<head runat="server"> <asp:PlaceHolder runat="server"> <!-- Leave the other references as they are --> <script type="text/javascript" src="<%= Url.Content("~/Scripts/xVal.Messages.en-US.js") %>"></script> </asp:PlaceHolder> </head>
If you run the project now, it will appear that nothing’s changed. However, simply by referencing xVal.Messages.en-US.js, you’ve told xVal to use messages defined in that file instead of using its built-in defaults. If you want to change the English messages, just edit xVal.Messages.en-US.js.
To support another language, make a copy of xVal.Messages.en-US.js, rename it to refer to the other language (e.g., xVal.Messages.es-ES.js), put that copy in your ~/Scripts/ folder, and then edit the messages so they’re in the other language.
Now, change the reference in your master page:
<script type="text/javascript" src="<%= Url.Content("~/Scripts/xVal.Messages.es-ES.js") %>"></script>
And that’s it! You’ve now got Spanish messages:
If you want to change the language dynamically at runtime, you should add some code that varies which xVal.Messages.*.js file gets referenced, perhaps according to the current thread culture.
Update: Thanks to the community for contributing a comprehensive set of default translations. Language files for Brazilian Portuguese, Danish, Spanish, Dutch, Polish, French, German, and Swedish will be included in the next release.
Implementing Custom Validation Logic
You could previously create custom server-side validation logic by subclassing whatever base class your server-side validation framework uses for validation rules. For System.ComponentModel.DataAnnotations, that means subclassing ValidationAttribute. For Castle Validator, it means making an attribute that implements IValidator.
Now, whatever server-side validation framework you use, you can also make custom rules run custom client-side logic by implementing xVal’s ICustomRule interface.
To try this out, download the demo project and add a new class to the DomainModel project called DivisibleByAttribute:
public class DivisibleByAttribute : ValidationAttribute, ICustomRule { private int Divisor { get; set; } public DivisibleByAttribute(int divisor) { Divisor = divisor; ErrorMessage = string.Format("Must be a multiple of {0}.", divisor); } public override bool IsValid(object value) { if(!(value is int)) return false; return ((int)value) % Divisor == 0; } public CustomRule ToCustomRule() { return new CustomRule( "DivisibleByN", // JavaScript function name new { divisor = Divisor }, // Params for JavaScript function ErrorMessage // Message if invalid ); } }
Since this derives from ValidationAttribute, your DataAnnotations runner will enforce it on the server when you attach it to some model property:
[Required] [Range(1, 20)] [DivisibleBy(4)] public int NumGuests { get; set; }
To run similar logic on the client, implement a JavaScript function called DivisibleByN:
<script type="text/javascript"> function DivisibleByN(value, element, params) { return value % params.divisor == 0; } </script>
Note that you should put this before any call to Html.ClientSideValidation(). Now, you’ll get client-side and server-side validation of your custom rule:
If you want to internationalize your custom rule’s message, then alter DivisibleByAttribute’s ToCustomRule() function so that it uses the CustomRule constructor that lets you specify a resource type and a resource string.
Defining Ad-Hoc Validation Rules in a View
xVal focuses on model based validation. That means you normally define rules in your model layer. However, sometimes it’s useful to throw in a few extra rules that apply only to a specific MVC view. There’s now a quick and easy way of doing this.
To try it out, download the demo project, go to the PlaceBooking.aspx view, and then edit the Html.ClientSideValidation() call to the following:
<%= Html.ClientSideValidation<booking>("booking") .AddRule("Name", new RegularExpressionRule("^[a-z]{3}\\d{3}$", RegexOptions.IgnoreCase) { ErrorMessage = "Must be three letters followed by three numbers." }) .AddRule("BookingDate", new RangeRule(DateTime.Now, null) { ErrorMessage = "Must be in the future." }) %>
(Note: you’ll also need to add a <%@ Import Namespace="xVal.Rules"%> directive to the top of the view.)
Now, your view’s ad-hoc rules will be combined with the model rules:
If you’re the sort of person who doesn’t like model based validation at all, you could use this feature to build your complete rules configuration inline in a view. Just start with a RuleSet.Empty and add ad-hoc rules to it:
<%= Html.ClientSideValidation("booking", RuleSet.Empty) .AddRule("Name", new RequiredRule()) .AddRule("BookingDate", new RequiredRule()) .AddRule("BookingDate", new DataTypeRule(DataTypeRule.DataType.Date)) /* Etc */ %>
The advantages of model-based validation are clear (DRY), but this gives you extra flexibility that might come in handy.
What next?
The next step is to let people start using this and ask for feedback about how it could be improved. I’ll shy away from adding major new features right now because I don’t personally have time to manage an enormous project. I’m more interested in any bugs you might find or ways in which the current feature set could be applied better. There are already a few issues registered on Codeplex that I’ll be attending to, or better still, you could submit a patch!
Just a reminder: if you’re able to provide translations of the language file into any other major language, and if you’re happy for me to include your translation in the next release, please send it to me.Update: Thanks to everyone for all the translations. We’ve now covered all the main ones, so no more are needed.
With thanks to MarkJPerry, DavidHayden, sjmueller, trevor, goneale, imm102, lobex, DerekMcDermott, richardu, Peter Mounce, Billy McCafferty, Mike Saunders, Andrew Scott, Vadim, and various others who have provided useful feedback on the previous release.
47 Responses to xVal 0.8 (Beta) Now Released
I just uploaded a patch on CodePlex with the Brazilian Portuguese translation; will convince my gf to help with the French translation soon
That was quick – we’ve got Brazilian Portuguese, Danish, and Spanish translations already. Thanks folks!
Brilliant. Just a little query, though I have not downloaded the source, I hope it is extensible enough to replace the NH Validators with EntLib validator.
@Kazi – there’s some discussion about supporting Enterprise Library’s Validation Application Block at http://xval.codeplex.com/Thread/View.aspx?ThreadId=44116. Unfortunately, VAB’s design makes it unsuitable for integrating with other systems, though we’re hoping version 5.0 might fix this. It is technically possible to integrate it with xVal, as sjmueller has demonstrated in the discussion I just mentioned, but personally I wouldn’t do this in a real project.
Thanks, this is great and works great
I just send you translated to polish file. Enjoy!
This is a fantastic update – and very timely for me!
The ad-hoc client side rules are very useful – i was wondering just yesterday the best way to validate registration details when a user is registering for my site where no model object exists.
I’m also now busy implementing ICustomRules for my client side validation.
Good work!
Rich
Thanks for this great work.
To support this, I just uploaded a patch with the german translation to codeplex.
Indeed great work.
Uploaded a patch with swedish translations.
Thanks to everyone for all the translations. We now have Brazilian Portuguese, Danish, Spanish, Dutch, Polish, French, German, and Swedish. I really appreciate these contributions.
I think that covers all the ones we need! If someone wants support for another language then they can create and use their own language file but it’s probably best not to include and maintain hundreds of translations in the core product. So, no more translations please.
There’ll be a 0.8.1 release shortly, which will include these language files. Note that internationalisation *does* work just as well with ASP.NET native validation as it does with jQuery.Validate – the documentation claims otherwise, but support was added since then.
Pingback: Reflective Perspective - Chris Alcock » The Morning Brew #297
Pingback: Using MetadataType attribute with ASP.NET MVC xVal Validation Framework « {Programming} & Life
Hello,
congratulations, great work with xVal!
I would like to contribute Czech localization messages, however, there’s a small issue I’d prefer to resolve first. Czech language (and many other) uses inflection – to make validation messages sound “human”, there should be some way to alter the message according to the input value, for example:
“StringLength_Min”: “Prosím zadejte alespoň 1 znak.” (for 1 char)
“StringLength_Min”: “Prosím zadejte alespoň 2 znaky.” (for 2-4 chars)
“StringLength_Min”: “Prosím zadejte alespoň 5 znaků.” (for 5 and more chars)
We can discuss this topic over e-mail if you like.
Pingback: Validation with Asp.net MVC, Xval & IDataerrorInfo | Schotime.net
Can you client-side validate a collection of a class? Let’s say I have a view in which I add n (n >= 2) persons and I want all of them to be valid (i.e.: Name, Surname etc.)?
@Petr – Thanks for pointing that out. I’m not immediately certain how to support that, but I suspect that there must be a well-established solution already present in other internationalization mechanisms. If you can suggest how you think this should work (e.g., how the translation files should be formatted) then please send me an email.
@Andrei – Yes, you certainly can. Presumably all your instances have different prefixes in the HTML, so just call Html.ValidationSummary multiple times (once for each prefix). Shouldn’t be too hard, but in any case is on my list of things to add documentation about.
The 0.5 release worked perfectly for me, but this looks even better.
Thanks a lot Steve. I’ve learnt a lot by plundering through your code as well!
Thank you very much!
Great work on adding NHibernate validation!
what would be nice is the addition of Lightspeed model validation (OR/M from Mindscape company) as it is something similar, attribute & model based, etc…
it is a wish not a command though, but somehow I am using LS more often than NHibernate these days as I am the same oppinion as David Hayden is, it’ll replace L2S anytime soon…
Have you tested this against the RTM of ASP.NET MVC yet?
Thus far I am not aware of any changes between the RC2 and RTM releases. Hopefully not much changed
http://twitter.com/elijahmanor
@Elijah – I will be checking over this very soon, but I don’t anticipate any problems or changes of behaviour
@cowgaR – why not have a go at writing an IRulesProvider for the Lightspeed ORM product yourself? For now I’m focusing on Microsoft and Open Source technologies only.
Thanks for your efforts. I really like being able to use the “buddy” classes as I can in DynamicData with frozen classes. Juan had posted in a response to the earlier blog entry on xVal that it would be nice to have xVal integrate into the existing asp.net MVC error display pattern. AKA, *’s next to fields with the error message text being placed in a validation summary (as an option). I also think it would be useful if the DataAnnotationsValidationRunner code were a method accessible from the ServerSide namespace.
Hi Steve,
I’d like to help with two thing, if nobody already did:
– Italian translation
– EntLib rule provider
PS: please, can you answer me via email? thx
Does the client side produce a validationsummary? I’ve added one in but no luck
@Jon, xVal is a bridge from your server-side validation config to your choice of client-side validation framework. If the client-side validation framework produces errors all collected together in a summary, then that’s what would happen. However, neither jQuery Validation or ASP.NET native validation do this, so xVal doesn’t attempt to provide such a feature.
A few people have asked for this so I may in future look into extending jQuery Validation to do it.
Steve,
I’ve applied xVal to my project but looking at the output of xVal it only provides validation for 3 of my 8 properties on my model. Any ideas?
@Jon, please move this discussion to http://xval.codeplex.com/Thread/List.aspx. Also, you’ll need to provide more information to give us a chance of diagnosing the issue. For example, please post (to the Codeplex forum) a minimal project that reproduces the issue.
Hi Steve, xVal is cool and I’m using it on a product that we are building. I have a question which I’m hoping someone can answer. I want to be able to submit a form via ajax once the form validation has succeeded. In the jQuery docs its says that the correct place to do this is in the submitHandler. The problem is I don’t have anyway (that I know) to get access to the instance of the validator attached to the form. Any ideas?
Dont worry I found out how to do it and it was super easy in the end.
$(‘#form-create-account’).data(‘validator’).settings.submitHandler = function(form)
{
// here I can do my ajax!
}
@Jake – glad you sorted that out. You’re the second person to ask that, so I’ll add it to the list of things to document.
Can I use xVal on an ASP.NET forms (3-tired) application for client side validation using JQUERY?
@Raj – no, it’s for ASP.NET MVC (not ASP.NET WebForms)
Dear Steve,
we are trying to use xVal (0.8) together with the NHibernateValidator (Version 1.0.0.4000) for both, Server – and ClientSide Validation. If we add now the
following Code snippet to get xVal Active on the ClientSide, we run into a Assembly error:
xVal.ActiveRuleProviders.Providers.Add(new NHibernateValidatorRulesProvider(ValidatorMode.OverrideExternalWithAttribute));
Could you maybe please give us a hint how to make this thing working?
//sorry, it’s the NHibernateValidator Version 1.2.0.1003
@Jonas – if you’re using a different version of NHibernateValidator to the one your copy of xVal.RulesProviders.NHibernateValidator.dll is compiled against, it won’t work. Please go to xval.codeplex.com and download the source code for xVal.RulesProviders.NHibernateValidator.dll and recompile it against your version of NHibernateValidator.
I know this is a pain, but that’s fundamentally the nature of assembly versioning. Sorry!
Thanks for xVal and for your book Pro ASP.NET MVC. They have been a real aid to me. ASP.NET MVC validation always seemed to have a gaping hole. You’ve certainly plugged that one up.
I would like to say that a Validation Summary is a very important option, at least to me. Page RealEstate and tidiness can often be handled much better through a summary. In many situations, Customers seem to like it better.
Also your code mentions that some validations will not be accurate with the DataAnnotationsTestRunner. Could you please be more specific?
Hi, I like this very framework very much.
I’m having an issue where I need to redirect form my “Save” action to my “load” action. the problem is that the ModelState is stored in the ViewData and when you redirect to another action you loose it.
SO I’m using ModelStateToTempData form mvcContrib which (obviously) puts the ModelState in the TempData. I’m poking around in the code trying to figure out how I can get the ClientSideValidation to pick up the errors or the modelstate from tempdata, but kind of drawing a blank. If you have any ideas or pointers for me that would be great.
again, very cool framework.
Thanks,
Hi Steve,
Great framework, and great work on the Pro ASP.NET MVC book. I’ve read/worked through it entirely!
I’m working on trying to get the nhibernate.validator integration working. It works great for the basics, but the value type validation doesn’t seem to be making it to the client at all.
For example: I have a user entity, which has an address value type. If there is invalid fields in the address, it will fail validation, but won’t show on the form why it failed, But if any of the regular user fields fails validation it does give the feedback.
Am i doing something wrong or is this something that isn’t implemented yet?
Thanks for the great work so far!
Patricia
Ignore the question in my last comment. I got it figured out. the solution is in the xval codeplex discussion forum!
@Mark – the DataAnnotations attributes don’t come with an official validation runner. For the demo project I supplied a simple one, but it doesn’t handle every combination of rules. From memory, the main thing is that it doesn’t validate email addresses – it says any string is valid. You’d need to enhance the runner to cope with this if you need to use it in your project.
@Raif – from my understanding, what you’re doing should work fine: xVal just sits on top of whatever server-side validation mechanism you’re using, so it should work with ModelStateToTempData. Sorry it took a while to reply – hope you got a solution.
Hi there. Not sure if this is on the xVal side or the DataAnnotations side of things but I figured I’d ask here first. I have two forms (new user, edit user) which use the same model. The two forms share most properties/fields but everything. Some fields in the edit user form will be display only (not an input box), and both forms will have their own extra fields as well.
My question is what is the best way to accomplish server & client side validation using the shared model and validation attributes, when these two forms will have different fields? Basically I’m wondering if there is a way to mark an attribute as optional for one form, but required for another.
My first thought was to implement ad hoc rules but it seems that only works for the client, and I would still have to implement custom server side validation on the server.
In a nutshell, is there an easy way to accomplish having “optional” form fields?
Thanks.
Pingback: xVal v1.0 Now Available « Steve Sanderson’s blog
I followed exactly this example using version 1.0. Everything worked beautifully in development environment. When uploaded to Godaddy, the app registers an eror and displays the error page whether or not the data entered passes validation or not with or without Client Side validation. Spent few hours troubleshooting, could not figure out where the problem is. Started a new app from scartch, and the same thing again. Gave up on it!
How do I use the framework for validating an array of checkboxes? I would like to have at least 1 selected.
Thanks.
Hello. And Bye.
Thanks for contributing your important time to post such an interesting & useful collection.It would be knowledgeable & resources are always of great need to everyone. Please keep continue sharing.