Creating a custom ASP.NET MVC @Html.ValidationSummary template styled with Bootstrap 3 panel

Today I had to customize the standard @Html.ValidationSummary that comes with ASP.NET MVC. Searched for it as always using Google and found this question at StackOverflow with two promising answers. One of them presented a nice approach that is the creation of a custom partial view called ValidationSummary.cshtml that lives in the standard Views\Shared folder. Initially I was afraid of implementing this because as one of the commenters said it didn’t play ball with jQuery Validate. I decided to experiment and see what would happen in my case. Guess what? It didn’t play ball with jQuery Validate. So it’s not OK. I was not satisfied and did further investigation regarding Microsoft's jquery.validate.unobtrusive.js file and it led me to the correct implementation to get the custom Validation Summary working with jQuery Validate. Let’s look at the code that Microsoft uses to fill the Validation Summary with errors:

function onErrors(event, validator) {  // 'this' is the form element
    var container = $(this).find("[data-valmsg-summary=true]"),
        list = container.find("ul");

    if (list && list.length && validator.errorList.length) {
        list.empty();
        container.addClass("validation-summary-errors").removeClass("validation-summary-valid");

        $.each(validator.errorList, function () {
            $("<li />").html(this.message).appendTo(list);
        });
    }
}

As we can see the code looks for a container that has a data attribute [data-valmsg-summary=true]. So when creating our custom Validation Summary template we must add that data attribute to our <div> container like this:

@model ModelStateDictionary

<div class='@(Html.ViewData.ModelState.IsValid ? "validation-summary-valid" : "validation-summary-errors") panel panel-danger'
     data-valmsg-summary="true">
    <div class="panel-heading">
        @Localization.CorrectErrors
    </div>
    <div class="panel-body">
        <ul>
            @foreach (var modelError in Model.SelectMany(keyValuePair => keyValuePair.Value.Errors))
            {
                <li>@modelError.ErrorMessage</li>
            }
        </ul>
    </div>
</div>

This Partial View approach gives you total control over what HTML structure/tags, CSS classes, etc you want applied to the validation summary.

Two things to take not in the above code:

1 - When the form is accessed for the 1st time, ModelState.IsValid is true and the CSS class validation-summary-valid is applied to the containing <div>.This is so so that it conforms to the standard ValidationSummary that comes with ASP.NET MVC and because this CSS class is used by jQuery unobtrusive validation code.
The standard Site.css file that comes with an empty ASP.NET MVC project also uses this very CSS class to hide the validation summary initially. It has this CSS rule:

.validation-summary-valid {
    display: none;
}

When post backing the form data, the view Model may pass the unobtrusive client side validation but may not pass the server side validation and in this case ModelState.IsValid will be false. Again to be conformant with jquery validate unobtrusive code we must set the class validation-summary-errors to the validation summary container. This is imperative; if we do not do this, then we won’t see the validation errors that come from the server side since the validation summary will be hidden.

2 - panel panel-danger are Bootstrap’s CSS classes that give some charming to our custom ValidationSummary. You can check Bootstrap 3 panel component here.

Following the above simple HTML structure it’s possible to make the custom validation summary compatible with jQuery Validate.

Here’s the end result:

ASP.NET MVC Custom Validation Summary with Bootrap 3 Look & Feel using Panel component

To get the above look & feel I changed some CSS classes in ~/Content/Site.css file to override Bootstrap’s CSS. Here are them:

.panel-body {
    padding: 10px;
}

ul, ol
{
    margin-bottom: 0;
    padding-left: 17px;
}

.panel
{
    margin-bottom: 0;
}

.form-group {
    margin-bottom: 0;
}

As a final take on this matter, it’d be great if the standard ASP.NET MVC @Html.ValidationSummary had a method overload accepting a template name. Let’s hope that in the future this gets added.

I assembled a sample ASP.NET MVC project and uploaded it to GitHub. Feel free to play with it and adapt it to your use case. Here’s it is: https://github.com/leniel/AspNetMvcCustomHtmlValidationSummary

Happy coding! Party smile

Prevent JavaScript code blocking the UI thread with setTimeout + a handy stopWatch to profile JS code

