Introducing DataTablesDotNet

The datatables plugin is one of the coolest jQuery plugins around, and I wanted to find a way to make it work easily with ASP.NET MVC sites. Initially I created some objects that included the various datatables property names and that worked well. However, when another project came along and I wanted to use datatables in that project too I realized the original way I created the objects just wasn’t going to cut it.

After a lot of searching I found this blog post. I liked what I saw. Even better was the additional code contributed by Paul Inglis in the comments. The only thing I did not like was the stringify used to turn the datatables JSON into key/value pairs. I also did not like the way the project was made available – a box.net download location with no way to contribute (hence the code in the comments). I decided I would build on these great contributions and update the code to work without the serialization.

So, here it is on GitHub. The code has been cleaned up, it uses Paul’s Expression code for building the filters/sorts, and it doesn’t stringify the datatables data which cuts the data sent pretty much in half. I also added a model binder so it all “just works”.

NOTE: Isn’t it funny how one can look for something and not see it right in front of them? When I was doing my original googling, I was getting next to nothing for results. It is funny how that can work out sometimes. I built upon the above codebase and pushed my code to GitHub and nuget because I thought I was providing something of value. It wasn’t until I searched for my nuget package that I saw about a dozen other packages doing similar things. That being said, there are only a couple that include everything I did – others are just models or binders, so it is somewhat of use. Also, I see in the most used package a minor flaw in logic in the binder, but it doesn’t break any functionality, so not a big deal. Finally, the process gave me a chance to do a deep-dive into Expressions, and that was very enlightening, so the entire process was still of use, even if the nuget package isn’t. 🙂

Backbone.js

We have decided to use backbone.js for a project at work, so I have been soaking up everything I can find about it. Tekpub has a great series (currently in development) that I am really digging, and it has got me pretty excited.

I recently checked out the Peepcode preview and it looks pretty promising. A co-worker also pointed me to a great book hosted on Github. I’d also like to check out the NetTuts backbone/.NET videos. Can you tell I like video learning?
🙂

I started thinking that WebAPI would probably work really well with backbone rather than a full-blwon MVC site. I started searching and I have been finding some great links, so I thought I’d compile a list of them here:

I am (obviously) a little late to jump on the backbone bandwagon, so there is a ton of great content out there. I would really like to find a project that can allow C# code to be converted into backbone models, but that may be a bit difficult. It would be great to use the strongly-typed models and then add some spice for backbone and have some Nuget-able library that can convert the C# model/spice to backbone for you to save some of the javascript work. Don’t get me wrong – I am not afraid of javascript. Quite the contrary – I have grown to really love javascript. What I don’t like is doing things twice. Writing the backbone views and then writing a lot of the same type of code on the server-side (for the data persistence) just doesn’t sound appealing.

One thing that could maybe make it all a little easier is to use Massive. I recently swapped out some data access code that was using SubSonic to use Massive (eliminating some other DLLs along the way too) and it is pretty cool. Of course, it uses the dreaded dynamic keyword, so no fancy-pants Intellisense, but that is okay. Methinks that a properly coded backbone app using WebAPI would result in very little server-side code anyway, so some dynamic objects pushing and pulling to and from a db would be no big deal.

MVC Templates

I am creating a plugin for our nopCommerce site, and I wanted to use a rich text editor for my admin page. I started looking at how to use the Telerik MVC editor, but then I realized I should be looking at an editor template. I found a great post by Brad Wilson about MVC templates.

This got me thinking. We opted to switch the rich editor from Telerik to CKEditor (for file upload ability) and when we did that I made the change by creating a new shared editor template. Since this plugin is ultimately used within the admin section, I thought I may be able to make use of the existing editor template. Sure enough, I could. Adding a simple template name parameter to the Html.EditorFor did the trick.

Conditional validation

