Mar 2

The problem

We try to strongly type everything in our MVC project, especially URLs. It’s pretty easy to do using all the build in functionality of ASP.NET MVC along with some lovin’ from MvcContrib, but the one situation we’ve always had problems with was client-side javascript. If it’s a basic action call with no arguments, we’re golden (using <%= Html.BuildUrlFromExpression(x => x.MyAction()) %>). It gets tricky when we have a slightly more complex action though:

[AcceptAjax]
public string DoSomethingComplex(int id, string accountNumber, int amount)
{
	return string.Format("id = {0}, accountNumber = {1}, amount = {2}", id, accountNumber, amount);
}

If we wanted to do an AJAX call to this bad boy, we’d unfortunately have to resort to string concatenation to build up the URL:

// get these values from form fields or something...
var id = 3;
var accountNumber = "123456";
var amount = 325;
 
var ugly_url = "/Home/DoSomethingComplex/" + id + "?accountNumber=" + accountNumber + "&amount=" + amount;

Booo creepy magic strings. Renaming the action name or any of the parameter names left us relying on either ReSharper’s ability to catch the change, manual search and replace, or hoping we had a UI test hitting the page to catch it. Basically, nothing too terribly reliable to keep our app in working order. The more you worry about small changes breaking your application, the less likely you are to refactor it. The less you refactor, the faster your application degrades into nastiness (code not matching up with current business conventions, etc), and the slower you are to respond to change. Not cool.

The solution

Before I go further, I should probably throw up this disclaimer: We use the default routes for everything. The application is behind a login page, and we have no need for fancy SEO friendly URLs, so the solution I’m about to show caters to that scenario. If your application leverages custom routes, you’ll either have to tweak this solution to your needs, or figure out something else. Sorry.

In a nutshell

You’ll end up being able to build the URL above like this:

var beautiful_url = "<%= Html.UrlTemplate<HomeController>(x => x.DoSomethingComplex(Any<int>.Arg, Any<string>.Arg, Any<int>.Arg)) %>"
						.substitute(id, accountNumber, amount);

This’ll produce a URL template like "/Home/DoSomethingComplex/{0}?accountNumber={1}&amount={2}" on the client. You then plug in the template’s holes with your client-side values. Pretty simple, really.

There’s a few server and client-side pieces to this puzzle.

Server-side portion

The heart of this solution (and the biggest chuck of code) is the actual building of the URL template.

private static bool onlyTakesInSingleViewModel(string[] routeValues)
{
	return (routeValues.Length == 3 && routeValues[2].ToLower().EndsWith("viewmodel"));
}
 
public static string UrlTemplateFor<CONTROLLER>(Expression<Action<CONTROLLER>> action) where CONTROLLER : Controller
{
	var routeValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action);
	var actionPath = string.Format("/{0}/{1}", routeValues["Controller"], routeValues["Action"]);
 
	if (routeValues.Count > 2)
	{
		var routeValuesKeysArray = routeValues.Keys.ToArray();
 
		if (onlyTakesInSingleViewModel(routeValuesKeysArray))
		{
			return actionPath;
		}
 
		if (routeValuesKeysArray[2] == "id")
		{
			actionPath += "/{0}";
		}
		else
		{
			actionPath += "?" + routeValuesKeysArray[2] + "={0}&";
		}
 
		var placeHolderCounter = 1;
 
		if (routeValues.Count > 3)
		{
			if (actionPath.Contains("?") == false)
			{
				actionPath += "?";
			}
 
			for (var i = 3; i < routeValues.Count; i++)
			{
				actionPath += routeValuesKeysArray[i] + "={" + placeHolderCounter++ + "}&";
			}
		}
 
		actionPath = actionPath.TrimEnd('&');
	}
 
	return actionPath;
}

This method (which has unit tests in the sample project provided at the end of the post) basically builds up the URL template by leaning on a method inside the MVC Futures assembly to get the controller, action, and parameter names. This is the portion you’d have to tweak if you use different routing rules.

Then it’s simply a matter of wrapping the UrlBuilder call with an HTML Helper extension method:

public static class HtmlHelperExtensions
{
	public static string UrlTemplate<CONTROLLER>(this HtmlHelper htmlHelper, Expression<Action<CONTROLLER>> action) where CONTROLLER : Controller
	{
		return UrlBuilder.UrlTemplateFor(action);
	}
}

Looking at the example of using this method above, you can see all the parameters in the UrlTemplate call replaced with calls to an Any class. Technically speaking, whatever values you put in the expression passed to UrlTemplate will be ignored. You can put in nulls for references & nullable types, 0’s for value types, etc. I decided to drive home the point to anyone looking at the code that we don’t care what value they provide by making a very slim class that provides the default value for whatever type is needed:

public class Any<T>
{
	public static T Arg
	{
		get { return default(T); }
	}
}

It drives home that whole not caring point pretty well, but it’s also a bit wordy, especially if there’s 3 or 4 parameters that need specified. You can omit using the Any class and just give dummy values if you want. Your choice.

Client-side portion

There’s not a whole lot to the client-side portion. Basically a very simple version of the .NET Framework’s string.Format method (which you’ll probably want to put in an external js file and reference as needed). It’s written as an extension on the string type to make reading the final product a bit more natural:

String.prototype.replaceAll = function (patternToFind, replacementString) {
	return this.replace(new RegExp(patternToFind, "gi"), replacementString);
}
 
String.prototype.substitute = function () {
	var formatted = this;
 
	for(var i = 0; i < arguments.length; i++) {
		formatted = formatted.replaceAll("\\{" + i + "\\}", arguments[i]);
	}
 
	return formatted;
}

That’s it. Using all these pieces together gives us the final product:

var beautiful_url = "<%= Html.UrlTemplate<HomeController>(x => x.DoSomethingComplex(Any<int>.Arg, Any<string>.Arg, Any<int>.Arg)) %>"
						.substitute(id, accountNumber, amount);

You can provide the values for the URL template from client-side code, or from your ViewModel by just outputting the value in the proper spot (i.e. use <%= Model.Id %> rather than the client-side id property). This setup has proven very helpful and quite versatile for us so far.

Potential pitfalls

Having shown all this, there are a few potential pitfalls you need to be aware of:

  1. The building of the URL template is pretty rudimentary. It also relies on a method inside the MVC Futures assembly, which I haven’t checked to see if it even exists in MVC3, let alone in future versions. I couldn’t find anything in the main MVC assembly or MvcContrib to fill my needs. Having said that, it’s isolated to one location and we could always get the controller, action, and parameter names by hand with a little expression tree walking, especially since we’re already limited to the default route setup and therefore know where they’d be with pretty good certainty.
  2. This allows you to rename controller, action, and parameter names with complete confidence. However, if you switch parameter positions around, especially if they’re the same type, you might run into a problem. In my usage example above, for instance, switching the id and amount parameters around would still compile and technically run, but the Javascript would continue passing the id in for the amount parameter and vise-versa. You don’t usually switch around parameters for no reason, but it’s worth noting, as you’d have to do a find usages and make sure all the calls are updated properly. At least you’d be able to find all the usages with certainty, though.

Conclusion

Next time you find yourself needing to concatenate strings on the client-side to call URLs, think about using this technique (or something similar) to keep it all strongly typed. If you’re going to work in a static language like C#, you might as well leverage it as much as possible. Strong typing lets you refactor with full confidence that no references to the rename will get left behind by mistake.

You can grab a copy of the source code for the project right here (built with MVC2). Give it a spin and let me know if you have any problems, or if you know a better way to do this without building the URLs by hand.

Jan 28
In-memory view rendering with Spark
icon1 Darrell Mozingo | icon2 ASP.NET MVC | icon4 January 28th, 2010| icon32 Comments »

We recently had a requirement to start printing some documents from our web application. These documents required some very precise positioning of a few elements that can’t be achieved with standard web browser printing capabilities. After weighing our options, we decided to go the generated PDF route. There’s quite a few HTML -> PDF generation options out there, but they almost all require you to either point them at an HTML document on disk or feed them a string of your HTML. Options, options, options. Yea, I think we’ll take the string route, thanks.

