Thursday, 23 February 2012

Language selector in ASP.NET MVC 3

Develop web applications with multi lingual (ML) support is always a very tricky affair, in this globalized world we are living nowadays is almost impossible to keep developing web applications without giving the opportunity to visitors from other languages than ours.

I’ll attempt to share with the community some of my strategies in order to give ML support using ASP.NET MVC 3.0, and I think the next versions will be backward compatible regarding these matters. Let’s start, one of the key points for ML is where to store the current language. There are some well-known places, in the session, in some cookie or even in the url.

Each strategy has its own pros and cons, after digging about the SEO and content indexing (here some SO guys talk about) I decided to choose the url as the ideal place for insert the current language the web is going to be displayed to the client. The general idea is to give the sense of “directories” where the language is the first level and the others contents are languages directories’ “children” in the big web content tree.

Having said that, there is another problem coming up: The route, despite the routing system provided by ASP.NET MVC 3.0 is powerful and very flexible, I have to say it’s something obscure to understand by definition (but not impossible), so let’s use an example on how the url should be:

  • http://www.example.com/directory/content/params
  • http://www.example.com/es/directory/content/params
  • http://www.example.com/fr/directory/content/params

Note that the first sample doesn’t have the language explicitly indicated in the url. This will be the default language defined by the site administrator, maybe. Even with this decision there are many things to think about. What to do when there is no language specified in the url? Maybe the easy way, to assume an internal (from configuration or hardcoded) default language, or maybe a better user experience in order to determine the user’s culture from the browser’s request or even a nice solution that a friend of mine implemented: search in a database table the IP address from the request and determine the country and depending on the country, the page is displayed in that language. Finally the concrete strategy is up to you.

Whatever decision you take, it’ll be necessary to have small (or medium size) element usually on top right of the page, which is the language selector. This fellow is responsible for render the links to the entry point in other languages rather than the current one. If you have a fixed number of languages (which I do not recommend, unless your client pays too few for the project, don’t blame it, it’s a joke, don’t do it), there’s not much difficulty so it’s possible to implement a set of links with all the necessary dirty url construction.

But what if the languages amount varies, for example, they come from a database? Then the routing system is here for save the world. At this point I say the whole explanation about how to get these routes is out of the scope of this post, I’ll talk more on details in a dedicated post. (Seriously I promise I’ll do it!) Here are the route samples.

routes.MapRoute(
    "Default_ln", // Route name
    "{lang}/{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", 
        id = UrlParameter.Optional },  // Parameter defaults
    new { lang = "[a-z]{2}(-[A-Z]{2})?" }
);

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", 
        id = UrlParameter.Optional }  // Parameter defaults
);
    

Well, these routes really do not differ too much from the default template in Global.asax.cs at Visual Studio 2010. The order is a key point for the success and the new parameter introduced here is lang in the first route. If the url contains the language as in the second and third in the above urls, they will match the first route ("Default_ln") and if the url does not contain any information about language, then it’ll match the second route ("Default").

Note the regular expression (regex) in the first route as a constrain, I mean, the first segment is a language if and only if the segment content matches the regex, which in fact verifies the culture format (such as es-ES or en-GB, or just es or en) you are free to modify it and don’t be afraid of, the regex don’t bite.

The language selector is to be done in order to the crawler (and the human visitors too) be able to find the content written in other languages. The first (and easiest) solution maybe using static links pointing to the home page, followed by the language code or empty for the default. Really, don’t do that! What if the user has navigated deeper in the content tree? In this case, the user will have to navigate again through the path, and that’s not good. The link should point to the current content path but as child of target language. The routing system allows us to do this just setting properly the values for routeData parameter in any HTML extension method used in the views.

Assuming we have in our viewmodel a propery named Languages which is a list of some class with Code and Name properties. One first implementation could be as follows:

foreach (var lang in Model.Languages)
{
    @Html.ActionLink(lang.Name, null, new {lang = lang.Code})
    @Html.Raw(" ")
}
    

The result is acceptable but there’s a small glitch with url generation, the default language doesn't match with the initial definition about not explicitly show the language, it generates the lang parameter for all language even for the default one. What to do? Or better, why this come about? The origin of this is that we are saying, for each language in the list generate a link with the parameter lang equals this language’s code. We could instead to say, if this language is the default then do not set the parameter lang et c’est tout! As in this fragment:

foreach (var lang in Model.Languages)
{
    if (lang.Code == DefaultLangCode)
    {
        @Html.ActionLink(lang.Name, null, new { })
    }
    else
    {
        @Html.ActionLink(lang.Name, null, new { lang = lang.Code })
    }
    @Html.Raw(" ")
}
    

But that doesn’t work too, why? If we are in the default language (/) everything appears to be ok, but if we change for example to Spanish (/es) then checkout the link to our default (/es)! Surprise! And it should be just /. The reason is behind the scenes of routing system, it “fills” the route parameters with the current parameters explicitly passed as in lang, and falls back with the current request context data and in this case current request has the lang parameter that the explicit parameter did not pass, so finally the link is generated with the parameter lang equals the current lang. Only after to have understood this particular matter about the routing system we are able to fix the issue, as follows:

