ASP.NET MVC Html Helpers Not Using Updated Model Values

If you’re using the Html helpers with the naming convention TypeNameFor (Func<>…) or the TypeName (string name,…), like TextBoxFor or TextBox, you might find some odd behavior when you post back form data to the controller, update your model, and send the model back to the view.  I was pulling teeth trying to figure out why certain input text boxes and drop down lists were not being set to the values I had in the model.

Problem:  ASP.NET MVC uses the post back data to set any drop down lists, text boxes, hidden fields, etc. before it uses a particular model’s values.  Let’s say you have the simple model below.

public class Car {
public Manufacturer Make {get;set;}
public string Color {get;set;}
}

In your view you are trying to use the “For” Html helper methods to display the car’s color input, your markup would be:

<% using (Html.BeginForm()) { %>
...
<%=Html.LabelFor(m => m.Color)%>
<%=Html.TextBoxFor(m => m.Color)%>
...
<% } %>

In the simplest cases, this works very well because it automatically binds the value to you model if you use automatic binding (i.e. you post method takes an instance of Car) or manually bind with TryUpdateModel<T>.  A problem arises when you post back, modify the model value, in our case Color, and re-show the form.  This sort of scenario can arise when you have an add form that once the user is done adding one record, you send them back to the add form with new defaults so they can add another record.  Below shows the simple controller and UI flow that will do this.

public CarsController : Controller {
[HttpGet]
public ActionResult Add() {
// our default we want
Car car = new Car {
Color = "Hot Sexy Pink"
};
return View(car); // return the model we want displayed
}

[HttpPost]
public ActionResult Add(Car car) {
try {
carDao.MakePersistent(car);
return Add(); // once saved, return user to add another
} catch {...}
}
}
The UI sequence will be as follows:
 
1.  You initially arrive at page “/Cars/Add” and Color input is:
 
first_add

 

 

2.  You change the value to the color you want.

after_add

3.  You submit the form, car is saved and controller returns you back to the add form to enter another car, but this time the default is incorrect, well from what you want it to be!  It still shows “Firey Red” for the color when the default should be “Hot Sexy Pink”, because the Add() controller method creates a new Car instance, set’s the Color value, and passes it back to the view.

rrr_add

The framework is setting the color input with the forms posted values (ModelState key’s values) and not the model value (car in our case) that you are passing to your view.  I can understand this because it’s the sticky form concept which is very useful, but not in this kind of scenario.  You want it to be set to your defaults.

Solution:  Clear the ModelState before redisplaying the form.  Since the helpers are using the ModelState key’s values, you can make a call to ModelState.Clear() to clear out the posted values.  If clearing all the values is not an option, you will have to set the keys to the desired default values.  Below shows a modification to our view and controller code that will fix our situation.  In the controller I’ve left a bunch a code out for brevity, like validation and error handling, but the idea is if the save is successful, clear the ModelState, and return user to a new add form with correct defaults.

<% using (Html.BeginForm()) { %>
...
<%=Html.LabelFor(m => m.Color)%>
<%=Html.TextBoxFor(m => m.Color)%>
OR
<label>Car color:</label>
<%=Html.TextBox("Color", Model.Color)%>
...
<% } %>

public CarsController : Controller {
[HttpPost]
public ActionResult Add(Car car) {
try {
carDao.MakePersistent(car);
ModelState.Clear(); // clear model state so new add form will not have old posted data
return Add(); // once saved, return user to add another
} catch {...}
}
}

Notice that I named the text box’s name property to the same name as the model property in the case of using Html.TextBox.  This ensures binding sets the correct properties on your model when posting back.  For example if the Car class had a decimal property like “Engine.Displacement”, the text box name would be “Engine.Displacement”.  This is very convenient, but there is a caveat with this as well which I talk about in this post, ASP.NET MVC Html.DropDownList Not Showing Selected Value.

ASP.NET MVC Html.DropDownList Not Showing Selected Value

I’ll have to admit, this is one of the only unfortunate nuances that I’ve come across in the ASP.NET MVC framework. 

Problem:   You’re using the Html.DropDownList, it’s name property is the same as your model’s property name, you pass a SelectList with you selected value, but in the UI it’s not showing your expected selection.  The reason behind this problem is that ASP.NET MVC first looks for a match between the name of the drop down and a property on the model. If there’s a match, the selected value of the SelectList is overridden and no value is selected.  This can be annoying.  Here is our example, which is as simple as I can get it without loosing the meaning.

