Wednesday, 9 November 2011

Øredev 2011, Day 1

I have never been to Øredev before. I must say I’m impressed so far. I like that it’s not so commercialized. Google and Microsoft together as friends as Phil Haacked twittered!

Keynote - Alexis Ohanian - Only your mom wants to use your website

Very good talk by Alexis! He mostly talked about the importance of really caring about your users. You should give a damn! As he put it. Only your mom cares about your lovely website, so to really stand out, you have to do something extra. Care about your users! Make something innovative to make them stay on your site. Bring your idea to life. The "old" sites that throws up hundreds of popups - the don't care about their users. He put his own created reddit as a good example, of course!

The talk was not so applicable to my current job situation as I mostly develop internal applications. But really good anyway!

Some small points I will bring with me:
  • Example of a great idea: make a lyrics site without obtrusive ads and popups (of course it's already on its way...).
  • Paging is bad! So glad someone says it. If you have like 20 pages of something - your not caring about your users. There not interested in 20 pages of something. Rethink!
  • Hipmunk: a flight booking site with a genius sorting: "Agony"! That's caring about your users! You don't want the cheapest flight if it's giving you agony!


Javascript effects - Seb Lee-Delisle
Also very good speaker and presenter! Maybe he felt that we scandinavians were a bit shy when we didn't respond to his "energy"? :-) He was hysterically funny too! Like it!

He skipped his slides and starting coding instead. Yay! In less than 30 minutes he had created an animated growing and swaying tree with HTML5 canvas and Javascript! Very impressive! Watch it here (its only html and js so source code is there automatically): http://dl.dropbox.com/u/5096013/ConfStuff/OredevTree.html. You need a good browser like Firefox (even Chrome seems to dislike it)

He also had a server to which all spectators (with an iPhone or Android) connected to - with a browser (i.e. an url)!. Then he started "playing" with all our phones :-) Started flashing with them in a cool wave and all kinds of stuff. Very cool! We also played a little game with all our phones - together! All with Javascript in the mobile browser. The things you can do nowadays...

More cool stuff can be found here http://creativejs.com/

.NET Collections Deep Dive - Gary Short

Love the scottish accent! :-)

He went through all the performance impacts of various collections and what is good for what. One type is great at insert, remove etc (like LinkedList) and some are great at lookups (like Dictionary)
One very interesting thing he mentioned was to always create a List with a initial size! If you don't the list grows with the double size for every add! 2, 4, 8, 16, 32, 64... And under the hood an Array.Copy() is done. Not so efficient! But if you initialize it with a given size - it also grows with that size. E.g. List(10) will grow with 10 for every add (10, 20, 30...).

Even if you create a list with initial values (List {1,2,3,4,5,6,7,8,9}) you should give it a default size (List(10) {1,2,3,4,5,6,7,8,9}). Because behind the scene it's doing Array.Copy() (and growing with the double size) for every value.

Also, never use List.Add() in a loop. Use AddRange() instead. Performance costs!

Still. All these perfomance costs are only noticable for > 10 000 items. So I don't know..?

HybridDictionary. Google it! :-)

Websockets: Hype or What? - Peter Moskovits

He used Prezi in his presentation - very powerful and different and interactive! I must start using it too!

HTTP is only half-duplex with quite a bit of overhead for every call (because that's how it is designed to work, and fits the needs great). Websockets is full-duplex with 2 bytes of overhead. That's right, 2 bytes! This means tremendous throughput! He had tested with 50K clients sending 50K mesages with < 3 ms latency! Impressive!

WebSockets are an W3C standard but also an IETF protocol. That means finally we have a standard that can be used in almost any browser on any plattform. There are also emulators for older browsers.
You can check if your browser support for websockets on http://websockets.org/ or more details on http://caniuse.com/ (and look for websockets).
Think of all the applications you can build when latency is almost 0. If you update something on a site with your mobile, the change can be instantly shown on your desktop browser. I mean instantly!
Some cool demos:

Mobile Web using MVC 4, HTML 5 and jQuery Mobile - Phil Haack

I don't believe that mobile apps are the future (neither did Steve Jobs). If our company is ever going to build a mobile app it will be a web app for phones. We can't simply ignore all Android and iPhone users and just create an WP7 app! And we don't have customers with a budget to build and maintain all three platforms.

The solution is mobile web apps!

Phil's talk was more a demo of the beauty of jQuery Mobile than anything else. Intentionally or not, I don't know...
Some cool tips to make your current web app a mobile web app:

Architecture Without an End State - Michael Nygard

Don't know what to say. Goog presentation, hard to describe here. I don't think I was the right target for this speak. It didn't give me that much. I'll leave it.

Kinect for Windows - Tess Ferrandez

Very cool stuff you can do with the Kinect SDK för Windows (still in beta though).

She live-coded some tracking for skeleton detection and more. Very fun to interact physically and vocally with your app :-). Another guy (can't remember his name) had made a gesture learning app with kinect. He demonstrated it on stage. He fired up the app and told it "Record me!" (the app started "recording"). He made a posture and said "record!" and the posture was recorded. He repeated that three times and know the app had learned a new gesture! Then he said "Watch me!" and the app started watching. Then he made the gesture and the app detected that he made the gesture.

Another guy had made his home a bit interactive by turning on and off lights in the room depending on where i were in the room.

Keynote - Abstraction Distraction - Neal Ford

I my opinion, the best talk of the day! Best speaker!

The reason for that is that many of the things he said was things that I said on an internal company talk I held about NUI (Natural User Interface). The folder and file system abstraction is bad, the save-button abstraction is bad etc...

Or, other things like why the gmail "labels" are way better than putting mail in folders a la Outlook. Because a mail can be about many things, not just one thing (which suits in a folder)! And with the label abstraction we can now specify the only egg-laying mammal platipus :-). Which we can't with the standard hierarchical abstraction.

Very hard to summarize all the things he said...

But in a nutshell what he said was that any abstraction is inperfect. You just have to know it and adapt to the that fact.


Sorry for all the typos and bad english, it's late and my head is kind of full...

Wednesday, 2 November 2011

Running deployment package with 'IIS Web Application Name' as parameter

It doesn’t work in VS2010 sp1…

But there’s a hotfix: http://support.microsoft.com/kb/2537134. (I went for solution 3)

Now I can run the deployment package manually as:

Or you can skip the -setParam:name='IIS Web Application Name' part by editing project settings for the current configuration:

2011-11-02_1137

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…