Turns out (surprise surprise!) that getting your rendered HTML from the Web Forms view engine that’s used by default in ASP.NET MVC isn’t so, um, easy. It likes its HttpContext with a side of HttpSession, and that’s just the appetizer. Kind of hard to get that to it in-memory without firing up a whole other server instance. Thankfully, it turns out our good friend Spark makes rendering a view to an HTML string in-memory incredibly easy.

How? Glad you asked:

public static string RenderViewToHtml<VIEW_MODEL>(string viewPathAndName, VIEW_MODEL viewModel) where VIEW_MODEL : class
{
	var templatesLocation = new FileSystemViewFolder(HttpContext.Current.Server.MapPath("~/Views"));
	var viewEngine = new SparkViewEngine(BuildSparkSettings()) { ViewFolder = templatesLocation };
	var descriptor = new SparkViewDescriptor().AddTemplate(viewPathAndName);
 
	var view = (SparkView<VIEW_MODEL>)viewEngine.CreateInstance(descriptor);
	view.ViewData = new ViewDataDictionary<VIEW_MODEL>(viewModel);
 
	string html;
 
	using (var writer = new StringWriter())
	{
		view.RenderView(writer);
		html = writer.ToString();
	}
 
	return html;
}
 
public static SparkSettings BuildSparkSettings()
{
	return new SparkSettings()
		.AddNamespace("System.Linq")
		.AddNamespace("System.Web.Mvc")
		.AddNamespace("Microsoft.Web.Mvc")
		.SetPageBaseType(typeof(SparkView))
		.SetDebug(false);
}

Simply pass in a path to your view (minus the /View part) along with a view model and you’ll get back a string full of rendered HTML goodness. The BuildSparkSettings() method can shared with the application startup code where you create and add Spark as an ASP.NET MVC view engine. Here’s a sample call:

It’s worth noting that Spark and WebForms views can happily live side-by-side in a single project, too. We use this for only a hand full of pages and the rest are still using the WebForms view engine. Plus, converting them to Spark was as simple as renaming the file and adding a view model declaration at the top of the page (along the lines of <viewdata model="OurNeatViewModel" />). Granted these pages aren’t really leveraging the power and beauty of Spark, but they still run and with virtually no modifications.

Will we be converting all of our views to Spark and using some of it’s neat-o features and conventions? Probably not any time soon. While lots of folks are apparently feeling lots of pain with Web Forms views, we’re not (well, other than this whole in-memory rendered affair anyway). So there really isn’t much gain for us from switching over. I also really don’t like the non-strongly-typedness of their views, which already bit me a few times just on the hand full of views we’re using it for. Perhaps that might get fixed or ReSharper will step up with support for it.

Spark does have a lot of neat features though. It’s ability to easily render a full view to an HTML string in-memory was just the first thing we needed from it. I’m sure there’ll be more in the future.

Jun 20

Part 1 discussed the benefits of a strongly typed view and part 2 went through the typical usage of the Mvc Contrib project’s fluent HTML library. Now we’ll take a look at a neater usage for it – validation.

Each extension in the Mvc Contrib fluent HTML library takes “behaviors” into account, applying all known behaviors first when rendering themselves to strings. These behaviors are defined by the following interface:

public interface IMemberBehavior : IBehaviorMarker
{
	void Execute(IMemberElement element);
}

Very simple. The interface defines a single method that takes in an IMemberElement, which provides the LINQ expression being used to render the control and also inherits from the IElement interface, which is the base interface all the HTML extensions end up deriving from:

public interface IElement
{
	/// <summary>
	/// TagBuilder object used to generate HTML.
	/// </summary>
	TagBuilder Builder { get; }
 
	/// <summary>
	/// How the tag should be closed.
	/// </summary>
	TagRenderMode TagRenderMode { get; }
 
	/// <summary>
	/// Set the value of the specified attribute.
	/// </summary>
	/// <param name="name">The name of the attribute.</param>
	/// <param name="value">The value of the attribute.</param>
	void SetAttr(string name, object value);
 
	/// <summary>
	/// Set the value of the specified attribute.
	/// </summary>
	/// <param name="name">The name of the attribute.</param>
	string GetAttr(string name);
 
