Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

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);
}

Monday, August 31, 2009

Simple MVP in ASP.NET

Model View Presenter (MVP)

The model:

public interface IEntity
{
SomeType SomeProperty1 { get; set;}
SomeOtherType SomeProperty2 { get; set;}
YetAnotherType SomeProperty3 { get; set;}
}



The interface (the view contract - insulates the presenter from the implementation):

public interface IEntityView
{
event EventHandler Init;
event EventHandler Load;
event EventHandler Unload;
IEntity Entity { get; set; }
bool Visible { get; }
}


The code behind (the view implementation):

public partial class EntityDisplayPage : Page, IEntityView
{
protected EntityDisplayPage()
: base()
{
new EntityPresenter(this); // wire the MVP pattern
}

#region IEntityView Members

public IEntity Entity { get; set; }

#endregion
}


The presenter (doesn't know the view implementation, manipulates it through the view contract defined as an interface):

public class EntityPresenter
{
public EntityPresenter(IEntityView view)
: base()
{
if (null == view)
throw new ArgumentNullException("view");
this.view = view;

this.View.Init += (sender, e) => { /* some business logic on init */ };
this.View.Load += (sender, e) =>
{
/* some business logic on load*/
this.View.Entity = GetEntityToDisplay();
};
this.View.Unload += (sender, e) => { /* some business logic on unload*/ };
}

private readonly IEntityView view;
public IEntityView View
{
get { return view; }
}
}


And that's how you get good separation through a simple MVP implementation in ASP.NET. I think it speaks for itself.

Wednesday, September 17, 2008

MSMQ Transactional Message Processing using Multiple Receive Queues

Here's the situation:
  1. You want to asynchronously process messages on a queue in a transactional manner, such that the message is only taken from the queue upon successfully processing it. This allows messages that failed to be properly processed to be processed again later with a chance at success.
  2. You want to have multiple workers processing these messages to improve efficiency and performance of long-running processing on large numbers of messages.
  3. When you shutdown, you want all the processing code to complete before allowing the process to exit.
The first item can be accomplished with using MessageQueue's BeginPeek method and PeekCompleted event. This will allow you to peek at the queue and and begin a transaction before actually receiving the message. Beginning a transaction before receiving the message allows you to abort the transaction should an error occur during processing, leaving the message on the queue to be processed again later (hopefully with a higher chance of success). The following event handler shows the boilerplate code to accomplish this:

private void queue_PeekCompleted(object sender, PeekCompletedEventArgs e)
{
var queue = (MessageQueue)sender;

var transaction = new MessageQueueTransaction();
transaction.Begin();
try
{
var message = queue.Receive(transaction);
// process the message here
transaction.Commit();
}
catch (Exception ex)
{
// abort if processing fails
transaction.Abort();
}
finally
{
// start watching for another message
queue.BeginPeek();
}
}

The second item can be accomplished by creating multiple receiving queues and telling them to start watching for incoming messages. The following snippets of code demonstrate how to accomplish this:

private readonly MessageQueue[] Receivers; // member
...
this.Receivers = Enumerable.Range(0, (count <= 0) ? 1 : count)
.Select(i =>
{
var queue = new MessageQueue(path, QueueAccessMode.Receive)
{
Formatter = new BinaryMessageFormatter()
};
queue.MessageReadPropertyFilter.SetAll();
return queue;
})
.ToArray();

// begin watching
foreach (var queue in this.Receivers)
{
queue.PeekCompleted += queue_PeekCompleted;
queue.BeginPeek();
}

...
// closing
foreach (var queue in this.Receivers)
{
queue.PeekCompleted -= queue_PeekCompleted;
queue.Close(); // stop peeking
}

The third item can be accomplished by simply incrementing and decrementing a counter when processing begins and ends respectively; then you simply block until that counter reaches zero. You'll want to place the decrement in a finally block to ensure that the counter is decremented even if processing throws an exception. Assuming you have a Counter class that implements thread safe increment and decrement operations (see bottom), you can create a member named "ProcessingCounter", and your PeekCompleted handler has the following line to do the processing,
this.Handle(queue.Receive(transaction));

your Handle method would look like this,

private void Handle(Message message)
{
this.ProcessingCounter.Increment();
try
{
// process message here;
}
finally
{
this.ProcessingCounter.Decrement();
}
}

and you could block after your MessageQueue.Close() calls like this

while (this.ProcessingCounter.Value > 0)
Thread.Sleep(100);

The following abstract class puts it all together. Simply implement the Process method and away you go!

public abstract class MessageProcessor<TMessage>
{
private readonly MessageQueue[] Receivers;
private readonly Counter ProcessingCounter = new Counter();
private bool IsClosing;

public MessageProcessor(string path)
: this(path, 1) { }

public MessageProcessor(string path, int count)
: base()
{
if (string.IsNullOrEmpty(path))
throw new ArgumentNullException("path");

if (!MessageQueue.Exists(path))
MessageQueue.Create(path, true);

this.Receivers = Enumerable.Range(0, (count <= 0) ? 1 : count)
.Select(i =>
{
var queue = new MessageQueue(path, QueueAccessMode.Receive)
{
Formatter = new BinaryMessageFormatter()
};
queue.MessageReadPropertyFilter.SetAll();
return queue;
})
.ToArray();
}

public void Close()
{
this.IsClosing = true;

this.OnClosing();

foreach (var queue in this.Receivers)
{
queue.PeekCompleted -= queue_PeekCompleted;
queue.Close();
}

while (this.IsProcessing)
Thread.Sleep(100);

this.IsClosing = this.IsOpen = false;
this.OnClosed();
}

public bool IsOpen { get; private set; }

protected bool IsProcessing
{
get { return this.ProcessingCounter.Value > 0; }
}

protected virtual void OnClosing() { }
protected virtual void OnClosed() { }
protected virtual void OnOpening() { }
protected virtual void OnOpened() { }

public void Open()
{
if (this.IsOpen)
throw new Exception("This processor is already open.");

this.OnOpening();

foreach (var queue in this.Receivers)
{
queue.PeekCompleted += queue_PeekCompleted;
queue.BeginPeek();
}

this.IsOpen = true;
this.OnOpened();
}

protected abstract void Process(TMessage @object);

private void Handle(Message message)
{
Trace.Assert(null != message);

this.ProcessingCounter.Increment();
try
{
this.Process((TMessage)message.Body);
}
finally
{
this.ProcessingCounter.Decrement();
}
}

private void queue_PeekCompleted(object sender, PeekCompletedEventArgs e)
{
var queue = (MessageQueue)sender;

var transaction = new MessageQueueTransaction();
transaction.Begin();
try
{
// if the queue closes after the transaction begins,
// but before the call to Receive, then an exception
// will be thrown and the transaction will be aborted
// leaving the message to be processed next time
this.Handle(queue.Receive(transaction));
transaction.Commit();
}
catch (Exception ex)
{
transaction.Abort();
Trace.WriteLine(ex.Message);
}
finally
{
if (!this.IsClosing)
queue.BeginPeek();
}
}
}

Incidentally, the following is my implementation of a thread-safe counter.

public class Counter
{
private readonly object SyncRoot = new object();
private int value;

public int Value
{
get
{
lock (this.SyncRoot)
{
return value;
}
}
}

public int Decrement()
{
lock (this.SyncRoot)
{
return --value;
}
}

public int Increment()
{
lock (this.SyncRoot)
{
return ++value;
}
}
}