foreach (var lang in Model.Languages)
{
    if (lang.Code == DefaultLangCode)
    {
        var currentlang = ViewContext.RouteData.Values["lang"];
        ViewContext.RouteData.Values["lang"] = null;

        @Html.ActionLink(lang.Name, null, new {})

        ViewContext.RouteData.Values["lang"] = currentlang;
    }
    else
    {
       @Html.ActionLink(lang.Name, null, new {lang = lang.Code})
    }
    @Html.Raw(" ")
}
    

What’s the trick here? In this case we have said as part of the if condition for the default language, save the current value of route parameter lang in a temporary variable, then set to null (makes the same effect as remove it) without the lang garbage, generate the link and restore the value to the route data dictionary so the rest of the languages generate their link with this parameter which is necessary.

Sometime I comment with my developer friends and I say, I hate the web development but at the same time I love it! Because most of the time I have to be finding the exact trick for achieve the expected result and that’s the magic of software development!

Tuesday, 21 February 2012

jQuery.NeatUpload – Examples refactored

jQuery.NeatUpload – Release 0.4

I’ve been using the jquery plugin for neatupload and the bugs keep coming up, well, that’s the developer’s life. Catching bugs is an ability that every developer must have and more than that, do not shame on, but be proud of.
This time I’ve improved the error handling when the server send as response some no comprehensive, for instance, there is a limit set in web.config for the maximum file size to upload and when the client attempts to send a file bigger than the limit, the server replies with some bizarre response.
As part of the mechanism implemented, it expects the HTML response for parse it and determine what to do, I mean, send information to the client indicating whether the request failed or not. Sometimes the HTML sent by the server was impossible to read because of some mysterious JavaScript error “Access denied”. I had no time for digging deeper in this matter, so I try-catch it and just a little extra setup in order to be consequent and ready. The release 0.4 can be downloaded here.

jQuery.NeatUpload – Examples refactored

In order to prepare for launch a new release of NeatUpload including these JavaScript features I’ve been doing some refactoring in the samples I published a few months ago. The first thing I’ll do is to apologize with the WebForms people, because I’ve let them in the road with the examples, just the part 1. Now the updated versions have both implementations WebForms and MVC3. Of course these new versions also have applied the bugfix mentioned above.
There’s something new in the web.config files, this time they are prepared for either IIS6 or IIS7+ and highly commented (well, this is questionable and relative to anyone’s need) every setting needed for set up NeatUpload even clarifying the confusing and inconsistent size units that Microsoft has implemented in both versions of IIS, they are in bytes and Kilobytes respectively.
Before describe what’s in these examples, I want to alert you about something that I’ve been dealing with many times and that has been cause of mysterious error in production scenarios. There is a setting in web.config that indicates the maximum time that IIS can wait before it shuts down the thread and return time out error. This is under and it’s expressed in seconds, this is especially useful when the files to be uploaded are really big.

What’s in the examples?

  • Default values: Shows how to use the minimum setup code and use the default values.
  • Changed Add and Upload texts: Shows how to change the texts for the elements that add and/or upload items rather than the default internal texts.
  • Changed Add and Upload elements: Shows how to change the default link for add and/or upload element by custom elements like buttons.
  • Custom cancel elements. Part 1: Shows how to change the cancel element by creating a simple new element inline and binding it to the internal click event.
  • Custom cancel elements. Part 2: Shows how to change the cancel element by cloning a complex element and binding it to the internal click event.
  • Start Upload Automatically: Show how to start automatically the upload without using a queue and adding one by one. This example uses just add element.
  • Show Progress Bar: Shows how to use a more cute visual feedback by styling up a progress bar that indicates the progress and changes the color if an error occurs.
  • Validating Data: Shows how to intercept the action of send the file to the server by performing validations to the associated data.
  • Sending extra Data: Shows how to send associated data along with the file by serializing it as JSON and how to receive it properly on the server.
à la prochaine mes amis!

Monday, 13 February 2012

Unobtrusive validation with dynamically created fields