// models
public class CarRegistration {
public string CountryCode {get;set;} // iso 2 char code
}
public class Car {
public CarRegistration Registration {get;set;}
public string Color {get;set;}
}

public CarsController : Controller {
[HttpGet]
public ActionResult Edit(string vin) {
Car car = carsDao.FindByVin(vin);
ViewData["countries"] = new SelectList(
contriesDao.List(), // list of countries for select list
"Code", // select value attribute
"CountryName", // select text display
car.Registration.CountryCode); // selected value
return View(car);
}
}
 
In your view you have the following Html.DropDownList helper rendering the countries list.  Notice that the name for the drop down list is “Registration.CountryCode”.  The reason for doing this is so when form is posted back, it will bind to the car instances property.  This part is handy, but what you don’t expected is that when the edit view is displayed the value that is stored in our car’s registration country is not selected in the drop down.
 
<%= Html.DropDownList("Registration.CountryCode", (IEnumerable<SelectListItem>)ViewData["countries"]) %>

Lets pretend our registration country for some car is DE, or Germany.  Your SelectList will have a internal list of SeletListItem’s that should produce the following in the rendered view.  Instead, of rendering what is show below, you get a select list of countries without any options that have the selected attribute set.
 
<select id="Registration_CountryCode" name="Registration.CountryCode">
...
<option value="GE">Georgia</option>
<option value="DE" selected="selected">Germany</option>
<option value="GH">Ghana</option>
...
</select>

Solution:  The solution to this issue lies within the name of the drop down list.  Changing the name to not match the model’s property name will correctly render the drop down with the selected value.  So change our view to the following corrects the problem.

<%= Html.DropDownList("countryCode", (IEnumerable<SelectListItem>)ViewData["countries"]) %>

The downside to this is that you cannot rely on model binding and have to pick this value out manually.

...
public ActionResult Edit(Car car) {
// get registration country
car.Registration.CountryCode = Request.Form["countryCode"];
}

Alternate Solution:  Ok, I had to amend this post because after looking at the source code for the MVC framework I noticed something that wasn’t quite intuitive.  There actually is a way to keep the model binding and have the correct select list and selected value.  The trick is you must add the selected list to the ViewData with the key name of you property and pass null to the Html.DropDownList helper (or use the DropDownListFor helper).  According to the example above here is how it is done:

public CarsController : Controller {
[HttpGet] public ActionResult Edit(string vin) {
Car car = carsDao.FindByVin(vin);
ViewData["Registration.CountryCode"] = new SelectList( // notice the view data key name!
contriesDao.List(), // list of countries for select list
"Code", // select value attribute
"CountryName", // select text display
car.Registration.CountryCode); // selected value
return View(car);
}
}

Our view now will have this:

<%= Html.DropDownList("Registration.CountryCode") %>

OR

<%= Html.DroopDownListFor(m => m.Registration.CountryCode)%>

The reason this works is because the helper extension for the DropDownList checks the ViewData collection for a key named “Registration.CountryCode” and casts it to IEnumerable<SelectListItem>.  Since you already stuffed this in the ViewData, it finds your existing list with the correctly selected value and inserts into the view.  In addition, you model binding will work now!

Localizing Validation Using DataAnnotations

Problem: I’m working this project using ASP.NET MVC, and I’d like to use the MVC’s built in validation at the same time localize it to produce culture specific error messages.  On of the issues I was having is trying to get the DataAnnotation’s to use my existing global resources that were in the sites “App_GlobalResources”.  This didn’t work because DataAnnotations use strong typed resource class names so they can be used in other applications like Silverlight, WinForms, etc.

Solution:

The solution is pretty simple but requires a little extra work on your part.  Once it’s setup, adding culture specific messages is a breeze.  In this example, my annotated classes live in a separate assembly from the main application.

1.  First off we need to add resources to the assembly that has our classes that will be annotating.  I create a folder called “Resources” for organization, as shown below.

resources_folderThere are a couple of ways you can add you resource files to you project.  You can either manually add them by right clicking on the folder and adding the new item, or you can try my DotNetLocalizer tool which will automate most of it for you.  Please note that the tool is a work in progress, but it does utilize Google translator which makes auto translation of your resources very fast.  When you add you resources there are a few important points to note.  First, you need to open the resx designer (double click the resx file) and set the Access Modifier to Public.  This is important so the DataAnnotations can access the resource data.

