Printable Web Page

Ever wonder how to make your unnecessary page elements disappear only to leave a perfectly printable web page?  Using the stylesheet link’s media attribute can do the trick.  Below describes how to utilize this media stylesheet to hide specific elements within your page.  One of the keys to remember is that when your presenting mostly readable text, you want to stick to black and white with possibly red or blue links to let the user know certain text represented hyperlinks.

1.  First thing to do is to define a css file to hold or media printing specific css.  Let’s call it pring.css.

2.  Add the following reference to the head section of your html document.

<link href="/Styles/Print.css" type="text/css" media="print" rel="stylesheet" />

3.  Define the core css classed that drive most of you page.  Below shows the core css classes we will use.  The class “nonprintable” will be applied to any element that should not be shown on the printed page.  Sometimes you will need to force certain css styles so you can use a “printable” class for this purpose.  Applying black and white to the body of the html document is the cleanest way to obtain a slick page.  Notice that “a” links get a red color and a transparent background; this helps the user realize the text was a hyperlink and prevent any a link’s background images from showing up.

/* GENERAL */
.nonprintable
{
display:none;
}

/* apply to specific items that must be forced */
.printable
{
background:white !important;
color:Black !important;
}

body
{
background:white;
color:Black;
}

/* A links */
a:link, a:visited
{
color:Red;
background: transparent;
font-weight: bold;
text-decoration: underline;
}

/* END GENERAL */
 
4.  Add any non-generic css classes.  For example, if you were using the ASP.NET ajax tab controls you’d want to define the following classes to hide tabs.
 
/* 
asp.net ajax tab control
*/
.ajax__tab_header, .ajax__tab_outer, .ajax__tab_inner
{
display:none;
visibility:hidden;
}
.ajax__tab_body
{
border-color:White;
visibility:hidden;
}

5.  Now apply css to elements within your document.  Menu’s, images, ads, and other content that you don’t want to print should get the “nonprintable” class.  This class will be assigned to the element but will not take affect until the user goes to print the page.  Try it by applying some css and doing a print preview.  This is a clever way of verify that the page looks correct without actually printing.

ASP.NET MVC Razor View Engine and Resources

The Razor view engine shipped with ASP.NET MVC 3 is very clean and has some nice coding enhancements, see a introduction on Scott Gu’s blog.  As I was converting a application over to use the new view engine, I was stumped to find that the global/local resource method was not directly accessible as it was with the default view engine.  In order to access a resource you would have to type the following expression ViewContext.HttpContext.GetGlobalResourceObject(classKey, resourceKey) which is quite length.  To mitigate this, I create some common extensions to clean up the code.  Below shows a clean way of doing this.

public static class CommonHtmlExtensions
{
public static object GetGlobalResource(this HtmlHelper htmlHelper, string classKey, string resourceKey)
{
return htmlHelper.ViewContext.HttpContext.GetGlobalResourceObject(classKey, resourceKey);
}

public static object GetGlobalResource(this HtmlHelper htmlHelper, string classKey, string resourceKey, CultureInfo culture)
{
return htmlHelper.ViewContext.HttpContext.GetGlobalResourceObject(classKey, resourceKey, culture);
}

public static object GetLocalResource(this HtmlHelper htmlHelper, string classKey, string resourceKey)
{
return htmlHelper.ViewContext.HttpContext.GetLocalResourceObject(classKey, resourceKey);
}

public static object GetLocalResource(this HtmlHelper htmlHelper, string classKey, string resourceKey, CultureInfo culture)
{
return htmlHelper.ViewContext.HttpContext.GetLocalResourceObject(classKey, resourceKey, culture);
}

}
 
In the view you will have consolidate resource calls.  Hopefully they will add something like this in the future of ASP.NET MVC.
 
@Html.GetGlobalResource("CommonText", "Some_ResourceKey")

TFS 2010 Build and Deploy with Web Deploy

It hasn’t been until recently that I’ve messed around with some of the web application deployment tools Visual Studio and TFS have to offer.  So I started with the one click publish which you can find in Visual Studio when you have your web application highlighted.  It’s really cool that you can deploy to a web server directly from Visual Studio, but what’s even cooler is that you can utilize the same process in a TFS build with little work at all!  Below shows the simple steps to creating a build definition that will deploy your web application.