Some time ago I started to take advantage of unobtrusive validation, one of the most important approaches for gaining cleanness in the resulting HTML. The way it works is, in a nutshell, as an adapter to the traditional jquery validation plugin, it searches through the HTML for every input element with data-val HTML5 attribute and value true, then it reads all possible validation rule, creates the rules element and finally calls to the validation plugin. This unobtrusive validation comes with the default template in MVC3 web projects using Visual Studio 2010.
Everything worked as expected when the entire HTML was generated from the server, I mean, as usually, using the HTML helpers such as @Html.TextBoxFor(...). Even if I’ve been working with AJAX, it worked as expected, just using a little tweak as I mentioned in this post.
Suddenly, a new scenario has arisen to the table. This time it’s necessary to validate elements dynamically created, client side only. When the page loads there are a lot of input with its data-* attributes properly rendered, but there is another set of input elements which will be created at runtime and therefore they must be validated as well. Until now there is no problem, isn’t it? Surprise if I tell it doesn’t work at all; it simply ignores these new elements created at runtime. But, what’s the difference? Previously I mentioned that it worked with AJAX, new content is added to the DOM. In fact, it works with AJAX. After digging a lot inside the source code and debugging, yes debugging and tracing! God bless these modern tools for doing this kind of work in JavaScript!
Long story short, the root of the problem is inside jquery validation plugin, and I think is not really a bug, but something that the plugin’s developer team did not think about. When the unobtrusive passes the data to the validator, this first checks in the internal cache using jQuery.data(...) and if anyone previously has passed the validation rules for this particular form, then it does nothing. What’s the problem? That is a good idea; do not perform the same task more than once. When using AJAX, in every test I’ve done there is an entirely new form that arrives from the server, this new form was not in the cache and that’s why it worked to me using AJAX. I show the exact code fragment where I found it.
 // check if a validator for this form was already created
 var validator = $.data(this[0], 'validator');
 if ( validator ) {
  return validator;
 }

 validator = new $.validator( options, this[0] );
 $.data(this[0], 'validator', validator);
 
But what if I add new elements dynamically to that form previously initialized with the validator plugin? That is not very bizarre, or maybe a little, anyway I think it should be considered. I found a quick and dirty workaround for solving my particular case. It consists in reset the internal validator’s cache by hand and then command unobtrusive to re-parse the form and Voilà!
 $.removeData(form[0], 'validator');
 $.validator.unobtrusive.parse(form);
 

I have prepared an example in order to demonstrate what I am saying is true. In the example I present a very simple login form using jquery validator and unobtrusive along with three buttons: (create new field, reset Validator Cache and Add new Form). How it works? The initial form is completely normal, just click the Login button and everything works as normal, the validators pop out with their messages. The code is here

Click the ‘create new field’ button and a new field appears and press Login again, this new field is not part of validation despite the fact it has properly configured the data-* attributes.

Now click the ‘reset Validator Cache’ button and click again Login button, Magic?! The new field is now part of the validation and we have a third validation message that wasn’t before.

Finally press the button ‘Add a new Form’ and an entire new form is created below, this form work as it should without remove anything from the cache.

I hope this experience which took me hours may help more people who wants to develop rich-client and a lot of JavaScript as today’s web application demands.

Monday, 6 February 2012

I became a member of NeatUpload Open Source Project

I’ll start with a question: who hasn’t ever borrowed at least a small piece of code from the community? I think the number is very close to zero, and why? Is it something about do not reinvent the wheel? And why the community is as huge as nowadays is? The truth is the times have changed, and the old times when a small group of hackers had access to the technology and they were too jealous with their achievements and there were too much selfishness in the air.

Now, as the internet and the communication media have globalized, the exchanges between developers around the world is something common, and probably that’s why you are reading this post. When you start learning a new technology/language/framework (the list might go on), you face many typical problems that a big number of developers around the world faced to, and without the help of some of these experienced developers the work becomes tortuous.

I recently read this post from Scott Hanselman about involving in open source projects and he explains how easy is, even with an example. But, why am I talking about all this? about a year ago, I had to develop a jquery plugin (which occupies several post in this blog) and I decided to publish it for the community. After all, the problem I solved might be the same for other people around the world and, why not to return back the favor to the community? When I needed, I had a lot of code available for just download it and use it. I know, it’s true, not always the documentation is as good as I’d like it was, but that’s something with I have to deal with.

A few weeks ago, I asked myself, what about to show my work to the NeatUpload team? I appreciate their opinion about and that’s what I did. Surprise for me! I received an email from Dean Brettle and Joe Audette celebrating my job and inviting me to join in the project.

My answer was very fast and now I am a member of NeatUpload project. My first contribution was to make the translations for Spanish language in the resources. According to joe and Dean, in the next release, will be included the plugin, documentation and examples mentioned in the early post in this blog. And of course, the further NeatUpload releases will include the last version of jquery.neatupload.

Conclusion, contribute to open source has no cost, is not hard to do, and the benefits you give to the community is returned back when you search for doubt in stackoverflow or just Google. So, contribute!

Wednesday, 1 February 2012

jQuery.NeatUpload - Release 0.3

A new bug has been detected in the jquery.neatupload plugin, the issue occurred if more than one tab opened in the same browser window tried to upload files in time overlapping. The effect was progress bars becoming crazy with the progress indications.
The cause was a naming collision with the postbackId parameter which identifies the current file being uploaded, the number always started by 1, so if two requests from the same browser send the same postbackId, the NeatUpload module doesn’t know who is who and the polls for display the progress show by moments the results of one and by moments the results of the other.
The solution, change the initialization value for the internal variable postbackId, this time helped by a random number and rounded for to eliminate the decimal comma separator, just esthetic. This change is applied to version 0.3 which can be downloaded here.