In early January of this year I was implementing some JavaScript code that does a lot of processing on the client side with the help of jQuery. It’s part of a project where my customer asked for the possibility of answering a questionnaire in two ways: using a Wizard (one question at a time) and Listing (all questions at once) in a single form. The client side code for the Listing is the culprit and the subject of this post. It’s also related to this question I posted at StackOverflow on February 19:

Why ASP.NET MVC default Model Binder is slow? It's taking a long time to do its work

That question on SO is the inverse part, that is, the server receiving the client side data, but that’s just the other “part” of the problem which I also managed to solve. I really hope that this post helps you understand the problem with the client side part at least…

One of the things that I didn’t like in that JavaScript code was that while the questions were being processed to be rendered subsequently by the JavaScript/jQuery client side code, the browser UI thread hung/froze a lot of times – I think it’s worth mentioning here that I didn’t get Firefox’s warning prompt for "Unresponsive script". Anyway, the simple fact that the page freezes gives the user and me the developer a feeling that something is wrong with the code. As users we expect things to be fluid – we expect a good UI experience and seeing your browser freezing while loading a web page is not the best impression one may have of your software product.

I’m more experienced with server side code and haven’t ever seen any of my JavaScript code run slow on the client. I then started searching on Google why this was happening and just stumbled on this really helpful and insightful article at O’Reilly Answers:

Yielding with JavaScript Timers

Read it carefully to get a grasp of the concepts involved. I read it maybe thrice at least to understand the code and adapt it to the problem at hand. It fitted so well in my situation that the result I got after adapting the code was mind blowing.

The part that really got my attention was the Timed Code section - way bellow that O’Reilly article. It tells us that batch processing items (questions in my case) instead processing everything once or one at a time is more efficient to avoid blocking the UI.

JavaScript UI Queue and UI Thread lanes depicted: timed code is intercalated taking turnsFigure 1 - JavaScript UI Queue and UI Thread lanes depicted: timed code is intercalated taking turns

The JavaScript code I implemented processes a bunch of questions I receive from the server to prepare them to be shown to the user. Using a AJAX GET request’s success callback I dumped all the questions (usually 100 up to more than 200 sometimes and each one formatted with the help of a ASP.NET partial view) inside a div element $("#questions") like this:

// Loading Questions for the Chapter selected...
function loadQuestions(chapterId)
{
    $("#questions").fadeOut('slow').empty();

    $.ajax({
        type: "GET",
        url: "@Url.Action(MVC.UserAssessment.ActionNames.List, MVC.UserAssessment.Name)",
        data: { assessmentId: @Model.AssessmentId, chapterId : chapterId },
        cache: false,
        success: function(questions)
        {           
            $("#questions").html(questions);
            
            setUpQuestions();
        },
        error: function()
        {
            alert("@Html.Raw(Localization.UnknownErrorAjax)");
        }
    });
}

With this I had all the questions’ HTML beautifully inserted on the page but I needed to process this HTML before showing it to the user. That’s where the setUpQuestions(); method played its role. It does the heavy lifting and was where the whole thingy just got screwed up – the browser hung from time to time while inside that method… How did I discover that the problem was inside that method? I used Firebug’s Console and the JavaScript’s Date object as shown in that O’Reilly article. In setUpQuestions I use jQuery’s find, setup form fields validation with jQuery validation plugin, disable/enable fields, apply CSS styles to the questions, etc and all of this was tackled all at once by the poor browser JavaScript engine.

To profile setUpQuestions I created a stopWatch JavaScript method that receives setUpQuestions method as the func parameter:

function stopWatch(func)
{
    var start = +new Date(), stop;

    func();

    stop = +new Date();
if (stop - start < 50)
{
//alert("Just about right.");
console.log("Just about right.");
} else
{
//alert("Taking too long.");
console.log(“Taking too long.");
} }

According to that O’Reilly article, the author recommends never letting any Javascript code execute for longer than 50 milliseconds continuously, just to make sure the code never gets close to affecting the user experience – blocking the UI thread.

When I ran the code selecting different chapters with varying number of questions I kept getting “Taking too long” and then I found where the problem was. I knew it was time to adapt the code presented in the Timed Code section of that O’Reilly article. So here it is and commented where appropriate to make understanding it a little bit easier:

/// More about it here: http://answers.oreilly.com/topic/1506-yielding-with-javascript-timers/
function
timedProcessArray(items, process, callback) { var todo = $.makeArray(items); // The first call to setTimeout() creates a timer to process the first item in the array. setTimeout(function () { var start = +new Date(); do { // Calling todo.shift() returns the first item and also removes it from the array. process(todo.shift()); } // After processing the item, a check is made to determine whether there are more items to process and if the time hasn't exceeded the threshold of 50 milliseconds while (todo.length > 0 && (+new Date() - start < 50)); if (todo.length > 0) { // Because the next timer needs to run the same code as the original, arguments.callee is passed in as the first argument. setTimeout(arguments.callee, 25); }
else { //If there are no further items to process, then a callback() function is called. if (callback) { callback(items); } } }, 25); }

This code made the whole thing fluid and now the user has a much better experience while interacting with the page despite it having a lot of form controls. What it basically does is: process a batch of items/questions and then allows the UI thread to take some processing time and then it repeats until there’s no more questions left in the todo array. The process method is actually the setUpQuestions method that gets passed as a parameter called process.

In my specific case, each question has 4 HTML input elements (input/text, select, etc). If the user selects a Manual’s Chapter to answer and this Chapter contains 230 questions for example, the <form> element will contain about 920 controls = 4 x 230.That's a lot of controls to be processed by the JavaScript code inside the setUpQuestions method. Now no matter how many controls are present in the HTML code. timedProcessArray will handle this easily allowing the UI thread to breath from time to time.

This is the modified version of the loadQuestions method that makes use of this life saving timedProcessArray method where setTimeout shines:

// Loading Questions for the Chapter selected...
function loadQuestions(chapterId)
{
    $("#questions").empty();

    $.ajax({
        type: "GET",
        url: "@Url.Action(MVC.SAvE.UserAssessment.ActionNames.Answer, MVC.SAvE.UserAssessment.Name)",
        data: { assessmentId: '@Model.AssessmentId', chapterId : chapterId, format: '@Assessment.Format.List' },
        cache: false,
        success: function(data)
        {
            var questions = $(data);

            questions.hide().appendTo("#questions");

            //stopWatch(function(){ return timedProcessArray(questions, setupQuestion, stats)});

            timedProcessArray(questions, setupQuestion);

            //stats(questions);
}, error: function() { alert("@Html.Raw(Localization.UnknownErrorAjax)"); } }); }

I didn’t pass a callback function to timedProcessArray but that’s up to you.

Hope it helps you take the most out of your highly intensive processing JavaScript code.

As a last note, with the arrival of HTML5 we now have Web Workers but browser support is still limited. Things are getting better for us developers. Smile In the near future this will be standard for sure but till then we must find a way to solve the problem with the proven tools/code. setTimeout is one of them.

Manage folders & files in your ASP.NET MVC app with elFinder.Net

Recently I had to evaluate what were my options when it comes to managing folders and files in an ASP.NET MVC project – a files manager somewhat like what a Content Management System does but I needed something way simpler and intuitive and principally of easy integration.

The Story
As part of a project requirement, a super user wants to able to offer other users some files like PDFs, Images, Videos, etc. This super user should be capable of creating a folder structure as he sees fit and then upload files to a central point (the server). All this looks like a difficult task to accomplish through a client server architecture since we’re dealing with clients and their files that need to go to the server. At first I thought about using a SharePoint module/web part but then it seemed overkill for what I wanted.

As always I just put some simple words in a Google search and to my surprise I found an outstanding open source project called elFinder by Studio 42. Here’s their ASCII art for your amusement:

      _ ______ _           _           
     | |  ____(_)         | |          
  ___| | |__   _ _ __   __| | ___ _ __ 
 / _ \ |  __| | | '_ \ / _` |/ _ \ '__|
|  __/ | |    | | | | | (_| |  __/ |   
 \___|_|_|    |_|_| |_|\__,_|\___|_|   

elFinder is an open-source file manager for web, written in JavaScript using jQuery UI. Creation is inspired by simplicity and convenience of Finder program used in Mac OS X operating system.

After going through the readme file for a moment, I thought: Oh my god, this is just what I need. The only drawback in my case was that the connector (server part) of elFinder is written in PHP and I’m developing an ASP.NET MVC app. Then let me go to Google once again and type elFinder ASP NET. To my surprise there are some ports to the .NET arena but they seem to lack integration simplicity, that is, the dependencies these ports need just interfere with my current code as was the case of the elFinder ASP.NET Connector that uses Autofac as a dependency. I use Castle Windsor for the IoC part and then this was a no go. A more careful read at the original elFinder wiki let me know about different ports of this amazing project: 3rd party connectors, plugins, modules. This page pointed me to ElFinder.NET connector for elFinder 2.x hosted at CodePlex.

I downloaded ElFinder.NET’s source code that comes with a sample ASP.NET MVC app and played with it. When I saw the amount of features available [ Client options + Connector options ] I almost cried in excitement Crying face. ElFinder.NET is a very well written and organized port put together by Evgeny Noskov. Congrats to him and to Studio 42 from Russia for sharing the code with the community. It works great and so I started integrating it with my ASP.NET MVC 4 app.

Along the way I hit some missing features that I saw are part of the original elFinder by Studio 42. They are startPath and uploadMaxSize. I contacted Evgeny through the CodePlex contact form and asked him about the option to set a start path in the root directory. Thinking he wouldn’t even answer me, I decided to implement it myself looking at the original elFinder codebase. Today I got an e-mail from Evgeny telling me that he just added the start path option to elFinder.Net. What a joy! Then I wanted to set a max upload size and I just saw that this option was also not present in elFinder.Net. Asked about it in this discussion and Evgeny promptly added it to the library. I even had no time to try to implement this one… he went even further and added a must have feature that I didn’t notice was missing: file download.

So after all this amazing story of “is giving that you receive” I decided to spread the word and write a blog post about elFinder.net…

It’s enough of background info. Let me show you one simple use case and how you can take advantage of such outstanding open source project.

The Use Case
Let’s say you want to let one super user with read/write permissions create a folder structure inside a given root directory in the server and upload files there. Other users accessing the app will then be presented with a page that has links that point to the 1st level folders of that root directory. These users will be able to only read those folders/files uploaded by the super user. Note: this app has some kind of membership implemented with roles and permissions granted to users. I’ll omit this part in this sample code for simplicity sake.

The super user has access to a screen (Files menu option) like the following one that contains elFinder files manager:

Figure 1 - elFinder.Net file manager UI styled with jQuery UI supporting any folder depth, file/folder upload/download, delete, rename, copy/cut/paste, preview, properties, drag and drop, etc.Figure 1 - elFinder.Net file manager UI styled with jQuery UI supporting any folder depth, file/folder upload/download, delete, rename, copy/cut/paste, preview, properties, drag and drop, etc.

Other users when logging in for example will have access to a page (Home menu option) listing the 1st level folders like this:

Figure 2 - 1st level folders links allow users to click on them and have the selected folder opened in elFinder’s file manager automagicallyFigure 2 - 1st level folders links allow users to click on them and have the selected folder opened in elFinder’s file manager automagically

When clicking the folder name link, the user will be sent to elFinder’s file manager and the folder will be selected automatically showing its content to the user. The user without super powers then is allowed only to read the folder content and if they want they can even download the files to their machines. The possibilities are endless…

The Code
The full code is available at this GitHub repo: https://github.com/leniel/elFinder.Net

You’ll find comments throughout the code. Make sure you read them carefully.

Let’s start defining two action methods in the HomeController.

public partial class HomeController : Controller
{
    [GET("")]
    public virtual ActionResult Index()
    {
        DirectoryInfo di = new DirectoryInfo(Server.MapPath("~/Files/MyFolder"));
        // Enumerating all 1st level directories of a given root folder (MyFolder in this case) and retrieving the folders names.
        var folders = di.GetDirectories().ToList().Select(d => d.Name);

        return View(folders);
    }

    [GET("FileManager/{subFolder?}")]
    public virtual ActionResult Files(string subFolder)
    {
        // FileViewModel contains the root MyFolder and the selected subfolder if any
        FileViewModel model = new FileViewModel() { Folder = "MyFolder", SubFolder = subFolder };

        return View(model);
    }
}

The Index action method corresponding View has this code:

@model IEnumerable<string>

@{
    ViewBag.Title = "Index";
}

Available 1st level Folders - clicking will navigate you to the File Manager setting the selected folder as elFinder's start path.

<ul>
    @foreach (string folder in Model)
    {
        <li><a href="@Url.Action(MVC.Home.ActionNames.Files, MVC.Home.Name, new { subFolder = folder })">@folder</a> </li>
    }
</ul>

The Files action method corresponding View has this code:

@model FileViewModel

@{
    ViewBag.Title = "Files";
}

@Html.Partial(MVC.Shared.Views.FilesForm, Model)

The FilesForm partial view has elFinder’s client side interesting pieces of code:

@model FileViewModel

@{
    ViewBag.Title = "Files";
}

@* Bundles with elFinder's CSS and JavaScript files configured in App_Start\BundleConfig.cs*@
@Styles.Render("~/Content/elfinder")
@Scripts.Render("~/Scripts/elfinder")

<script type="text/javascript">
    $(function ()
    {
        var myCommands = elFinder.prototype._options.commands;

        var disabled = ['extract', 'archive', 'resize', 'help', 'select']; // Not yet implemented commands in ElFinder.Net

        $.each(disabled, function (i, cmd)
        {
            (idx = $.inArray(cmd, myCommands)) !== -1 && myCommands.splice(idx, 1);
        });

        var selectedFile = null;

        var options = {
            url: '/connector', // connector route defined in the project folder App_Start\RouteConfig.cs
            customData : { folder : '@Model.Folder', subFolder: '@Model.SubFolder' }, // customData passed in every request to the connector as query strings. These values are used in FileController's Index method.
            rememberLastDir: false, // Prevent elFinder saving in the Browser LocalStorage the last visited directory
            commands: myCommands,
            //lang: 'pt_BR', // elFinder supports UI and messages localization. Check the folder Content\elfinder\js\i18n for all available languages. Be sure to include the corresponding .js file(s) in the JavaScript bundle.
            uiOptions: { // UI buttons available to the user
                toolbar: [
                    ['back', 'forward'],
                    ['reload'],
                    ['home', 'up'],
                    ['mkdir', 'mkfile', 'upload'],
                    ['open', 'download'],
                    ['info'],
                    ['quicklook'],
                    ['copy', 'cut', 'paste'],
                    ['rm'],
                    ['duplicate', 'rename', 'edit'],
                    ['view', 'sort']
                ]
            },

            handlers: {
                select: function (event, elfinderInstance) {

                    if (event.data.selected.length == 1) {
                        var item = $('#' + event.data.selected[0]);
                        if (!item.hasClass('directory')) {
                            selectedFile = event.data.selected[0];
                            $('#elfinder-selectFile').show();
                            return;
                        }
                    }
                    $('#elfinder-selectFile').hide();
                    selectedFile = null;
                }
            }
        };
        $('#elfinder').elfinder(options).elfinder('instance');

        $('.elfinder-toolbar:first').append('<div class="ui-widget-content ui-corner-all elfinder-buttonset" id="elfinder-selectFile" style="display:none; float:right;">'+
        '<div class="ui-state-default elfinder-button" title="Select" style="width: 100px;"></div>');
        $('#elfinder-selectFile').click(function () {
            if (selectedFile != null)
                $.post('file/selectFile', { target: selectedFile }, function (response) {
                    alert(response);
                });
               
        });
    });
</script>

<div id="elfinder"></div>

The last part is the FileController that gets called in every connector request:

public partial class FileController : Controller
{
    public virtual ActionResult Index(string folder, string subFolder)
    {
        FileSystemDriver driver = new FileSystemDriver();

        var root = new Root(
                new DirectoryInfo(Server.MapPath("~/Files/" + folder)),
                "http://" + Request.Url.Authority + "/Files/" + folder)
        {
// Sample using ASP.NET built in Membership functionality... // Only the super user can READ (download files) & WRITE (create folders/files/upload files). // Other users can only READ (download files) // IsReadOnly = !User.IsInRole(AccountController.SuperUser)
            IsReadOnly = false,
Alias = "Files", // Beautiful name given to the root/home folder MaxUploadSizeInKb = 500 // Limit imposed to user uploaded file <= 500 KB }; // Was a subfolder selected in Home Index page? if (!string.IsNullOrEmpty(subFolder)) { root.StartPath = new DirectoryInfo(Server.MapPath("~/Files/" + folder + "/" + subFolder)); } driver.AddRoot(root); var connector = new Connector(driver); return connector.Process(this.HttpContext.Request); } public virtual ActionResult SelectFile(string target) { FileSystemDriver driver = new FileSystemDriver(); driver.AddRoot( new Root( new DirectoryInfo(Server.MapPath("~/Files")), "http://" + Request.Url.Authority + "/Files") { IsReadOnly = false }); var connector = new Connector(driver); return Json(connector.GetFileByHash(target).FullName); } }

Hope it helps.

IIS 8 Web Site in Windows 8 externally accessible to the World

Today I needed to allow a per to access an application that’s under development. Instead of buying a cheap ASP.NET hosting account I decided to host the app on my local IIS 8 server. The process to get this configured and working was somewhat exciting since I learned new things along the way.

I’ll show in this post the steps I followed to have this working as expected…

My setup:

  • Windows 8 running inside a virtual machine in Parallels 8 with IP address 192.168.1.107;
  • ASP.NET MVC 4 app deployed in the Default Web Site in IIS 8 that is configured to accept incoming connections in the standard port 80;
  • Linksys WAG200G router/modem connected to the outside/external World.

Steps to follow:
1 - Go to the router’s management interface. In my case it’s located in the address 192.168.1.1.

2 - You’ll need to set a port forwarding configuration. In my case it’s located in Applications & Gaming / Single Port Forwarding. It’ll vary slightly depending on your router vendor and model.

Application: HTTP
External Port: 80
Internal Port: 80
Protocol: TCP
IP Address: 192.168.1.107 (your Windows/IIS machine IP address)
Enabled: True (checked)

Linksys WAG200G Single Port Forwarding configurationFigure 1 - Linksys WAG200G Single Port Forwarding configuration

Make sure to hit the Save Settings button way bellow the page.

3 - Go to Windows 8 Control Panel / System and Security / Windows Firewall / Turn Windows Firewall on or off.
Turn off Windows Firewall for Private Networks.

Turning off Windows 8 Firewall for Private NetworksFigure 2 - Turning off Windows 8 Firewall for Private Networks

4 - Take note of your internet IP address. You can see it in the router’s status page. In my case it’s located in Status / Gateway. Again where you’ll find this info will vary depending on your router vendor.

Taking note of the internet/Gateway IP that uniquely identifies the machine on the internetFigure 3 - Taking note of the internet/Gateway IP that uniquely identifies the machine on the internet

You can also see your current IP Address using Gmail’s Last Account Activity report if you happen to have a Gmail account of course.

5 - Open a browser window and type your internet Gateway IP address taken in step 4. You should be presented with the beautiful IIS 8 default web page if you have no app deployed in the Default Web Site; otherwise you should see your app’s default page/login view.

IIS 8 Default Web Site pageFigure 4 - IIS 8 Default Web Site page

That’s it! Now the web site/app is available externally to any user in any part of the WORLD directly from my development machine.

Anytime I want I can hit Publish from within Visual Studio 2012 and deploy directly to the local IIS 8 server. The user that knows my IP address can then see my ongoing work remotely and free of charge for now.

Note 1
I do not have a static IP address, that is, my ISP here in Brazil (Oi Velox) gives me a dynamic IP address. This means that if there’s a power outage or if the router resets for whatever reason I’ll get a different address – it’s really important to know about this. To overcome such limitation there are some services that can help. One of them is No-IP. It basically allows you to access your computer by a hostname instead of an IP address by using dynamic DNS. They have a free utility app that runs in the background and that automatically syncs your current dynamic IP address with your custom hostname defined in No-IP service.

Excerpts from No-IP site:

What is a hostname?
A hostname is a name given to a computer to make connecting to it easier. Instead of typing out a long IP address you can enter the hostname followed by the domain name, such as myhostname.no-ip.com.

What is dynamic DNS?
Dynamic DNS makes it possible to connect to computers with dynamic IP addresses without needing to know the actual IP address.

They have a free account available with some limitations but it’s worth trying anyway.

Note 2
If for some reason your ISP blocks the default IIS port 80 (something common – hooray! not in my case today) you can try forwarding from a different external port like 8888 in step 2 above. In this case, you’d have to specify this port address when trying to access your IIS server. For example:

189.xxx.xxx.xxx:8888

where 189.xxx.xxx.xxx is your internet IP address.

Data binding view values to an array parameter in ASP.NET MVC

If you want the source codez, jump here.

This looks like something so easy to be done and at the same time I guess a lot of people fail the first time they try to get this working. This question at StackOverflow proves that. So to help the fellow developers out there I put together a concise ASP.NET MVC 4 sample application to show how to data bind/postback view values to an array parameter in an controller action method. I show two ways of doing this: using a traditional/full postback and an AJAX/partial postback. This way you can choose the best option for you.

Use case
User wants to be able to select 3 values ( at least 1 being mandatory Surprised smile ) in the view using dropdowns and data bind the selected value(s) to an array that will be treated inside the controller.

User Interface
While implementing the code I thought why not make the app a little bit fancier and give it some meaning and so I complemented the sample with color picker dropdowns. This is the UI:

ASP.NET MVC Array Data Binding sample app UI

Code
ASP.NET MVC needs the generated form elements to follow a certain format so that the model binder can do its job, that is, understand what you’re trying to do; otherwise when you debug the code you’ll just get a null value in the array parameter or ViewModel array property inside you controller action. This means that the model binder didn’t understand your posted data and I’m sure you thought it would. I’ve already been in this situation…

So the question is: How to make the model binder understand the view data? Let’s get to the code…

The sample’s code is well documented, so I’ll just copy/paste the important parts here. Just read the comments to understand what’s going on…

In the view side, you must create the input elements following this format:

@* Pay special attention to how we must name the form fields.
selectedColors is the name of a parameter defined in the controller action that will receive the form values. It’s necessary to suffix the name with [n], where n must be zero-based and unbroken. *@ @for (int i = 0; i < 3; i++) { @Html.DropDownList("selectedColors["+i+"]", Model.Colors, "-- Pick a Color --") }

In the controller side, you must have an action method with an array parameter named exactly like the name given to the dropdowns on the view side ( selectedColors ) like this:

/// <summary>
/// This action method works with a simple int[] array that's not part of a ViewModel.
/// </summary>
/// <param name="selectedColors">Simple int[] array</param>
/// <returns>ArrayPostResult view</returns>
[HttpPost]
public ActionResult TestArrayPost(int[] selectedColors)
{
    if (Request.IsAjaxRequest())
    {
        ViewBag.PostBack = "AJAX";

        return PartialView("ArrayPostResult", selectedColors);
    }

    ViewBag.PostBack = "Full";

    return View("ArrayPostResult", selectedColors);
}

The above code should take care of handling the full postback scenario.

To do an async/partial postback using AJAX you can use this jQuery code as an example:

$("#submit-ajax").click(function () {

    var selectedColors = [];

    // For each select HTML element/dropdown,
    // push its selected value into selectedColors
    $('select option:selected').each(function () {
        selectedColors.push($(this).val());
    });

    $.ajax({
        type: "POST",
        url: "/Home/TestArrayPost",
        dataType: "html",
        traditional: true,
        data: { selectedColors: selectedColors },
        success: function (response) {

            $("#result").html(response).fadeIn();

            // Hiding the GO back button...
            $("#result").find("#go-back").hide();

        },
        error: function (xhr, textStatus, exceptionThrown) {
            $('#result').html(exceptionThrown);
        }
    });
});

Note
If you want to postback the values to an array property that’s inside your ViewModel, for example:

public int[] SelectedColors { get; set; }

You can do this in the view side:

@for (int i = 0; i < 3; i++)
{
    @Html.DropDownListFor(m => m.SelectedColors[i], Model.Colors, "-- Pick a Color --")
} 

Then on the controller side, you’d have this:

[HttpPost]
public ActionResult TestArrayPost(ColorsModel model)
{
    if (Request.IsAjaxRequest())
    {
        ViewBag.PostBack = "AJAX";

        return PartialView("ArrayPostResult", model.SelectedColors);
    }

    ViewBag.PostBack = "Full";

    return View("ArrayPostResult", model.SelectedColors);
}

Source code
The code uses a bit of jQuery to control the UI logic and to postback the values through AJAX.

It’s hosted at GitHub and so you can navigate through it easily here.

You can download the Visual Studio 2012 solution here:

https://github.com/leniel/AspNetMvcArrayDataBinding/archive/master.zip

Hope it helps.

References
To implement this sample app I Googled some of the concepts employed like setting the background-color of select/dropdown options based on the option’s text. Pretty interesting stuff…

The following is a list of links that helped me:

Model Binding To A List
ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries
Drop-down Lists and ASP.NET MVC
@Html.DropDownListFor; How to set different background color for each item in DDL?
How do I convert an enum to a list in C#?

SignalR OnDisconnected Task and Dependency Injection with Castle Windsor - Hybrid lifestyle to the rescue

Today I faced a Castle Windsor dependency injection problem in an ASP.NET MVC app. The problem happened when using SignalR.

While implementing some UI real time user interaction I needed to have my persistence facility (Database context) injected inside my SignalR Hub class.

I Googled and found this awesome and to the point post by Mira Javora:

SignalR-Dependency Injection using Castle.Windsor

With the code he provided I was able to configure SignalR’s dependency resolver and everything was working as expected as Mira showed in his post.

In my case two objects are being injected in the Hub class:

public class AssessmentHub : Hub
{
    private MyContext _database { get; set; }

    private ILogger _logger { get; set; }

    public AssessmentHub(MyContext database, ILogger logger)
    {
        _database = database;
        _logger = logger;
    }

...
}

They were being properly injected in my own Hub class methods but things started to go wrong when SignalR’s OnDisconnected method was being called:

public override Task OnDisconnected()
{
    try
    {
        Guid connectionId = Guid.Parse(Context.ConnectionId);
// Database was null here! Sad smile
var client = Database.HubConnections.Single(hc => hc.ConnectionId == connectionId); UnlockChapterAndUpdateClients(client); Database.HubConnections.Remove(client); Database.SaveChanges(); } catch (Exception ex) { Logger.Error(ex.Message, ex); } return base.OnDisconnected(); }

This was the error I was getting:

HttpContext.Current is null. PerWebRequestLifestyle can only be used in ASP.Net.

The OnDisconnected method is an asynchronous method and as such it runs under a background thread ( not the one processing the request ). ASP.NET controls the threads and makes sure that only one thread is processing the request. This way HttpContext and as a consequence my _database injected object is null inside that method.

After some thinkering I remembered that I had my Persistence Facility registered PerWebRequest:

public class PersistenceFacility : AbstractFacility
{
    protected override void Init()
    {
        Kernel.Register(Component.For<MyContext>().          
            LifeStyle.PerWebRequest);
    }
}

Then, I Googled a little bit more and found this StackOverflow question:

Castle.Windsor lifestyle depending on context?

User Cuong Le shared a great post by Mauricio Scheffer called:

Hybrid lifestyles in Windsor

His post describes exactly what I needed (an Hybrid lifestyle ), that is, a way of keeping using the PerWebRequest life style when HttpContext is available but then resort to Transient lifestyle when it’s not.

An hybrid lifestyle is one that actually blends two underlying lifestyles: a main lifestyle and a secondary lifestyle. The hybrid lifestyle first tries to use the main lifestyle; if it's unavailable for some reason, it uses the secondary lifestyle. This is commonly used with PerWebRequest as the main lifestyle: if the HTTP context is available, it's used as the scope for the component instance; otherwise the secondary lifestyle is used.

I then grabbed Mauricio’s NuGet package Castle.Windsor.Lifestyles and changed my Persistence Facility code to:

public class PersistenceFacility : AbstractFacility
{
    protected override void Init()
    {
        Kernel.Register(Component.For<MyContext>().          
            LifeStyle.HybridPerWebRequestTransient());
    }
}

I’m back in business now. Call me