Related to my recent post about cascading drop down lists, I needed to do some conditional validation based on a drop down list selection. I found a great post on Simon Ince’s blog about conditional validation in MVC 3. He even has a new project to wrap up some of the conditional functionality that he blogged about, but I decided to roll my own since I would learn more going that route.

Using the project attached to his post, I started dissecting what he was doing. After a while, I got the client validation working, but I realized I was so focused on the client/server validation piece that I did not get my conditions correct! After a few tweaks, I finally got everything working. Here is the custom attribute:

public class ConditionalMaximumWeightAttribute : ValidationAttribute, 
                                                 IClientValidatable {

    private const string ERRORMSG = "Weight must not exceed {0} lbs.";

    public string DependentProperty { get; set; }
    public string DependentValue { get; set; }
    public int MaximumWeight { get; set; }

    public ConditionalMaximumWeightAttribute(string dependentProperty, 
                                             string dependentValue, 
                                             int maximumWeight) {
        this.DependentProperty = dependentProperty;
        this.DependentValue = dependentValue;
        this.MaximumWeight = maximumWeight;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
                         ModelMetadata metadata, ControllerContext context) {
        var rule = new ModelClientValidationRule() {
            ErrorMessage = String.Format(ERRORMSG, this.MaximumWeight),
            ValidationType = "maximumweight",
        };

        string depProp = BuildDependentPropertyId(metadata, context 
                                                            as ViewContext);

        rule.ValidationParameters.Add("dependentproperty", depProp);
        rule.ValidationParameters.Add("dependentvalue", this.DependentValue);
        rule.ValidationParameters.Add("weightvalue", this.MaximumWeight);

        yield return rule;
    }

    protected override ValidationResult IsValid(object value, 
                                        ValidationContext validationContext) {
        // get a reference to the property this validation depends upon
        var containerType = validationContext.ObjectInstance.GetType();
        var field = containerType.GetProperty(this.DependentProperty);

        if (field != null) {
            // get the value of the dependent property
            var dependentvalue = 
                field.GetValue(validationContext.ObjectInstance, null);

            var weight = 
                containerType.GetProperty(validationContext.DisplayName);
            int weightvalue = 
                (int)weight.GetValue(validationContext.ObjectInstance, null);

            // compare the value against the target value
            if (dependentvalue == this.DependentValue && 
                                  weightvalue > this.MaximumWeight) {
                // validation failed - return an error
                return new ValidationResult(String.Format(ERRORMSG, 
                                            this.MaximumWeight));
            }
        }

        return ValidationResult.Success;
    }

    private string BuildDependentPropertyId(ModelMetadata metadata, 
                                            ViewContext viewContext) {
        // build the ID of the property
        string depProp = viewContext.ViewData.TemplateInfo
                         .GetFullHtmlFieldId(this.DependentProperty);
        // unfortunately this will have the name of the current field appended 
        // to the beginning,
        // because the TemplateInfo's context has had this fieldname appended 
        // to it. Instead, we
        // want to get the context as though it was one level higher (i.e. 
        // outside the current property,
        // which is the containing object (our Person), and hence the same 
        // level as the dependent property.
        var thisField = metadata.PropertyName + "_";
        if (depProp.StartsWith(thisField))
            // strip it off again
            depProp = depProp.Substring(thisField.Length);
        return depProp;
    }
}

Gist

To put this in context, I need to restrict a maximum weight allowed for a carrier. At a certain point, we may as well go with another carrier because it is cheaper. However, I don’t want to restrict the maximum weight if the carrier that has been selected is the cheaper carrier.

The attribute is used like so, where PropertyName is the name of the related property to check, PropertyValue is the conditional value of the property, and MaximumWeight is an integer representing the maximum weight for the conditional:

public class ...

    [ConditionalMaximumWeight("PropertyName", "PropertyValue", MaximumWeight)]
    [Required(ErrorMessage = "Weight required")]
    public int? Weight { get; set; }

    ...
}

Here is the client-side implementation:

<script type="text/javascript">
    $.validator.addMethod("maximumweight",
        function (value, element, parameters) {
            var carrier = $("#" + parameters["dependentproperty"]).val();
            var carriervalue = parameters["dependentvalue"].toString();
            var weightvalue = Number(parameters["weightvalue"]);
            if (carrier == carriervalue && value > weightvalue) {
                return false;
            }
            return true;
        }
    );

    $.validator.unobtrusive.adapters.add(
    "maximumweight",
    ["weightvalue", "dependentproperty", "dependentvalue"],
    function (options) {
        options.rules["maximumweight"] = {
            weightvalue: options.params["weightvalue"],
            dependentproperty: options.params["dependentproperty"],
            dependentvalue: options.params["dependentvalue"]
        };
        options.messages["maximumweight"] = options.message;
    });
</script>

Gist

I should probably do a little null checking in on the client-side, but I may just find that out the hard way! 🙂

ASP.NET MVC Cascading drop down lists

Found this great post on how to create cascading drop downs in ASP.NET MVC.

I created a page for looking up shipping rates by carrier, weight and zip code. For my particular usage, I had 2 lists: Carrier and ShipMethod. I wanted the cascading list to be disabled when the initial list selection had yet to be made. I created functions to populate the target list as well as enable/disable the target list. I made the js into a reusable Razor helper which should allow me to use it anywhere I need this functionality.

Here is the helper code:

@helper DynamicDropDowns() {
<script type="text/javascript">
    function listChanged($list, $target, url) {
        var listId = $list.val();
        if (listId == "") { // User selected first option, 
                            // so clear and disable the list
            $target.empty();
            enableList($target, false);
            return;
        }
        $.getJSON(url, { id: listId }, function (data) {
            $target.empty(); // Clear the list
            $.each(data, function (idx, item) { // Add the data
                $target.append($("<option/>",
                {
                    value: item.Value,
                    text: item.Text
                }));
            });
            enableList($target, true); // Enable the list
        });
    }

    function enableList($list, enabled) {
        $list.attr("disabled", enabled ? null : "disabled");
    }
</script>
}

Gist

And here it is in action:

<script type="text/javascript">
    $(function () {
        var $carrier = $("#Carrier");
        var $ship = $("#ShipMethod");
        enableList($ship, false);
        $carrier.change(function () {
            listChanged($(this), $ship, "/Tools/GetShipMethodsByCarrier");
        });
    });
</script>

My first foray into ASP.NET MVC

I have recently begun the .NET MVC journey, and I see recurring “buzzwords”: Inversion of Control (IoC) and Dependency Injection (DI). If you are at the same point in your MVC journey as me, you may be wondering what the heck these things are?!?! They have certainly caused me a bit of confusion. I have yet to implement DI, but I have decided to stick with the MS stack and try out Unity.

I decided I’d give this whole thing another shot tonight. I recently built my first little MVC application – a guestbook. Remember those from 1996? I thought it would be something a bit different and I knew it would be pretty simple (the database is two tables, 1 of which I am really not using right now). I also brought it into the 21st century with a little Google mappage to show where the guestbook signer is located on our big, blue marble. I’ve got it mostly working and I’ll get it up online as soon as I get the membership stuff locked down.

I want to “do it the right way”, so I want to try out the DI stuff. I have been searching for a good starter post that would break down the whole IoC/DI stuff into small, digestible chunks that my overworked brain could handle. I finally found .NET HITMAN’s post that breaks down the history behind Unity, why DI is a good thing, and how to add references to the Unity DLL’s to your project, which is exactly what I was in need of. Since this is an ASP.NET MVC app, I also found Shiju Varghese’s post that explains how to add DI to the NerdDinner project. Since I “followed along” with the NerdDinner app while creating my Guestbook app, I found the post extremely helpful and easy to follow.