access_mod

Now verify and set the following properties on all the resx files.  Right click the resx file and select Properties.  The Build Action is usually set to this by default but it never hurts to double check.

resx_propsNow based on the above setup, you should have strongly typed resources in your assembly.  Using the example assembly pictured above, the resource class would be Wictbm.Core.Resources.Validation.

2.  Now comes the fun part with the annotations.  Below shows a snippet of a class I have with annotated properties.  The annotations are the three items that mark the property “HousingCost”: Required, Range, and DisplayFormat.  Of the three, the one to notice is the Required attribute’s named parameters ErrorMessageResourceName and ErrorMessageResourceType.  The ErrorMessageResourceName is the resource key value, and the ErrorMessageResourceType is the class key value which it strongly typed.  As you can see the value for ErrorMessageResourceType is the class “Resources.Validation”, which is short for the full path of Wictbm.Core.Resources.Validation.

dataannotation 3.  Lastly, we need to do some validation.  Since I was working on a ASP.NET MVC application, I will demonstrate it below (note that I am using version 2 of mvc).  Other applications follow the same type of concepts.  Highlighted in the image below shows the html helper used to trigger the validation messages should there be any validations that fail.  In Step 2’s image shows this property “HousingCost” as Required.

mvc_validation

Let’s see what happens when our UI culture is set to Spanish and the form is submitted with this property blank.  First I’ll show the before then the failed validation.  As we can see, the message before form submission shows no error, then after submitting the form with no data present in the text box results in the error message that I’ve highlighted in yellow.

validation_before

validation_result 
That’s it.  You can also add client validation which makes use of the DataAnnotation’s in the web site.  A good example of this is shown in Scott Gu’s Model Validation post.  If your working on a ASP.NET site and are curious how I set the user’s culture on the page request see my blog on Setting Culture For ASP.NET Page Request.

Setting Culture For ASP.NET Page Request

.NET makes it easy to work with different locales by using the System.Globalization.CultureInfo class.  In a web application you can take advantage of culture specific behaviors such as date and currency formats by setting the executing thread’s culture properties.  Doing this allows your application properly format a decimal when you call you use formatting like “{0:C}” for currency, see Numeric Formatting Strings.

Problem:  Need to store user’s preferred culture and set the culture on page request so that the application take advantage of user’s setting.

Solution:  There are are a number of ways to store the culture.  I like to have options so, I the following three areas: url query string, cookies, and user language (from browser).  You can also use session, database, sub domain (i.e. en.mysite.com for english), but I find these three to be to be the lightest weight and work well.

1.   Create a HttpModule to step into the request pipeline and set the thread’s culture.  Below shows the module I use.  Notice the order of precedence for getting language.  I first check cookie, then query string, and final browser language.  The key to getting the application to use the correct culture is the lines where we set Thread.CurrentThread culture properties.  Finally I store whatever value I find back in a cookie for the next time.

using System.Globalization;
using System.Web;
using System.Threading;

namespace MyAssembly {
public class LocalizationModule : IHttpModule
{
private static readonly string LANGUAGE_CULTURE_PARAM = "lang";
private static readonly CultureInfo DEFAULT_CULTURE = new CultureInfo("en");

public void Dispose() { }

public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new System.EventHandler(context_PreRequestHandlerExecute);
}

void context_PreRequestHandlerExecute(object sender, System.EventArgs e)
{
HttpRequest request = HttpContext.Current.Request;
HttpCookie cookie = request.Cookies[LANGUAGE_CULTURE_PARAM];
string lang = null;
CultureInfo ci;

if (cookie != null) // check cookie first
lang = request.Cookies[LANGUAGE_CULTURE_PARAM].Value;
else if (request.QueryString[LANGUAGE_CULTURE_PARAM] != null) // chceck query string second
lang = request.QueryString[LANGUAGE_CULTURE_PARAM];
else if (request.UserLanguages.Length > 0) // check browser language third
lang = request.UserLanguages[0];

// don't do this if you are using sub cultures like en-GB
lang = lang == null ? DEFAULT_CULTURE.Name : lang.Split('-')[0];

try
{
ci = new CultureInfo(lang);
}
catch
{
ci = DEFAULT_CULTURE;
}
// set thread's culture properties
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
// store cookie value for user's preference
if (cookie == null)
{
cookie = new HttpCookie(LANGUAGE_CULTURE_PARAM, ci.TwoLetterISOLanguageName);
HttpContext.Current.Response.AppendCookie(cookie);
}
else
cookie.Value = lang;

cookie.Path = "/";
}
}}


