Tuesday, December 29, 2009

Quick Hack to Restrict Countries in DotNetNuke's Address Control

Today, I needed to restrict the countries that were listed in DotNetNuke's Address control for a custom module I was writing. I only wanted to display the North American countries of Canada, Mexico and United States. After surfing the net for 5 minutes, nothing was rising to the top as a solution so I hacked my own solution out.

Assuming you have a web control with the following declaration,
...
<%@ Register TagPrefix="dnn"
TagName="Address"
Src="~/Controls/Address.ascx" %>
...
<dnn:Address id="addressControl" runat="server" />
...

you can restrict the countries in the code-behind like so:

using System.Linq;
...
private static readonly string[] Countries
= new[] { "Canada", "Mexico", "United States" };
...
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);

var list = this.addressControl.FindControl("cboCountry")
as CountryListBox;
foreach (var item in list.Items.Cast<ListItem>().ToArray())
{
if (!Countries.Contains(item.Text))
list.Items.Remove(item);
}
}


Enjoy!

Tuesday, December 8, 2009

Global.asax Session_End NullReferenceException

I had an issue pop up on an ASP.NET web app this morning consisting primarily of NullReferenceExceptions being thrown when Global.asax runs some cleanup code from its Session_End handler. Basically, the cleanup code is disposing some IDisposable items stored in session state before the session blinks out of existence. The manner in which the session was being accessed was the following:

System.Web.HttpContext.Current.Session[...

This throws a NullReferenceException since HttpContext.Current is null. Null? Why is the context null? It didn't seem logical at first, but after a minute of thought, it came to me. Of course there's no context, the session expires on a timeout. Although, the lifecycle of a session begins with a request, it doesn't end with one. Thus, when a session times out there is no request or response available, and thus no context.

Well, how do I access the session then?

Easy. Global.asax has a Session property. It is not null at this point, and this allows you to work with the session before the session is garbage collected. I had to change my cleanup code interface, but I the resolution consisted of Global.asax passing the session to the cleanup code rather than having the cleanup code acquire it itself through the current HttpContext.

protected void Session_End(object sender, EventArgs e)
{
// HttpContext.Current.Session throws a
// NullReferenceException since no HttpContext
// exists when a session expires, thus the client
// code can't access the HttpSessionState object this
// way and needs it to be passed directly from
// Global.asax (i.e. this.Session)

this.Controller.Cleanup(this.Session);
}