	/// <summary>
	/// Remove an attribute.
	/// </summary>
	/// <param name="name">The name of the attribute to remove.</param>
	void RemoveAttr(string name);
 
	/// <summary>
	/// The text for the label rendered before the element.
	/// </summary>
	string LabelBeforeText { get; set; }
 
	/// <summary>
	/// The text for the label rendered after the element.
	/// </summary>
	string LabelAfterText { get; set; }
 
	/// <summary>
	/// The class for labels rendered before or after the element.
	/// </summary>
	string LabelClass { get; set; }
}

This allows a behavior to do basic modifications to an element, including changing HTML attributes and adding text before/after the element. More advanced operations can be done by breaking polymorphism and checking what type the IElement parameter actually is. Mvc Contrib bundles in one behavior by default, the ValidationBehavior, which checks ASP.NET MVC’s ModelState for any possible errors to display, effectively making the Mvc Contrib’s HTML helpers act the same as the built in ASP.NET MVC’s when it comes to error handling.

You’ll notice above I said each HTML extension takes all “known” behaviors into account when rendering themselves to strings. So how do the extensions learn about these behaviors? Simply put, the ModelViewPage we had our view page inherit from takes an array of them in one of its constructor overloads. The default constructor only loads the ValidationBehavior. All we need to do is create our own view base page, inherit from the ModelViewPage, and pass in our own behaviors like so:

public class FluentViewPage<T> : ModelViewPage<T> where T : class
{
	public FluentViewPage()
		: base(new MaxLengthBehavior())
	{
	}
}

There’s really not much to the above behavior, either. Simply have it inherit from IMemberBehavior and you’re good to go. Here it is in all its entirety:

public class MaxLengthBehavior : IMemberBehavior
{
	public void Execute(IMemberElement element)
	{
		var attribute = new MemberBehaviorHelper<StringLengthAttribute>().GetAttribute(element);
 
		if(attribute != null && element is ISupportsMaxLength)
		{
			element.SetAttr(HtmlAttribute.MaxLength, attribute.MaximumLength);
		}
	}
}

The passed in member element knows the property specified in the this.TextBox(x => x.Name) call (Name, in this case), as well as all the elements defined on the IElement interface above. We take that and use a helper class to pull the desired attribute off the passed in property. If it has the attribute we’re looking for, and supports setting a maximum length (checking using the ISupportsMaxLength marker interface so we’re not trying to somehow set the max length on a checkbox, for example), we set the max length HTML attribute on the element. Pretty simple, but again, this is only really scratching the surface of what can be done with these behaviors.

So with all this in place, simply slap the StringLenght attribute on any needed view model properties. For instance, if we modify the CustomerViewModel’s name property like this:

[StringLength(30)]
public string Name { get; set; }

The outputted HTML would be:

<input id="Name" maxlength="30" name="Name" type="text" value="John" />

Neat, huh? In our current project, we’re using these to automatically denote required fields, and in conjunction with xVal, require those fields complete with client side checks. All from a few simple attributes.

A zip of the final project can be found here, for reference.

May 23

In part 1, I explained the reasoning behind using strongly typed HTML helpers in your view (with ease of refactoring being chief among them). Now that you have an ASP.NET MVC project referencing the needed Mvc Contrib assemblies, how can you actually get started using them?

Lets start by taking this sexy looking view model that represents a single customer:

public class CustomerViewModel
{
	public int Id { get; set; }
	public string Name { get; set; }
	public CustomerType Type { get; set; }
}

Where CustomerType is a standard enumeration:

public enum CustomerType
{
	Preferred,
	Standard,
	Delinquent
}

Then we’ll provide an easy enough action for editing a customer:

// In reality, we'd take in a customer Id and use that to load the customer from the database.
public ActionResult Edit()
{
	var customerViewModelLoadedFromDatabase = new CustomerViewModel
	                                          	{
	                                          		Id = 10,
	                                          		Name = "John",
                                                    		Type = CustomerType.Standard
	                                          	};
 
	return View("Edit", customerViewModelLoadedFromDatabase);
}

Before looking at the view, though, we’ll need to reference the MvcContrib.FluentHtml.dll assembly, and add the following to our web.config, under the configuration/system.web/pages/namespaces node:

<add namespace="MvcContrib.FluentHtml" />

With all that out of the way, here’s the relevant portion of the edit view:

<% using(Html.BeginForm<CustomerController>(x => x.Update(null))) { %>
	<%= this.Hidden(x => x.Id) %>
 
	<table>
		<tr>
			<td><b><%= this.Label(x => x.Name) %>:</b</td>
			<td><%= this.TextBox(x => x.Name) %></td>
		</tr>
		<tr>
			<td><b><%= this.Label(x => x.Type).Value("Customer Type") %>:</b></td>
			<td><%= this.Select(x => x.Type).Options<CustomerType>().Selected(Model.Type) %></td>
		</tr>
		<tr>
			<td colspan="2" align="center">
				<%= this.SubmitButton("Update Customer") %>
			</td>
		</tr>
	</table>
<% } %>

First, note that the page must inherit from MvcContrib.FluentHtml.ModelViewPage, not the standard Mvc ViewPage class. The strongly typed Html.BeginForm is from the Mvc Futures Assembly. Also, these extensions are on the ModelViewPage base class, not the normal Html helper type methods (i.e. they’re this.TextBox instead of Html.TextBox).

These fields are mostly self explanatory: you’ll see the Id is written to a hidden field on the page using the Hidden extension, the Name using the TextBox extension, and the Type (as a drop down list) using the Select extension. All of these extensions have quite a few customizable methods on them, such as the Options and Selected methods on the Select extension shown above. The options method allows you to specify (via generic type or otherwise with an overload) the options for the drop down, while the selected method allows you to specify which option of the list should be highlighted (it’ll default to the top item if the parameter is null). The Label extension can generate an HTML label “for” the specified control, so by clicking the “Name” or “Customer Type” labels above, most browsers will set focus to their respective controls.

Another quite useful extension is the this.IdFor(x => x.Name), which for our setup would simply output Name, but it comes in handy when dealing with sub objections and collections. This allows you to put a strongly typed reference to your control id’s in Javascript, so renaming the view model’s property renames all references, including the Javascript ones. Huge help there.

Alright, I’ll admit for basic cases like this it’s a bit harder to see the immediate benefits of strong typing, so let’s complicate it a tad by introducing a sub view model for an address, and a collection of order view models by adding this in the Edit action to the customer object initialization:

Address = new AddressViewModel
          	{
          		Street = "123 Easy St.",
          		City = "Beverly Hills",
          		State = "CA",
          		Zip = "90210"
          	},
Orders = new List<OrderViewModel>
         	{
         		new OrderViewModel
         			{
					Id = 300,
         				ApplyDiscount = true,
         				Quantity = 10
         			},
         		new OrderViewModel
         			{
					Id = 301,
         				ApplyDiscount = false,
         				Quantity = 20
         			}
         	}

Here’s one way to modify the edit page to deal with these new objects:

<tr>
	<td><b>Address:</b></td>
	<td>
		<table>
			<tr>
				<td>Street:</td>
				<td><%= this.TextBox(x => x.Address.Street) %></td>
			</tr>
			<tr>
				<td>City:</td>
				<td><%= this.TextBox(x => x.Address.City) %></td>
			</tr>
			<tr>
				<td>State:</td>
				<td><%= this.TextBox(x => x.Address.State).Styles(width => "30px") %></td>
			</tr>
			<tr>
				<td>Zip:</td>
				<td><%= this.TextBox(x => x.Address.Zip) %></td>
			</tr>
		</table>
	</td>
</tr>
<tr>
	<td><b>Orders:</b></td>
	<% for(int i = 0; i < Model.Orders.Count; i++) { %>
		<td>
			<%= this.Hidden(x => x.Orders[i].Id) %>
			<table>
				<tr>
					<td>Quantity:</td>
					<td><%= this.TextBox(x => x.Orders[i].Quantity) %></td>
				</tr>
				<tr>
					<td><%= this.Label(x => x.Orders[i].ApplyDiscount).Value("Apply Discount") %>:</td>
					<td><%= this.CheckBox(x => x.Orders[i].ApplyDiscount)%></td>
				</tr>
			</table>
		</td>
	<% } %>