2.  The last task is to register the module in the web.config file.  Below shows the configuration under the system.web section of the configuration file.

<system.web>
...
<httpModules>
<add name="LocalizationModule" type="MyAssembly.LocalizationModule, MyAssembly" />
</httpModules>
...
</system.web>

reCAPTCHA Custom Styling

CAPTCHA is one of those neat little items that help prevent automated attacks on sites that have form submissions such as registration or blog posts.  I was searching for a way to use CAPTCHA in a ASP.NET MVC site, but what I found can be applied to any coding tool like PHP, Java, Ruby, etc.  I followed this excellent blog Using ReCaptcha with Asp.Net MVC for most of the backend code.  Once I got it working I realized that the default generated CAPTCHA widget didn’t go well with the site’s color palette.  Fortunately you can change the widget’s appearance.

Solution:

1.  Place this snippet before the form element that contains the CAPTCHA widget.  Note that I went with the “clean” theme.  Other themes are possible, see full reference here.

<script type="text/javascript">
var RecaptchaOptions = {
theme : 'clean'
};
</script>

2.  Somewhere in your form element place the following HTML and script reference, this is a barebones approach.  In the script reference don’t forget to replace “your_public_key” with the public key you got from signing up for API key.

<script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge?k=your_public_key"></script>
<noscript>
<iframe src="http://www.google.com/recaptcha/api/noscript?k=your_public_key"
height="300" width="500" frameborder="0"></iframe><br>
<textarea name="recaptcha_challenge_field" rows="3" cols="40">
</textarea>
<input type="hidden" name="recaptcha_response_field"
value="manual_challenge">
</noscript>

3.  If you want to internationalize your CAPTHCA widget, you can include the additional div elements shown here and add the following to the RecaptchaOptions shown in step 1.  You’ll have to insert the translated text of your choice dynamically.
 
<script type="text/javascript">
var RecaptchaOptions = {
custom_translations : {
instructions_visual : "Scrivi le due parole:",
instructions_audio : "Trascrivi ci\u00f2 che senti:",
play_again : "Riascolta la traccia audio",
cant_hear_this : "Scarica la traccia in formato MP3",
visual_challenge : "Modalit\u00e0 visiva",
audio_challenge : "Modalit\u00e0 auditiva",
refresh_btn : "Chiedi due nuove parole",
help_btn : "Aiuto",
incorrect_try_again : "Scorretto. Riprova.",
},
theme : 'clean',
};
</script>

That’s it.  My widget looked something like the image below.  I left out the some of the customization div elements and went with they’re “clean” look.

Capture

Configuring NAnt for Windows

This is somewhat of a corollary to my post on Configuring Eclipse IDE for Windows.  I will use some of the same configuration that is noted in the post and it’s repeated here for clarity.

Preparation

Create the following path variables.  To get to the system variables, right click on your computer icon and select Properties.  In the Advanced tab and click the button Environment Variables.  At the time of this writing these are the version of products I used so they may differ.

  • HOME = {drive}:\Source
  • TOOLS_HOME = {drive}:\Tools
  • NANT_HOME = %TOOLS_HOME%\nant-X (X is the version number)

Append the following to the system “Path” variable: %NANT_HOME%\bin

Installation

Note that when extracting zipped files, extract files so “app-version” isn’t sub folder with the same name (i.e. “app-version” ^ ”app-version”).

Download NAnt X and extract to %TOOLS_HOME%\nant-X

Verify by going to a command like and running “nant – help”.  You should see a list of parameters.

NHibernate and Paging Results

One of the most common operations in web sites that list data such as inventory items, blog posts, pictures, etc. is data paging.  If you happen to be using NHibernate for you project and want a really clean way to page and sort through your items, then read on. 

Problem:  The other day I was trying  to optimize some data paging that was using Linq on a large record set instead of paging the records at the data level.  I knew that NHibernate had the methods SetMaxResults and SetFirstResult for limiting results, but what I didn’t know is how to execute all the data retrieval, including total pages count, all in on query, especially using all the filters that the List<> query was using.  I knew where I wanted to get but was missing a few puzzle pieces.  I can’t take all the credit for the solution below, but I will consolidate 2 great ideas into one post.*