1.  Install Web Deploy on the IIS server you wish to deploy to. http://go.microsoft.com/?linkid=9684516 for x86 or http://go.microsoft.com/?linkid=9684517 for x64.  This is used to remotely install you web application and configure any IIS settings.  NOTE:  I recently ran into some issues with installing this where it doesn’t install all the necessary components.  If you reinstall it and select Change, you may find that all component where not installed.  If you are running into issues with permissions during web deploy see this thread http://william.jerla.me/post/2010/03/20/Configuring-MSDeploy-in-IIS-7.aspx.

2.  Create a new build definition.  This can be found on the Team Explorer windows, and right clicking the Builds folder.

3.  Set a drop location for the build output.

image

4.  Set the following MSBuild Arguments. These are required for the web deploy build target. These are space separated build parameters. Four of them you must provide information for.  If you don’t provide information about username password, I believe it will use the build agent’s process identity.

/p:DeployOnBuild=True

/p:DeployTarget=MsDeployPublish

/p:MSDeployPublishMethod=RemoteAgent

/p:CreatePackageOnPublish=True

/p:DeployIISAppPath={Site/application}

/p:MsDeployServiceUrl={You IIS Server Running Web Deploy Agent}

/p:UserName={Username}

/p:Password={Password}

{Site/application} – the web sites name of application name under the site. An example of just the site would be “Default Web Sites”, or in the case of a application under a site then “Default Web Sites/MyApp”.

{You IIS Server Running Web Deploy Agent} – the server name of IP address of the IIS server that your deploying to. It will be running the Web Deploy Agent service.  For example, http://MyIISMachine or http://10.210.7.123.

{Username} – a username that has sufficient privileges on the report IIS server copy content and modify IIS metabase.

{Password} – password for the user

image

5.  You might have to place the build agent account in the Adminstrators group on the machine being deployed to.

6.  Save you build definition.  Now queue it and watch it run.

See also my post on Configure Click-Once Publisher in Visual Studio.

Configure Click-Once Publisher in Visual Studio

Click once publishing makes it easy to deploy web applications right within Visual Studio.  Some hosting providers, like Discount ASP.NET, support click once publishing.  If you are using a hosting provider, check with them for the required information as they will provide you with the correct credentials and service url.

1.  Highlight your web application that you are deploying. Right click it and select Publish.

image

2.  The Publish Web dialog should appear. Set the following items:

· Publish Method = Web Deploy – this tells it to use the web deploy agent that will be running on our remote IIS server.

· Service Url – set this to the server name/IP of the machine that you are deploying to, which also has the web deploy agent running on it. If you are deploying to a hosting provider and they support this, check with them for this configuration.

· Site/application – set this to the site name and/or site/application name. If you don’t have applications under your site then this can just be the site name, like “Default Web Site”.

· Username and Password – set the credentials with sufficient privileges to the deployment operations, this user will need to be able to edit the IIS metabase. If you are using a hosting provider, they will provide this information for you.

image

3.  Click Publish, and that’s it.

Web.Config Issues Deploying .NET 4.0 MVC2 Site To IIS7

In .NET 4.0 they cleaned up a lot of the configuration elements for a web site’s web.config and moved it the the frameworks machine.config.  This has greatly streamlined the web.config.  The other day I was deploying a MVC2 site running under .NET 4.0 to an IIS7 web server and received a configuration error stating “There is a duplicate 'system.web.extensions/scripting/scriptResourceHandler' section defined”.  It turns out that MVC2 project template comes with come web.config settings which work under .NET 2/3.5, but are redundant in 4.0.  In order to fix this, remove the following settings, the type attributes have been removed for brevity.

<sectionGroup name="system.web.extensions" ...>
<sectionGroup name="scripting" ...>
<section name="scriptResourceHandler" .../>
<sectionGroup name="webServices" ...>
<section name="jsonSerialization" .../>
<section name="profileService" .../>
<section name="authenticationService" .../>
<section name="roleService" .../>
</sectionGroup>
</sectionGroup>
</sectionGroup>

See ASP.NET 4 Breaking Changes for details on breaking changes in .NET 4.0.

Find jQuery Autocomplete Input ID

The other day I was working with jQuery autocomplete where the autocomplete was being applied to a collection of input elements.  One of the issues I was running into was that I needed a reference to the input that the automplete was extending during the execution of the select event.  The way to do this is to store a reference to the input inside the function executing the select event, in essence create a closer.  Below shows how this done, the call to $(this) resolves to the input that is being autocompleted.