When I started off with my MVC project, I went with SubSonic 3.0 for data access. I am a big fan of SubSonic and I use 2.1 at work, so I was really interested to see what 3.0 had to offer and I knew that with Rob’s focus on MVC that 3.0 would work quite nicely. It also gave me a chance to use some LINQ goodness, which, to this point, I haven’t been able to use extensively. I was quite impressed with the T4 LinqTemplates and overall I think 3.0 is a great new addition to the SubSonic family.

Another thing I keep seeing in MVC apps is repositories. It is my understanding that the repository enables easier unit testing (but I am an .NET MVC n00b, so I could be wrong) since the controller isn’t talking directly to your data access code. So I went about creating a GuestbookRepository class for my controller to talk to.

Now that I am going the whole DI route, it seems I need to first create an interface, then inherit from that interface. So here is the IGuestbookRepository interface:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using MvcApplication.Models;

namespace MvcApplication.Repositories {

    public interface IGuestbookRepository {

        IQueryable<mvc_guestbook> GetAllMessages();
        mvc_Guestbook GetMessage(int id);
        void Add(mvc_Guestbook guestbook);
        void Delete(mvc_Guestbook guestbook);
        void Save(mvc_Guestbook guestbook);
        void Update(mvc_Guestbook guestbook);
    }
}

* NOTE: I don’t really like the mvc_Guestbook references in there (they seem smelly) but I am not sure what I should put there, so this is going to have to do for now until I determine if this is correct or find out what is correct.

Now that I have my interface, I modifed my GuestbookRepository class to inherit from the interface. Here is the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using MvcApplication.Models;

namespace MvcApplication.Repositories {

    public class GuestbookRepository : IGuestbookRepository {

        private GuestbookDB db = new GuestbookDB();

        public IQueryable<mvc_guestbook> GetAllMessages() {
            return from guestbook in db.mvc_Guestbooks
                   orderby guestbook.MessageDate descending
                   select guestbook;
        }

        public mvc_Guestbook GetMessage(int id) {
            return db.mvc_Guestbooks.SingleOrDefault(g => g.GuestbookID == id);
        }

        public void Add(mvc_Guestbook guestbook) {
            guestbook.Add();
        }

        public void Delete(mvc_Guestbook guestbook) {
            guestbook.Delete();
        }

        public void Save(mvc_Guestbook guestbook) {
            guestbook.Save();
        }

        public void Update(mvc_Guestbook guestbook) {
            // Save message history
            SaveHistory(guestbook.GuestbookID);
            // Save updated message
            guestbook.Update();
        }

        private void SaveHistory(int id) {
            mvc_Guestbook past = mvc_Guestbook.SingleOrDefault(g => g.GuestbookID == id);
            mvc_GuestbookHistory history = new mvc_GuestbookHistory();
            history.GuestbookID = past.GuestbookID;
            history.Name = past.Name;
            history.Email = past.Email;
            history.Message = past.Message;
            history.Location = past.Location;
            history.Latitude = past.Latitude;
            history.Longitude = past.Longitude;
            history.EditDate = DateTime.Now;
            history.Add();
        }
    }
}

We’ve got all our basics: Get all, get one, create, delete. There are also methods for adding and saving. It seems SubSonic uses .Save() as either add or update, while .Add() and .Update() only work as, well, add or update. Also of note in the Update method is the call to SaveHistory. This is meant to show an update history of the messages, though I am not currently sure if I am going to enable editing. Better to have this in now and not need it, I guess.

Finally, we have the GuestbookController which uses the dependency injection I just set up. Here is the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;

using MvcApplication.Models;
using MvcApplication.Repositories;

namespace MvcApplication.Controllers {

    public class GuestbookController : Controller {

        private IGuestbookRepository gr;

        public GuestbookController(IGuestbookRepository repository) {
            gr = repository;
        }

        public ActionResult Index(int? page) {
            const int pageSize = 5;
            var guestbook = gr.GetAllMessages();
            var pagedGuestbook = new PaginatedList<mvc_guestbook>(guestbook,
                page ?? 0,
                pageSize);
            return View(pagedGuestbook);
        }