</tr>

You’ll notice this is all still in a strongly typed manor, even with the sub object and object collection. These are basically the same extensions as before, except for CheckBox, which works as you’d expect. Note the Styles method on most of these extensions, which takes a param of Func’s that allows you to define CSS styles. The state text box, for examples, is defining the width CSS style and setting it to 30px.

All of these extensions take the current ViewData into account when rendering, just as the default ASP.NET MVC extensions do. For instance, the above CheckBox extension will render “checked” if the ApplyDiscount property is true coming in. You can also start to imagine how using the this.IdFor(x => x.property) extension to reference controls in your Javascript would start to come in handy here, as HTML id tag rendering for arrays (where the brackets are replaced with underscores) and sub objects (where dots are replaced with underscores) can get pretty complex.

That pretty much covers the basics of the FluentHTML extensions. These reasons alone were enough to get my team to switch our current project over to using them, let alone some of the more advanced features, such as basic validation integration. I’ll go over a few of those in the next part of this series, though. You can grab a zip of the current project here.

Apr 30

Out of the box, ASP.NET MVC uses weakly typed extension methods to generate various HTML elements (inputs, check boxes, select lists, etc). By weakly typed I mean they require strings, which are actually strings based on the properties of your view model. For instance, given this view model:

public class OrderViewModel
{
	public int Quantity { get; set; }
	public bool ApplyDiscount { get; set; }
}

You’d generate an input box for the quantity, using the standard HTML helper extensions, like so:

<%= Html.TextBox("Quantity") %>

Ew, strings. That’s so .NET 1.1, right? With .NET 3 we get Expressions and lambdas. Now lambdas are just more concise ways to define delegates (methods you can pass around as variables), so they’re nothing really new new. Expressions, for the purposes of this post, allow you to specify, in a compile safe manner, which property you want to use for something, which can then be parsed during run-time to get the property’s string name (suffice to say Expressions can do much more and form the foundation for LINQ To SQL). For instance, what if, instead of using the above TextBox method for the quantity product, we could do this:

<%= Html.TextBox(x => x.Quantity) %>

Rest assured it’d produce the same HTML in the end while giving us the type safety we’re looking for. What do I mean by type safety? I mean you can preform a rename refactoring on Quantity and you’d also rename the usage in the view (Resharper will actually do most rename refactorings on strings too, but it’s not 100% reliable – it’s a guess at best). That means less chance of something breaking (especially something you won’t find out about until runtime when your customers are in there), which means high quality, which is just cool.

OK, so we’re aware of what a strongly typed view would look like and the benefits of it. How can we do it? Well, we can roll our own (which has been done in a few places very nicely but is quite a bit of work), we can use the basic ones provided in the MVC Futures assembly (which provide pretty much the same functionality, look, and feel as the existing ones in System.Web.Mvc but with the strong typed goodness), or we can use the ones included in the open source MVC Contrib project. This is a project that provides a lot of really nice “glue” to help out with any ASP.NET MVC project, taking advantage of many of the extensibility points built into the framework already.

Unfortunately, it looks like the latest release download doesn’t include the Fluent Html assembly (fluent html is what most people use when referring to this strong typed HTML tag output because it’s a “fluent” interface, as you’ll see shortly). You’ll need to build the project from source, so grab the latest copy at http://mvccontrib.googlecode.com/svn/trunk, then run the ClickToBuild batch file in the root folder. It’ll do it’s thing, then when it’s finished you’ll need to grab the following files in the newly created buildnet-3.5.win32-MVCContrib-release folder:

  • MvcContrib.dll
  • MvcContrib.pdb (optional – provides line numbers if you need to debug anything)
  • MvcContrib.xml (method and parameter comments)
  • MvcContrib.FluentHtml.dll
  • MvcContrib.FluentHtml.pdb
  • MvcContrib.FluentHtml.xml

In the next part I’ll go over the basic usage of the library, then in the third part I’ll cover some of the cooler aspects, like tying it into validation and other things.

Part 2 and Part 3.