$(".all-my-autos")
.autocomplete({
source: "auto-me.php",
minLength: 2,
delay: 500,
select: function (event, ui) {
var input = $(this); // reference to input
// do what you need with input...
alert(input.attr('id'));
}
});

Visual Studio 2010 Javascript Outlining Plugin

The other day my colleague Ben Martin, a somewhat developer tool aficionado, sent me this great JavaScript enhancement plugin for Visual Studio.  I’d have to say, it is one enhancement I’m surprised was not already in Visual Studio.  The plugin adds outlining and minimizing/maximizing code blocks, the same that you would get in a C# code file.  It is a much needed enhancement and a must for anyone who is doing JavaScript coding.  I think the only thing I noticed that would be nice to have in it would be the Ctrl+M+O hotkey which minimizes all code blocks.  You can download the enhancement here.

Getting Started With Eclipse And Team Explorer Everywhere

In a previous post, Install Team Explorer Everywhere 2010, I covered the installation of TEE, so now I’m going to cover connecting to a TFS team project collection. 

1.  To get started open the Team Foundation Server Exploring (TFS Explorer for short) perspective, this can be found in Window ^ Open Perspective ^ Other…clip_image002

Now your current windows should look like the screen shown below.  The icon used to add a TFS server connection is circled in red, which will be used in the next step.  If you’ve used TFS with Visual Studio, you’ll notice that the layout is nearly identical to what it is in Visual Studio.

clip_image002[7]

2.  To add the TFS server, click on the icon that is circled in the previous image. The “Add Existing Team Project” dialog will appear. This is where you add your TFS server (see image below). The advanced tab allows you to port settings, for example if you’re using SSL. Enter in the correct server URL, the default would be http://{server}:8080/tfs. Click Next.

clip_image002[9]

3.  Continuing from the server setup, you should be on the Team Project selection page. On the left pane is the team project collections list. Prior to TFS 2010, there could only be one project collection. On the right pane are the team projects within the collection. Select the team projects that you want view. Click Next.

clip_image002[11]

4.  Once it finishes querying TFS, the last window will appear showing any workspaces you have. Here I have one because I already created a workspace through Visual Studio. Select your workspace and click “Finish” if you have one else continue with this step to create one.

clip_image002[13].

If you don’t have a workspace defined, you can create one by using the “Add…” button. You will see the workspace dialog appear as shown below. By default the workspace name will be your machine name. In the working folder you must map a source folder to a local folder. In the Status column select Active from the options. In the Source Control Folder option, click the browse “…” icon to bring up the TFS source “Browse for Folder” dialog. Select the source path you want and click Ok. Now in the Local Folder column, select the browse “…” icon to pick local file path where you want the source to copy down to. Once done you can click Ok to finish creating workspace.

clip_image002[15]

5.  Now the Team Explorer should be filled in and some more sub-windows should appear (see image below). With a team project expanded double click the “Source Control” item, see red circled item. This will display the Source Control window. Below highlights the 3 main windows that I use on a regular basis.

    • Team Explorer: Contains a list of team project collections, and under each collection is a list of team projects. Items will show up based on what you have selected in your workspace.
    • Source Control: Shows a folder tree display of all available branches to you. Navigating these you will be able to see whatever you have checked in to these branches.
    • Pending Changes: This shows a list of any pending changes that you have checked out. You can also check the items in from this pain as well, shelve/unshelve, associated check-in with work items, etc.

clip_image002[17]

 

And that’s it, you are now ready to check in/out your project files to TFS and take advantage of the integrated features of TFS such as bug tracking and shelvingShelving is a neat feature of TFS that allows you place your code on a virtual “book shelf” with some name so at some later date you can retrieve this named “book” of code from the shelf.  This is very useful if your working on a large feature and you have files checked out for more than a day.  At the end of the day you can shelve the code, which stores your changes on the server.  If your machines dies for some odd reason, all your hard work is not lost.  You can also share you shelved items with other team members.  For details of shelving see, Walkthrough: Shelving Version Control Items.

Running Database Project Deploy Script In SQL Management Studio

