Pieter Germishuys

Trying to be a better software craftsman

Navigation Menu

Cascading DropDownList with ASP NET MVC 2 and JQuery

Posted by on Oct 13, 2011 8:41 PM in mvc,jquery,aspnet,dropdownlist | 0 comments

First we will need to setup the JsonResult controller action.

/// <summary></summary>  
/// Get Models
/// <param name="makeID" />  
/// <returns></returns>  
public JsonResult GetModels(string id)  
{   
    JsonResult result = new JsonResult();   
    var filteredModels = from model in homeViewModel.Models   
                         where model.MakeID.ToString() == id  
                         select model;   
    result.Data = filteredModels.ToList(); 
    result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
    return result;  
} 

This method now gives us the ability to use the nifty $.getJSON jquery call. The signature for the call is as follows

jQuery.getJSON( url, [ data ], [ callback(data, textStatus) ] )

Given that we have setup 2 Drop Down Lists, one for Makes and the other for Models, like so.

Html.DropDownListFor((model) => model.MakeID, new SelectList(Model.Makes, "ID", "Description")) Html.DropDownListFor((model) => model.ModelID, new SelectList(Model.Models, "ID", "Description"))

we can include the following bit of jquery

//Hook onto the MakeID list's onchange event  
$("#MakeID").change(function() {   
//build the request url   
var url = '<!--Url.Content("~/")-->' + 'Home/GetModels';

//fire off the request, passing it the id which is the MakeID's selected item value   
$.getJSON(url, { id: $("#MakeID").val() }, function(data) {    
//Clear the Model list    
$("#ModelID").empty();    
//Foreach Model in the list, add a model option from the data returned    
$.each(data, function(index, optionData) {     
  $("#ModelID").append("<option value=" + optionData.ID +">"+optionData.Description+"</option>");    
});   
});  
}).change();

Read More

Building Games for Windows Phone 7 using XNA 4.0

Posted by on Apr 14, 2011 10:02 PM in xna,teched | 0 comments

As the last day of TechEd Africa has finally dawned on us, I must say that I have had a blast. It was an amazing 3 days!

Considering everyone had such a blast at the after party, by just looking at the photos going up, We had a pretty good attendance at the Building Games for Windows Phone 7 using XNA 4.0. For those who would like to get their hands on the slides and the demo, please grab them here :)

alt text

Slide Decks and the Sample Code

Thank you to everyone that attended my session!

Read More

ASP.NET MVC 3 Good Looking jQuery Validation

Posted by on Apr 14, 2011 10:02 PM in asp,mvc,jquery,validation | 0 comments

I really like good looking websites and along with that a great user experience.

Cedric Dugas' jQuery Validation Engine is now hosted on github. If you have not seen what the jQuery Validation engine looks like, you are definitely missing out.

alt text

Now wouldn't you want something like that to replace your standard, boring ASP.NET MVC validation?

I have decided to give it a bash using an HTML Helper Extension method.

public static class HtmlExtensions
{
    public static MvcHtmlString ValidatedEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        if (htmlHelper.ViewData.ModelMetadata.ModelType == null)
        {
            return new MvcHtmlString(String.Empty);
        }

        TagBuilder tagBuilder = new TagBuilder("input");
        var name = ExpressionHelper.GetExpressionText(expression);
        string validation = String.Empty;
        //Try to get the attributes for the property
        Object[] objects = typeof(TModel).GetProperty(name).GetCustomAttributes(true);
        foreach (Attribute attribute in objects)
        {
            if (attribute.GetType() == typeof(RequiredAttribute))
            {
                validation += "validate[required]";
            }
            if (attribute.GetType() == typeof(RangeAttribute))
            {
                var min = ((RangeAttribute)attribute).Minimum;
                var max = ((RangeAttribute)attribute).Maximum;
                validation += String.Format("validate[required, min[{0}],max[{1}]]", min, max);
            }
            if (attribute.GetType() == typeof(StringLengthAttribute))
            {
                var minimumLength = ((StringLengthAttribute)attribute).MinimumLength;
                var maximumLength = ((StringLengthAttribute)attribute).MaximumLength;
                string validator = String.Format("maxSize[{0}]", maximumLength);

                if (minimumLength >= 0)
                {
                    validator += String.Format(",minSize[{0}]", minimumLength);
                }
                validation += String.Format("validate[required, {0}", validator);
            }
        }

        tagBuilder.GenerateId(name);
        tagBuilder.AddCssClass(validation);
        return new MvcHtmlString(tagBuilder.ToString());
    }
}

Here is a link to the sample website, updated to ASP.NET MVC 4

Read More

Using Automapper between Models and ViewModels