Solution:  Using NHibernate, we will utilize the following concepts/methods:

  • CreateMulitCriteria() – a way to execute more than one ICriteria in one database call
  • CriteriaTransformer.Clone() – clones the a given criteria object
  • SetMaxResults – limits result set
  • SetFirstResult – takes results from a starting location

Since paging is pretty common we can make use of Generics to alleviate repetitive coding, and Extensions to append functionality to the existing ISession.  If you don’t want to use Extension, you can write a static helper class.

Define a wrapper for our paged results:

public class PagedResult<TModel>
{
public IList<TModel> Items { get; protected set; }

public long TotalItems { get; protected set; }

public PagedResult()
{
this.Items = new List<TModel>();
}
public PagedResult(IList<TModel> items, long totalItems)
{
Items = items;
TotalItems = totalItems;
}
}
Define the Extension method to do the work.
public static class NHibernateExtensions
{
public static PagedResult<TModel> CreatePagedResult<TModel>(this ISession session, ICriteria criteria, int startIndex, int pageLength)
{
// clone the criteria for page count
ICriteria countCriteria = CriteriaTransformer.Clone(criteria)
.SetProjection(NHibernate.Criterion.Projections.RowCountInt64());
countCriteria.ClearOrders(); // clear order by

// set paging on base criteria
criteria.SetFirstResult(startIndex)
.SetMaxResults(pageLength);

// get all data in one execution
var multiCriteria = session.CreateMultiCriteria()
.Add(criteria)
.Add(countCriteria);
// execute both queries
IList results = multiCriteria.List();

var pagedResult = new PagedResult<TModel>(
((IList<TModel>)results[0]), // get paged items
(long)((IList)results[1])[0]); // get total records

return pagedResult;
}
}
First we clone the ICriteria which represents our parent query to get our list data.  The parent ICriteria holds all the filter conditions, grouping, etc. that is going to be applied in determining the results.  After cloning this, we apply a projection that generates the count query, and we also clear the ordering clause since it’s not needed.  Next we take advantage of the paging capabilities in the ICriteria interface, SetFirstResult and SetMaxResults.  This is similar to using TSQL’s ROW_NUMBER function, or MySql LIMIT.  In order to execute the queries in one go, we use the ISession.CreateMulitCriteria() method which prepares us for the 2 query execution.  Executing this will return our paged items and secondly our total records count.  In the case of our total records we’re only concerned with the result in the first row hence the “((IList)results[1])[0]”.
 
Here is a capture from a NHibernate Profiler.  I had to remove a lot of the columns so the important pieces are noticeable, and highlighted some of the key items.  Notice the top select is for the list of items, and the bottom select is for the total records.  Since this is SQL server 2005+ it’s making use of the ROW_NUMBER function mentioned above.
nhibernate_profile_capture

* See: stackoverflow post’s comment by Geir-Tore Lindsve, Stefan Sedich’s Blog post

Converting IP To Numeric

When looking up a Geo IP, you will need to convert the IP address to numeric value.  Below shows the formula for the transformation in both directions.

Given IP address is: w.x.y.z

Numeric:

256^3(w) + 256^2(x) + 256(y) + z

or

16777216(w) + 65536(x) + 256(y) + z

IP:

w = (int)( IP Number / 16777216 ) % 256 
x = (int)( IP Number / 65536 ) % 256 
y = (int)( IP Number / 256 ) % 256 
z = (int)( IP Number ) % 256

Doing this in .NET would yield the following code:

public static uint? IPToNumeric(string address)
{
string[] splits = address.Split('.');
if (splits.Length == 4)
{
try
{
return
16777216 * uint.Parse(splits[0]) +
65536 * uint.Parse(splits[1]) +
256 * uint.Parse(splits[2]) +
uint.Parse(splits[3]);
}
catch { }
}
return null;
}

public static string NumericToIP(uint numeric)
{
try
{
return string.Format("{0}.{1}.{2}.{3}",
(uint)(numeric / 16777216) % 256,
(uint)(numeric / 65536) % 256,
(uint)(numeric / 256) % 256,
numeric % 256);
}
catch { }
return null;
}