Visual Studio Database Projects is a great way to manage and maintain your SQL server database schema.  The projects offer compile time checking just like any other code type project would.  When you build build the project you have the options of either creating a deployment script or a script plus deploy it to a given database instance.  If you create the script, there is one caveat that I find myself forgetting the first time I run it via SQL Management Studio, setting the SQL command mode.  This is necessary to resolve the lines that start with “:”, such as “:setvar”.  To enable the script to run successfully, open the menu Tools ^ Options.  Click the “Query Execution” in the list.  Check the “By default, open new queries in SQLCMD mode”.  Open a new query window and run your script.

temp

Executing Stored Procedure With NHibernate

There are two reasons why you might want to execute a stored procedure using NHibernate.  The first would be for your normal CRUD activities which can be found here, Populating Entities From Stored Procedures With NHibernate.  I’d like to focus on the other scenario you might find yourself needing to execute a procedure, like running a complex report or some query that is better performed in a procedure.  The real benefit of NHibernate is that you’re not coding to an implementation but to a set of interfaces.  This buys you the blissful ignorance of the underlying database vendor, see also my post on NHibernate And Paging Results.

Executing a procedure requires two main items, a connection and a command object.  The connection comes from the session, and the command comes from the connection’s method CreateCommand.  Below shows a very straightforward way of executing a procedure.  Notice that the connection and command objects are just interfaces from System.Data namespace.

List<SomeDto> list = new List<SomeDto>();

using (ISession session = NHSessionManager.OpenSession())
{
// use the ISession to get the database connection
IDbConnection conn = session.Connection;

// use the connection object to get the database command object
IDbCommand cmd = conn.CreateCommand();

// set the command text to the procedure's name and set the command type
cmd.CommandText = "dbo.MyAwesomeProcdure";
cmd.CommandType = CommandType.StoredProcedure;

// using the command object you can create a parameter, setting it's properties accordingly
IDbDataParameter p;
p = cmd.CreateParameter();
p.DbType = DbType.Int32;
p.ParameterName = "@someParam";
p.Value = someParamValue;
cmd.Parameters.Add(p);

// data read to capture results
IDataReader reader = null;
try
{
reader = cmd.ExecuteReader(CommandBehavior.SingleResult);
while (reader.Read())
list.Add(new SomeDto
{
Name = reader.GetString(0),
Age = reader.GetInt32(1),
...
});
}
finally
{
if (reader != null)
reader.Close();
}
}

return list;

Install Team Explorer Everywhere 2010 For Eclipse

Typically shops using Eclipse will probably be using SVN or some other source control system, but there are cases where you shop may be a mix of coding languages.  Team Foundation Server is a good offering for source control and much more, such as bug tracking, project management, etc.  If you are in such a shop, Teamprise, which is now owned by Microsoft, wrote a plugin for Eclipse that will connect to Team Foundation Server.  I will describe how to install this plugin for Eclipse in the below steps.  I’m basing my example off the Ganymede installation of Eclipse.

1.  Download TFSEclipsePlugin-UpdateSiteArchive-10.0.0.zip.  Unpack zip file into C:\Tools. You should have C:\Tools\TFSEclipsePlugin-UpdateSiteArchive-10.0.0.

2.  In Eclipse, open the menu Help ^ Software Updates… On other flavors of Eclipse this maybe Help ^ Install New Software.

3.  In the Available Software tab, click the button “Add Site…”. In the “Add Site” dialog, click the “Local…” button, which will bring up a folder dialog. See the screen below. Select the folder C:\Tools\TFSEclipsePlugin-UpdateSiteArchive-10.0.0 which is what was unpacked earlier. Click Ok in folder dialog, then click Ok in “Add Site” dialog.

clip_image002[4]

4.   Now you should see the plugin available in your “Available Software”. Check the Visual Studio Team Explorer Everywhere 2010 checkbox and click the “Install…” button. It will chug through some requirements calculations for a second or two.

clip_image002[6]

5.  After it’s done checking dependencies, an Install dialog will appear as shown below. Click Next button, accept the license agreement, and then click Finish button. After it’s done it will suggest that you restart eclipse, so do that now.

clip_image002[8]

 

In upcoming blogs I will be talking about the usage of this plugin with respect to TFS.

SSRS Will Not Let You Upload RDLs of Certain Sizes

