Monday 24 October 2011

NLog and config transform

To make config transforms work with NLog you need to modify the config transform file slightly.
Edit the configuration in the transform file:

Now you can transform the nlog section in your config file like this:

Sunday 9 October 2011

MVC 3: Custom Validation

Every time you need validation in an application you end up with something that needs a specific validation rule.

There’s lots of blog post on how to implement custom validation using MVC 3 and jQuery validation (+unobtrusive). So why write another one? I’m going to share my thoughts on how it’s working and the steps for implementing it. Thus, this may be more of a note to my self…

Lets say we want to validate a Swedish personal identity number (it has a specific format and a control number suffix, it’s unimportant for this example, just mentioning something that's not built-in :-)). I like to start with the JavaScript part. Since user interaction response should be as quickly and close to the interaction as possible.

First register the JavaScript function (that will perform the actual validation) to the jquery validator plugin:
   1: $.validator.addMethod('personalid', function (value, element, params) {
   2:     // Check if the field is optional
   3:     if (this.optional(element))
   4:         return true;
   5:  
   6:     // Do some validation here (return true or false).    
   7:  
   8:     return true;
   9: });
Now we have a function called “personalid” that will be called on validation. The name "personalid" is important, it will be used later. Keep it in mind!
  • value: the value to validate.
  • element: the element being validated
  • params: we’ll get to this later.
Next we also register to the unobtrusive validation adapter. It will convert the HTML5 data-val-personalid to a format that jQuery validator can handle. We’ll get to that later.
1: $.validator.unobtrusive.adapters.addBool('personalid');
Here we have some different functions to choose from. Depending on which we use, it will affect the params parameter in the previous function registration, like this:
  • addBool(‘personalid’): (the one we use) – params will be true.
  • addSingleVal(‘personalid’, ‘someparam’): params will contain a provided value (I'll show a little about that later…).
  • addMinMax(‘personalid’, ‘minparam’, ‘maxparam’): params will have params.min and params.max attributes containing values by HTML5 data attributes.
  • add: full “control”. requires a more detailed example:
1: $.validator.unobtrusive.adapters.add("personalid", ["param1", "param2", "param3"],
   2:     function (options) {
   3:         options.rules['personalid'] = {
   4:             param1: options.params.param1,
   5:             param2: options.params.param2,
   6:             param3: options.params.param3
   7:         };
   8:         options.messages['personalid'] = options.message;
   9:     }
  10: );
Here params will contain params.param1, params.param2 and params.param3.

Back to our validation. We only use addBool so let's write some C# for server validation and also to generate the HTML5 data-attributes to the MVC view.
1: public sealed class PersonalIdentityNumberAttribute : ValidationAttribute, IClientValidatable
   2: {
   3:     private const string DefaultErrorMessage = "Invalid {0}";
   4:  
   5:     public string SomeParam { get; set; }
   6:  
   7:     public PersonalIdentityNumberAttribute()
   8:         : base(DefaultErrorMessage)
   9:     { }
  10:  
  11:     public override string FormatErrorMessage(string name)
  12:     {
  13:         // "name" is DisplayName of the property being validated.
  14:         // ErrorMessageString is set in constructor.
  15:         return string.Format(ErrorMessageString, name);
  16:     }
  17:  
  18:     protected override ValidationResult IsValid(object value, ValidationContext validationContext)
  19:     {
  20:         if (value == null)
  21:             return ValidationResult.Success;
  22:  
  23:         // Do some validation here, return ValidationResult.Success or new ValidationResult() for error.
  24:  
  25:         return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
  26:     }
  27:  
  28:  
  29:     public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
  30:     {
  31:         ModelClientValidationRule clientValidationRule = new ModelClientValidationRule
  32:                                                              {
  33:                                                                  ErrorMessage = FormatErrorMessage(metadata.DisplayName),
  34:                                                                  ValidationType = "personalid"
  35:                                                              };
  36:         clientValidationRule.ValidationParameters.Add("someparam", SomeProperty);
  37:  
  38:         return new[] {clientValidationRule};
  39:  
  40:     }
  41: }

I think you can read the code yourself. Just some notes; SomeParam is totally unnecessary, I just want to show the principle. It will not even be parsed since we uses addBool, hence extra params will be ignored. But most important see lines 31-36, ValidationType is important. It corrolates to the name we registered in the jQuery validation above (addBool). I told you to remember this name ("personalid")! Also ValidationParameters.Add is important since it belongs to the name of addSingleVal above (but we don't use that one in this example). Or we can add more properties and use the add jQuery validation function.

Now we can use this attribute in our model:
   1: [Required(ErrorMessage = "Required")]
   2: [PersonalIdentityNumber(SomeParam = "foo")]
   3: [Display(Name = "Personal Identity Number")]
   4: public string PersonalIdentityNumber { get; set; }
Since we’ve implemented GetClientValidationRules this will be rendered as:
<input 
data-val="true" 
data-val-personalid="Invalid Personal Identity Number" 
data-val-personalid-someparam="foo"
data-val-required="Required"
id="PersonalIdentityNumber" name="PersonalIdentityNumber" type="text" value="" />

data-val-personalid comes from ValidationType (data-val-xxx) and has the value of the DisplayName. data-val-personalid-someparam comes from ValidationParameters.Add and has the value of SomeParam.

Now this can be used by the unobtrusive JavaScript we registered. And we have also created the server side validation.

If we had used the addSingleVal('personalid', 'someparam') instead, the params parameter would have been 'foo':
$.validator.addMethod('personalid', function (value, element, params) {
alert(params); // will alert: 'foo'
}

Or, if we had used add('personalid', ['param1', 'param2', 'param3']) instead (and had properties in the C# code, above, for them) the params parameter would have attributes like this:
data-val-personalid-param1="one"
data-val-personalid-param2="two"
data-val-personalid-param3="three"

$.validator.addMethod('personalid', function (value, element, params) {
alert(params.param1); // will alert: 'one'
alert(params.param2); // will alert: 'two'
alert(params.param3); // will alert: 'three'
}


Want to know how to really validate a swedish personal identity number? Read more here http://en.wikipedia.org/wiki/Personal_identity_number_(Sweden)

Friday 7 October 2011

MVC 3: Disable submit button on invalid input

…or enable it on valid input :-)
In a previous post I talked about having the submit (save) button disabled until valid input.
But how do you do that? I’m going to show you a way to do it using MVC 3 and its support for unobtrusive javascript/ajax. Remember this is *a* way, not *the* way to do it. Feel free to criticize it any way you want :-)
First my View (with just a single field):
   1: <div id="RegistrationPanel">
   2:     @using (Html.BeginForm("Save", "Registration"))
   3:     {
   4:         <div class="editor-label">
   5:             @Html.LabelFor(m => m.Name)
   6:         </div>
   7:     
   8:         <div class="editor-field">
   9:             @Html.TextBoxFor(m => m.Name)
  10:             @Html.ValidationMessageFor(m => m.Name)
  11:         </div>
  12:     
  13:         <input type="submit" value="Register" />
  14:     }
  15: </div>


Then my Model:
   1: public class RegistrationModel
   2: {
   3:     [Required(ErrorMessage = "Required field")]
   4:     [DisplayName("Name")]
   5:     public string Name { get; set; }
   6: }
Nothing special, very straight forward, very simplified. Using the built in support in MVC 3 for unobtrusive validation. As a note you can see I’m not using the Ajax.BeginForm, because I don’t like it. To much “magic” a la WebForms. I want to know (and control) what’s going on.

But now, let’s get on with the button disabling stuff.

First make sure you include all the javascript files you need:
   1: <script src="@Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script>
   2: <script src="@Url.Content("~/Scripts/jquery-ui-1.8.16.min.js")" type="text/javascript"></script>
   3: <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
   4: <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
   5: <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
   6: <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>

The modernizr isn’t really needed here, but I include it anyway.

Then I also include a javascript file for my View. It contains all the “good” stuff:
   1: var Registration = (function () {
   2:     var form;
   3:     var submitButton;
   4:   
   5:     return {
   6:         Init: function () {
   7:             form = $('#RegistrationPanel form');
   8:             submitButton = form.find('input[type=submit]');
   9:             submitButton.button();
  10:  
  11:             // Get jquery validator object
  12:             var validator = form.data('validator');
  13:             // Hook into the jquery validator showErrors event
  14:             validator.settings.showErrors = function () {
  15:                 var nrOfInvalids = this.numberOfInvalids();
  16:                 var buttonVerb = (nrOfInvalids > 0) ? 'disable' : 'enable';
  17:                 submitButton.button(buttonVerb);
  18:                 this.defaultShowErrors(); // also execute default action
  19:             };
  20:   
  21:             form.submit(function () {
  22:                 if (form.valid()) {
  23:                     $.post(form.attr('action'), form.serialize(), function (jsonData) {
  24:                         // Notify user about success
  25:                     },
  26:                     'json');
  27:                 }
  28:                 return false;
  29:             });
  30:         }
  31:     };
  32: })();
  33:  
  34: $(function() {
  35:     Registration.Init();
  36: });
That does it! I hook up to an event in the jquery validator showErrrors event http://docs.jquery.com/Plugins/Validation/validate#toptions (for disabling/enabling submit button).

This also keeps the server validation (TryUpdateModel).

jqGrid and BeautyTips

I love jqGrid. I also like (not love) BeautyTips for creating nicer tooltips or better known as “talk bubbles” or “help balloons”.
The combination of jqGrid and BeautyTips is great when you have a row where there are some kind of “comment” for the row or other large textual information.
2011-10-07_1138
The problem with BeautyTips is that it doesn’t work very well with relative positioned elements - like jqGrid! What happens is that the comment becomes hidden behind the jqGrid header/footer, like this:
2011-10-07_1140
The good thing is that BeautyTips has a setting called offsetParent. That property tells BeautyTips in which DOM-object the tooltip (balloon) should be appended. Default is the body DOM-object which causes the problem. But if we append the tooltip into the jqGrid DOM (a div). The problem is solved! We just need to find what the jqGrid top DOM object is. jqGrid uses an id for its created top DOM element: “gbox_XXX”. E.g.:
   1: offsetParent: $('#gbox_gridId')
“gridId” is the id of the table you use for jqGrid:

   1: <table id="gridId"></table>


   1: $('#gridId').jqGrid({...});
Now we get a nice looking tooltip, like the first picture above.

Thursday 6 October 2011

Notes on upgrading MVC 2 to MVC 3

Finally found the time to upgrade a customers MVC 2 project to MVC 3 (something has always been more important).
There are a great tool for upgrading an MVC 2 project. More info found here: http://blogs.msdn.com/b/marcinon/archive/2011/01/13/mvc-3-project-upgrade-tool.aspx.
So far so good. But ReSharper (5.1.3000.12) started to give me a lot of errors in my views. First there was “Cannot resolve symbol Html/Url” etc. That problem was solved by deleting the cache files (xxx.Resharper.user). But then it started given my errors on
   1: <%=Html.LabelFor(m => m.xxx) %>
saying System.Core should be referenced. This was solved by adding

   1: <Reference Include="System.Core">
   2:   <Private>True</Private>
   3: </Reference>
in the csproj-file.
Now everything seems alright…