        public ActionResult AjaxIndex(int? page) {
            const int pageSize = 5;
            var guestbook = gr.GetAllMessages();
            var pagedGuestbook = new PaginatedList<mvc_guestbook>(guestbook,
                page ?? 0,
                pageSize);
            return PartialView("Messages", pagedGuestbook);
        }

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Create() {
            if (Session[Request.ServerVariables["REMOTE_ADDR"].ToString()] != null ? DateTime.Now.Subtract(Convert.ToDateTime(Session[Request.ServerVariables["REMOTE_ADDR"].ToString()])).Minutes >= 5 : true) {
                mvc_Guestbook guestbook = new mvc_Guestbook();
                return View(guestbook);
            } else {
                Session["DELAY"] = (5 + Convert.ToDateTime(Session[Request.ServerVariables["REMOTE_ADDR"].ToString()]).Subtract(DateTime.Now).Minutes).ToString();
                return View("Denied");
            }
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create(mvc_Guestbook guestbook) {
            if (ModelState.IsValid) {
                try {
                    guestbook.MessageDate = DateTime.Now;
                    gr.Save(guestbook);
                    Session[Request.ServerVariables["REMOTE_ADDR"].ToString()] = DateTime.Now.ToString();
                    return RedirectToAction("Details", new { id = guestbook.GuestbookID });
                } catch {
                    ModelState.AddModelError("Error", "Error saving message");
                }
            }
            return View();
        }

        [Authorize]
        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Edit(int id) {
            mvc_Guestbook guestbook = gr.GetMessage(id);
            if (guestbook == null) {
                return View("Not Found");
            } else {
                return View(guestbook);
            }
        }

        [Authorize]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit(int id, FormCollection collection) {
            mvc_Guestbook guestbook = gr.GetMessage(id);
            try {
                UpdateModel(guestbook);
                gr.Update(guestbook);
                return RedirectToAction("Details", new { id = guestbook.GuestbookID });
            } catch {
                ModelState.AddModelError("Error", "Error saving message");
                return View(guestbook);
            }
        }

        [Authorize]
        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Delete(int id) {
            mvc_Guestbook guestbook = gr.GetMessage(id);
            if (guestbook == null) {
                return View("Not Found");
            } else {
                return View(guestbook);
            }
        }

        [Authorize]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Delete(int id, string confirmButton) {
            mvc_Guestbook guestbook = gr.GetMessage(id);
            if (guestbook == null) {
                return View("Not Found");
            } else {
                gr.Delete(guestbook);
                return View("Deleted");
            }
        }

        public ActionResult Details(int id) {
            mvc_Guestbook guestbook = gr.GetMessage(id);
            if (guestbook == null) {
                return View("NotFound");
            } else {
                return View(guestbook);
            }
        }
    }
}

For the code to wire this all up, I used Shiju’s example of the HttpContextLifetimeManager class as well as the UnityControllerFactory class. However, since I wasn’t using the NerdDinner code but my own Guestbook, I had to make the following changes to the UnityControllerFactory.Configure method:

public static void Configure() {
    //create new instance of Unity Container
    IUnityContainer container = new UnityContainer();
    //Register dependencies
    container.RegisterType<IFormsAuthentication, FormsAuthenticationService>();
    container.RegisterType<IMembershipService, AccountMembershipService>();
    container.RegisterInstance<MembershipProvider>(Membership.Provider);

    container.RegisterType<IGuestbookRepository, GuestbookRepository>(new HttpContextLifetimeManager<IGuestbookRepository>());
    ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container));
}

Finally, as Shiju illustrates, I added the call to UnityControllerFactory.Configure() into the Application_Start() method in my Globals.asax file and all is well.

All in all, I wouldn’t say I am 100% comfortable with exactly all that is happening in the code, but it is a good start at understanding DI with .NET MVC.