Posted by on Apr 14, 2011 10:01 PM in asp,mvc,automapper,models,viewmodels | 0 comments

First, let me introduce you to Automapper, A convention-based object-object mapper. alt text

"AutoMapper uses a fluent configuration API to define an> object-object mapping strategy. AutoMapper uses a convention-based> matching algorithm to match up source> to destination values. Currently, AutoMapper is geared towards model projection scenarios to flatten complex object models to DTOs and other simple objects, whose design is better suited for serialization, communication, messaging, or simply an anti-corruption layer between the domain and application layer."domain and application layer."and application layer."

When developing Subtle (The blog engine currently used to run pieterg.com), I needed the ability to easily map the ViewModels to Domain Models. Let's say a login view for example. I will get to the GetUser method in a bit

/// <summary>    
/// Account Login View Model    
/// </summary>
public class AccountLoginViewModel    
{
        public string Username { get; set; }
        public string Password { get; set; }    
}

I have removed the validation attributes

/// <summary>   
/// User    
/// </summary>    
public class User
{
        public virtual int ID { get; set; }
        public virtual string Username { get; set; }
        public virtual string Password { get; set; }
        public virtual string VerificationGuid { get; set; }
        public virtual bool Verified { get; set; }    
}

Now we need to tell Automapper how to map these types, and in most cases, it's generally quite good at figuring out the mapping itself.

Mapper.CreateMap<AccountLoginViewModel, User>();

This only needs to be setup once and can be done in the Global.asax. What I have chosen to do is leverage Ninject and create an AutoMapping module.Now that we have done the initial setup, let's take a look at a controller action.

[HttpPost]    
public ActionResult Login(AccountLoginViewModel accountLoginViewModel)    
{       
        //Get the user from the Account Login View Model        
        User user = accountLoginViewModel.GetUser();                
        //Validate the user         
        //If you have failed, pass back the accountLoginViewModel
        return View(accountLoginViewModel);    
}

This is our simple login action that gets passed an AccountLoginViewModel. I wanted to hide the mapping as much as possible and chose to do it in a method called GetUser(). The reason for this is so that if something goes haywire, I can pass the ViewModel back to the view and let the user correct their mistakes, also keeping the views clean and dumb.The magic of AutoMapper happens in the GetUser method

/// <summary>    
/// Get User    
/// </summary>    
/// <returns></returns>    
public User GetUser()    
{
        User user = new User();
        AutoMapper.Mapper.Map<AccountLoginViewModel, User>(this, user);
        return user;
}

There are more complex scenarios, but as a brief introduction to Automapper, I think this post will suffice.

Read More

HtmlHelper extension method for Disqus

Posted by on Apr 14, 2011 6:32 AM in disqus,htmlhelper | 0 comments

I could not help myself but create an HtmlHelper extension method for Disqus as all the script tags made me (my view) feel a bit dirty.

After reading the following question on Stackoverflow, I was tempted to go back and look at how I was adding Disqus to my views.

/// <summary>
/// Display Comments for Post
/// </summary>
/// <param name="html"></param>
/// <param name="post"></param>
/// <returns></returns>
public static MvcHtmlString DisplayCommentsForPost(this HtmlHelper html, string shortName, Post post)
{
    StringBuilder commentsBuilder = new StringBuilder();
    commentsBuilder.Append("<div id=\"disqus_thread\">");
    commentsBuilder.Append("</div>");
    commentsBuilder.Append("<a href=\"http://disqus.com\" class=\"dsq-brlink\">blog comments powered by <span class=\"logo-disqus\">");
    commentsBuilder.Append("Disqus</span></a>");
    commentsBuilder.Append("<script type=\"text/javascript\">");
    commentsBuilder.Append("var disqus_shortname = '" + shortName + "';");
    commentsBuilder.Append("var disqus_identifier = '" + post.ID + "';");
    commentsBuilder.Append("var disqus_url = '" + HttpContext.Current.Request.Url + "';");
    commentsBuilder.Append("var disqus_developer = 0;");

    /* * * DON'T EDIT BELOW THIS LINE * * */
    commentsBuilder.Append("$(document).ready(function () {");
    commentsBuilder.Append("var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;");
    commentsBuilder.Append("dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';");

    commentsBuilder.Append("(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);");
    commentsBuilder.Append("})();");
    commentsBuilder.Append("</script>");
    commentsBuilder.Append("<noscript>");
    commentsBuilder.Append("Please enable JavaScript to view the <a href=\"http://disqus.com/?ref_noscript\">comments");
    commentsBuilder.Append("powered by Disqus.</a>");
    commentsBuilder.Append("</noscript>");
    return MvcHtmlString.Create(commentsBuilder.ToString());
}

Read More