Not sure exactly how we ran into this, but for some reason one of our 2008 Reporting Services servers would only allow us to upload RDLs that were less than ~105k.  Couldn’t find much online so we ended up calling Microsoft to figure out what the deal was.  Turns out here is a registry key that needs to be in place to remedy this situation.

Location: \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP\Parameters

Add a REG_DWORD with the name MaxRequestBytes and a hex value of 500000.  You will be able to upload larger RDLs now.

VS2010 And SSRS Report Viewer Hanging

The other day I needed to integrated Reporting Services reports with a web application.  I knew I wanted to use the ReportViewer control, but I ran into a few issues of which I’ll state here.  Briefly, one issue is that the web application was already an ASP.NET MVC application, so I wanted to see if I could get the control to work with a view.  I tried to wrap the control in a <form runat=server>, because it needs viewstate, etc  Some ASP.NET controls will work just fine in MVC, no biggy, but this one is a no go.  So I was left with using webforms, not the ideal, but that’s what I had to work with.  So the big issue I ran into was that the ReportViewer control would hang and never load a report.  It turns out that they made some fixes to the async rendering behavior.  To avoid having the report hang you need to set report properties on the initial page post only, as shown below.

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
rptViewer.ServerReport.ReportPath = "/MyReportFolder/My Report";
rptViewer.ServerReport.ReportServerUrl = new Uri("http://SomeRptServerName/ReportServer/");
}
}

Using VS2008 VS2005 with TFS 2010 Compatibility

The other day I was trying to setup a TFS 2010 server to demo it’s usage.  Since most of the developers using are VS2010, I didn’t have any issues showing them how to connect. But when it came to some designers that needed BIDS (VS2008) for creating reports for Reporting Services, I ran into some bizarre issues.  One of the main issues is that TFS 2010 uses project collections, which is new, and older clients need some backwards compatibility fixes.

Problem: Older versions of Visual Studio will not connect to TFS 2010.  You might get authentication or server unavailable errors.

Solution:  Install the backwards compatibility patches for you version of Visual Studio.  Below shows the steps to take to get your version of VS connected

1.  Install Visual Studio service pack:

VS2008 SP1: http://www.microsoft.com/downloads/details.aspx?FamilyId=FBEE1648-7106-44A7-9649-6D9F6D58056E&displaylang=en

VS2005 SP1: http://www.microsoft.com/downloads/details.aspx?FamilyId=BB4A75AB-E2D4-4C96-B39D-37BAF6B5B1DC&displaylang=en

2.  Install Team Explorer if you need it:

VS2008: http://www.microsoft.com/downloadS/details.aspx?familyid=0ED12659-3D41-4420-BBB0-A46E51BFCA86&displaylang=en

VS2005: http://www.microsoft.com/downloads/details.aspx?FamilyID=46473C2A-BB85-4461-BB27-4792A5DEF222&amp;displaylang=ja&displaylang=en

3.  Install VS forward compatibility for TFS:

VS2008: http://www.microsoft.com/downloads/details.aspx?FamilyID=cf13ea45-d17b-4edc-8e6c-6c5b208ec54d&displaylang=en

VS2005: http://www.microsoft.com/downloads/details.aspx?FamilyID=22215e4c-af6f-4e2f-96df-20e94d762689&displaylang=en

4.  Since TFS 2010 has introduced the concept of project collections connecting to TFS by adding a server to the Team Explorer will not work like it used to.  You have to modify the registry and insert the connection to the server with this type of format:  http://{TFS Server}:8080/tfs/{CollectionName} (some of the default here are port and tfs server root folder name).  The reason you can just add this as a new server is that the server path does not allow the “/” character.

VS2008: Enter a new string value at this key location “HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\TeamFoundation\Servers”.  The key name can be the name of you tfs project collection if you want.  The key I added for my project demo was http://d01teamweb/tfs/DefaultCollection with a key name DefaultCollection.

VS2005: Enter a new string value at this key location “HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\8.0\TeamFoundation\Servers”.  The key name can be the name of you tfs project collection if you want.  The key I added for my project demo was http://d01teamweb/tfs/DefaultCollection with a key name DefaultCollection.

You’ll need to reopen any existing VS instances that need to pick up this information.  Once you open VS and go to the Team Explorer window, you should see the project collection you added to the registry.  Since 2005/2008 don’t handle project collection, they can only work with one at a time.

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