Feb 19
ELMAH with ASP.NET MVC
icon1 Darrell Mozingo | icon2 ASP.NET MVC | icon4 February 19th, 2009| icon37 Comments »

We finally got to the point of needing some error reporting in our new application. We’d read about ELMAH before and assumed we’d use that, but that was a while before we decided to go with the ASP.NET MVC framework instead of the traditional WebForms.

I was a little worried we’d hit some road block using ELMAH in conjunction with ASP.NET MVC, but it actually works out of the box without a hitch. ELMAH has a built in module for displaying any logged errors, and is accessible (by default) via http://localhost/elmah.axd. The latest releases of ASP.NET MVC automatically ignore routes with a .axd extension, though I’m not sure for how many releases they’ve been including that, so earlier releases will have a problem getting to that URL.

Simone Busoli wrote up an excellent article on the most important features of ELMAH and getting it setup. A must read if you’re going to implement this solution.

Here’s a quick run-down of the steps we went through for our application, though (using SQL logging & emailing the developers whenever an exception is logged):

  1. Reference the ELMAH.dll assembly in your project.
  2. Define the section group in your web.config:
    <sectionGroup name="elmah">
        <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
        <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
        <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
    </sectionGroup>
  3. Define the needed ELMAH section elements, along with their related SQL connection string, in your web.config (we’re only allowing access to the error page via the local host):
    <elmah>
        <security allowRemoteAccess="0" />
        <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ErrorLogging" />
        <errorMail
            from="PPError@PatriotSoftware.com"
            to="PPDevs@SynergyDataSystems.com"
            subject="Patriot Pay Error"
            async="true"
            smtpPort="25"
            smtpServer="imail.topechelon.corp" />
    </elmah>
     
    <connectionStrings>
        <add name="ErrorLogging" connectionString="Data Source=...." />
    </connectionStrings>
  4. Add the follow handler to the section that’ll allow you to view the errors (I used the path errors.axd instead of the default elmah.axd, just because I hate using default URL like that in case we ever allow this on something other than localhost w/a restricted login):
    <add verb="POST,GET,HEAD" path="errors.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
  5. Add the following modules to the section, which will actually catch exceptions for logging to SQL and emailing out:
    <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
    <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
  6. (Optional) Add the following methods to your Global.asax, which will filter all exceptions thrown on the local host and ignore them (so developing on your local machine won’t keep emailing everyone else, which, trust me, gets old pretty damn quick):
    public void errorLog_Filtering(object sender, ExceptionFilterEventArgs e)
    {
        if(ErrorFiltering.Filter(new HttpContextWrapper(e.Context)))
        {
            e.Dismiss();
        }
    }
     
    public void errorMail_Filtering(object sender, ExceptionFilterEventArgs e)
    {
        if(ErrorFiltering.Filter(new HttpContextWrapper(e.Context)))
        {
            e.Dismiss();
        }
    }

    and in another file somewhere (note the HttpContextWrapper in both of these pieces of code, for easier testing):

    public class ErrorFiltering
    {
        public static bool Filter(HttpContextWrapper httpContextWrapper)
        {
            return httpContextWrapper.Request.IsLocal;
        }
    }
  7. Run the SQL script included with the ELMAH download to generate the needed table and stored procedures, then hookup SQL security and the connection string from the previous steps

You should be good to go now, ripe with error logging goodness. For added user friendliness, we use the following in our web.config to redirect users to nice pages when an error pops up:

<customErrors mode="RemoteOnly" defaultRedirect="~/Errors/Generic.html">
    <error statusCode="404" redirect="~/Errors/NotFound.html" />
    <error statusCode="500" redirect="~/Errors/Internal.html" />
</customErrors>

The only thing that buggs me about using ELMAH is how Resharper acts with it. The SectionHandler’s defined in the sectionGroup in the web.config (from step 2 above) are internal to the ELMAH assembly, so Resharper freaks out that saying they’re not defined. Bzzt. Sorry, Resharper, try again. So I’ve simply built a local version of the project with those attributes marked as public and it’s all good. I’m looking into filing a bug report with Resharper on this issue now, as it does it with log4net too. Quite annoying when you have the Solution-wide Analysis option turned on and the web.config consistently shows up with “errors”.