Archive for April, 2011

What’s Interesting About This Piece Of Code?

24 commentsWritten on April 18th, 2011 by
Categories: JavaScript
        $.get('/Home/Locations', function (data) {
            $.each(data, function () {
                var id = this.Id;
                var marker = new google.maps.Marker({
                    position: new google.maps.LatLng(this.Coordinates.Lat, this.Coordinates.Lng),
                    map: map
                });

                google.maps.event.addListener(marker, 'click', function (event) {
                    showDialogFor(id);
                });
            });
        });

NHibernate Examples

11 commentsWritten on April 10th, 2011 by
Categories: NHibernate

I published some NHibernate examples almost 4 years ago, and they still get downloaded pretty frequently. Unfortunately they still use NHibernate 1.2 and are somewhat limited as to what they demonstrate. My NHibernate course is rather example/exercise-heavy so i thought it would be a good time to replace those outdated examples with new ones and make them available to anyone who wants them. The examples are not complete yet, but will be updated frequently in the next couple of weeks. After that, i intend to keep them up to date to demonstrate new NHibernate features as they are introduced with new releases. Of course, you're more than welcome to contribute examples of your own.

The solution consists of a suite of automated tests that run on a SQLite database, which demonstrate some features of NHibernate. All tests currently run with the classic HBM mapping files and FluentNHibernate. Choosing which of the two is used can be done by selecting the correct build configuration (either HBMSQLITE or FLUENTSQLITE) before running the tests. Running the tests doesn't require any software to be installed or any configuration to be performed by you. Though you can obviously run the tests on different databases if you want to. The object model that is used is based on Northwind with a couple of changes. The object model can evolve into whatever it needs to be to showcase NHibernate features/usage. Some other models might also be introduced later on to show features that wouldn't fit well with the Northwind-based model.

These examples could be useful to people who are new to NHibernate, but could be interesting for experienced NHibernate users as well, if only as a playground to quickly experiment with some features that you're unsure of.

You can find the code here or you can always download the latest version here.

Automatically Including Current Language In Generated URLs With ASP.NET MVC

4 commentsWritten on April 6th, 2011 by
Categories: ASP.NET MVC

When you're pushing out localized content to your users, you don't want to mess up any possible output caching you've got set up (or would want to set up later on). One common approach to deal with this is to always include the relevant language code as a route parameter in your URLs. It works great with output caching because each localized version of the content will be accessible through its own URL, and as an extra benefit, your content is indexable by search engines in every language you support as well.

The only downside to that approach is that you absolutely have to make sure that the correct language code is always included in each URL you put on your pages. That's tedious work at best, error-prone at worst. Ideally, each URL that you generate on your pages automatically has the current language code included in it. And obviously, you want to be able to provide it explicitly as well (for language selection links for example). It took me a while to figure out how this can be done with ASP.NET MVC but i did manage to find a pretty nice solution.

I was browsing the MVC source code (see how useful this whole open source thing is?) to look for some kind of hook i could use to influence how URLs are generated when you use Url.Action or Html.ActionLink in your views. And it turns out that there is one, though it's not really an obvious one. Whenever you use Url.Action or Html.ActionLink, ASP.NET MVC calls the GetVirtualPath method for each defined Route object and the first returned VirtualPathData instance is the one that will provide the final URL that is rendered in your links. So we first need to come up with our own custom Route class:

    public class AutoLocalizingRoute : Route
    {
        public AutoLocalizingRoute(string url, object defaults, object constraints)
            : base(url, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), new MvcRouteHandler()) { }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            // only set the culture if it's not present in the values dictionary yet
            // this check ensures that we can link to a specific language when we need to (fe: when picking your language)
            if (!values.ContainsKey("language"))
            {
                values["language"] = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
            }

            return base.GetVirtualPath(requestContext, values);
        }
    }

Now we have to make sure that we define a route of this type before our normal routes are defined:

            var localizingRoute = new AutoLocalizingRoute("{language}/{controller}/{action}/{id}",
                new { id = UrlParameter.Optional }, new { language = "^[a-z]{2}$" });
            RouteTable.Routes.Add("LocalizingRoute", localizingRoute);

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

This ensures that our AutoLocalizingRoute instance will get a chance to provide a VirtualPathData instance whenever an action-URL is needed, before the standard Route instance is called to create one.

Now, all we need is something that sets the current thread's Culture and UICulture property based on the language code in the URL of each request. I did this with a HttpModule, of which only this part is relevant here:

        private void OnBeginRequest(object sender, EventArgs e)
        {
            var currentContext = new HttpContextWrapper(HttpContext.Current);
            var routeData = RouteTable.Routes.GetRouteData(currentContext);
            if (routeData == null || routeData.Values.Count == 0) return;

            if (routeData.Values["language"] == null)
            {
                RedirectToUrlWithAppropriateLanguage(currentContext, routeData);
            }

            var languageCode = (string)routeData.Values["language"];
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(languageCode);
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(languageCode);
        }

And that's it. Every time we generate an URL to a Controller Action, the current language code will be included automagically, so there's no chance of us forgetting it somewhere.

Customizing ASP.NET MVC’s Required Property Validation Messages

6 commentsWritten on April 3rd, 2011 by
Categories: ASP.NET MVC

I recently got convention-based localization of display labels working with ASP.NET MVC, and this week, i wanted to get something similar working for required field validation messages. ASP.NET MVC3 shows a default validation message when a required field is not filled in, unless you specify a resource provider and the name of the resource key when you put the Required attribute on a property. Just like with the display value of labels, i wanted a convention based approach for this. I wanted ASP.NET MVC to look for a resource key with the NameOfModelClass_NameOfProperty_required convention.

After some googling and browsing the MVC3 source code, i couldn't really find the hook i needed to make this happen, so i let it rest for a few days and got back to it later on. I had more luck the second time around and found the hook i needed. ASP.NET MVC uses the RequiredAttributeAdapter class to retrieve a ModelClientValidationRequiredRule which by default is initialized with the default error message. The trick was just to inherit from this class and return a ModelClientValidationRequiredRule with your own message, and then register that class with the DataAnnotationsModelValidatorProvider. This is the new subclass of the RequiredAttributeAdapter class:

    public class ConventionsBasedRequiredAttributeAdapter : RequiredAttributeAdapter
    {
        public ConventionsBasedRequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute) 
            : base(metadata, context, attribute) {}

        public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
        {
            string errorMessage;

            var className = Metadata.ContainerType.Name;
            var propertyName = Metadata.PropertyName;

            var specificKey = string.Format("{0}_{1}_required", className, propertyName);
            // TODO: make the ResourceManager configurable
            errorMessage = Resources.ResourceManager.GetObject(specificKey) as string;

            if (string.IsNullOrEmpty(errorMessage))
            {
                var genericMessageWithPlaceHolder = (string)Resources.ResourceManager.GetObject("Generic_required_field_message");

                if (!string.IsNullOrEmpty(genericMessageWithPlaceHolder))
                {
                    errorMessage = string.Format(genericMessageWithPlaceHolder, Metadata.DisplayName);
                }
            }

            if (string.IsNullOrEmpty(errorMessage))
            {
                errorMessage = ErrorMessage; // fallback to what ASP.NET MVC would normally display
            }

            return new[] { new ModelClientValidationRequiredRule(errorMessage) };
        }
    }

And this is how you tell ASP.NET MVC to use it:

            DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(typeof(RequiredAttribute), 
                (metadata, controllerContext, attribute) => new ConventionsBasedRequiredAttributeAdapter(metadata, 
                    controllerContext, (RequiredAttribute)attribute));

And that's it... with this approach you have full control over how the message is formatted.