Adding Schema & Sproc Prefix to ELMAH

on Tuesday, June 23, 2009

Background: ELMAH (Error Logging Modules and Handlers) is a great tool for any web developer that doesn’t want to go through the pain of adding in error logging to their web applications. A great tutorial on it was written up by Simone Busoli.

One of the features that ships with ELMAH is a database script for setting up the SQL Server table and stored procedures. And, unfortunately you can’t alter the names of the stored procedures out of the box, because the names are hardcoded in the ELMAH dll. This causes a bit of a problem with our environment and SQL Server 2008, because the script is designed for SQL Server 2000. All of the stored procedures are created under the owner [dbo].

While you can setup the schema of ‘dbo’ in SQL Server 2008, it’s not the most flexible way to go. Also, using the dbo schema would enforce the rule that you must have only one ELMAH error table in the database. Which would require making a separate database for each website.

This constraint didn’t work for our environment, so I went through the source code and found that it was a pretty straight forward process to add in Schema & Stored Procedure Prefixes while keeping the dll backwards compatible. Since ELMAH uses Inversion of Control to make it more reusable, you only need to update one file, SqlErrorLog.cs.

First you add in new properties for the Schema and SprocPrefix. And, then initialize them in the constructor:

/// <summary>
/// The schema name to use in place of 'dbo' on 2005/2008 Sql Server instances.
/// </summary>
internal virtual string Schema { get; set; }

/// <summary>
/// The stored procedure prefix. When used this will allow multiple applications
/// to use the same database (but, different sprocs/tables) to store exception
/// logs.
/// </summary>
internal virtual string SprocPrefix { get; set; }
public SqlErrorLog(IDictionary config)
{
// ... left out for clarity

// grab the schema if provided, else use 'dbo' as default
Schema = config["schema"] == null ? "dbo" : config["schema"].ToString().Trim();

// grab the stored procedure prefix if one is provided. the default value is an empty string.
SprocPrefix = config["sprocPrefix"] == null ? string.Empty : config["sprocPrefix"].ToString().Trim();
}

After that, all that’s left is updating the private Commands classes method signatures to require the schema and sprocPrefix variables. Like so:

public static SqlCommand LogError(
Guid id,
string appName,
string hostName,
string typeName,
string source,
string message,
string user,
int statusCode,
DateTime time,
string xml,
string schema,
string sprocPrefix)
{
var commandText = string.Format( "[{0}].[{1}ELMAH_LogError]", schema, sprocPrefix );
var command = new SqlCommand(commandText);

// ... left out for clarity
}

And, finally update the code which calls those methods.

Then you can use the ‘schema’ and ‘sprocPrefix’ attributes in the configuration file.

<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="XYZ" schema="Ent" sprocPrefix="WebApp1_" />

Thanks Atif Aziz for making it so easy.

The error message just isn’t helpful

on Tuesday, June 16, 2009

(Heads Up: This is not my code. I’m trying to help out.)

In our systems there is a web application (not website) which has an automated Cruise Control (ccnet) build. And that ccnet build has worked for a couple of weeks until I added a  new webpage.

Unfortunately, once I added the webpage to the build I started to receive this error  from the asp compiler (when I removed the webpage the error went away):

/Announcements/ArchiveFeed.aspx(2): error ASPPARSE: Could not load type 'ArchiveFeed'.


I looked at both the aspx and aspx.cs file which created the error and could not understand why the error message was being generated:



ArchiveFeed.aspx:



<?xml version='1.0' encoding = 'utf-8'?>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ArchiveFeed.aspx.cs" Inherits="ArchiveFeed" Title="Announcement Archives" %>

<rows>
<page>1</page>
<total>2</total>
<records>15</records >

<asp:Repeater ID="repeater1" runat="server">

<HeaderTemplate>
</HeaderTemplate>

<ItemTemplate>
<row id='<%# DataBinder.Eval(Container.DataItem, "Id") %>'>
<cell><%# DataBinder.Eval(Container.DataItem, "Id") %></cell>
<cell><%# DataBinder.Eval(Container.DataItem, "Subject") %></cell>
<cell><%# DataBinder.Eval(Container.DataItem, "Message") %></cell>
<cell><%# DataBinder.Eval(Container.DataItem, "Editor") %></cell>
<cell><%# DataBinder.Eval(Container.DataItem, "Tr") %></cell>
</row>
</ItemTemplate>

<FooterTemplate>
</FooterTemplate>

</asp:Repeater>

</rows>


 



ArchiveFeed.aspx.cs:



using System;
using System.Collections;
using System.Web.UI;
using Ucsb.Sa.Registrar.Herald;
using Ucsb.Sa.Registrar.Herald.Services;


public partial class ArchiveFeed : Page
{
private AnnouncementService _servAnnounce = AppSettings.GetAnnouncementService();
private ArrayList list1 = new ArrayList();
protected void Page_Load(object sender, EventArgs e)
{
/*if (Session["validated"] == null || !Session["validated"].Equals("true"))
{
Response.Redirect("Login.aspx");
}*/
Response.ContentType = "text/xml";
AnnouncementList aList = _servAnnounce.getAllAnnouncements();
for (int i = 0; i < aList.Announcements.Count; i++)
list1.Add(new ArchiveInformation(aList.Announcements[i].ID,aList.Announcements[i].Subject,aList.Announcements[i].Message,
aList.Announcements[i].Editor,aList.Announcements[i].ActiveTimeRange));
//lists.Add(aList.Announcements[i].ID);
this.repeater1.DataSource = list1;
this.repeater1.DataBind();
}
}



After asking some of the other developers in the department about the problem, a unanimous conclusion was made: “That’s just weird”. So what the heck is going on?



Any help would be appreciated.



UPDATE: The code behind for the page wasn't able to compile because a referenced assembly wasn't updated in the source control system. I have become too reliant on the source control system's Visual Studio integration.

List of useful commands: Remote Commands

on Monday, June 15, 2009

When using remote desktop a number of problems can occur which will make your remote system unresponsive. The worst of which is a system freeze, which requires a hard boot. But, here’s a couple things to try before driving into the office. In order to use these commands you will need to remote into another system on the same network.

Attempt a remote reboot of the system: shutdown –m \\XXX.XXX.XXX.XXX  -r

Sometimes, after attempting a remote restart the shutdown process seems to hang or become unresponsive. If that occurs, then you can use psexec to attempt to run remote commands: psexec \\XXX.XXX.XXX.XXX cmd.exe

Once you have a command prompt on the remote system, you can get a list of active processes using: tasklist

And, you can kill a process using: taskkill /PID XXXX or taskkill /IM notepad.exe

To exit psexec use Ctrl-C.

Windows 7 RC, VS 2010 Beta & SQL Server 2008 SP1

on Saturday, June 13, 2009

Near the end of the VS 2010 Beta installer SQL Server Express 2008 is installed. The installer will pause for a moment and display a warning dialog stating that SQL Server has known compatibility issues with this version of Windows. An installation helper is provided which offers a solution of installing SQL Server 2008 SP1. The given link to the SP1 installer is: http://www.microsoft.com/downloads/details.aspx?familyid=01AF61E6-2F63-4291-BCAD-FD500F6027FF&displaylang=en#filelist.

Unfortunately, all of the downloads on the page are install for SQL Server Express editions, not SP1. There are links on the bottom of the page which lead to the SP1 download: http://www.microsoft.com/downloads/details.aspx?familyid=66AB3DBB-BF3E-4F46-9559-CCC6A4F9DC19&displaylang=en.

Hopefully, this write up will clear up a little bit of the confusion. It’s also likely that a future version of the installer will include the service pack.

PS. After a little bit more searching on MSDN, I ran across a much more thorough write-up by Weston Hutchins: http://social.msdn.microsoft.com/Forums/en-US/setupprerelease/thread/4c740329-7366-43ca-b9f4-207a391b311b

iPhone and Microsoft Exchange

on Monday, June 1, 2009

At work we use a Microsoft Exchange server for all email. It’s a stable email server and the Microsoft Outlook client has a really polished UI. The 3rd party extensions aren’t as mature (IMHO) as the Thunderbird extensions, but the Calendar integration is pretty top notch.

I try to keep all my calendar events using the Exchange calendar system because it’s so easy to use. And I have integrated the Exchange Calendar with Google Calendar in order to have easy access to the system from home. The Google Calendar Sync service does a pretty good job of providing synchronization, but I’ve seen it miss a few appointments/meetings here and there. For the most part, it’s accurate and efficient.

Recently, I got an iPhone and have been blown away by the integration and accuracy. I haven’t been using the iPhone as long as the Google Calendar Sync; so this might be a premature evaluation.

However, I have found a couple of the features to be really compelling.

First, the easiness of adding my email account to the iPhone was amazing. Of course I had to put in my email address & password. But, here was the great part: To hook up the phone to the web interface of Exchange meant 1) entering the domain name that the Exchange server was on (eg. somedomain.com) and then 2) click “Next”. The phone searched the domain network for a web access point and returned with the correct dns information (eg. webmail.somedomain.com). That was it.

Second, I’ve compared the iPhone’s calendar with my Google Calendar and the iPhone caught all of the appointments/meetings which the Google Calendar missed.

Third, the iPhone is actually receiving emails a few seconds before the Outlook client on my work computer is. And, the Calendar is automatically being updated when the email arrives.

A Big THANK YOU to the iPhone designers for making this such an easy process!

 

The other phone I was considering was the Google phone. Does anyone have experience with that phone? How does the email/calendar integration on the G1 compare with the iPhone email/calendar integration?


Creative Commons License
This site uses Alex Gorbatchev's SyntaxHighlighter, and hosted by herdingcode.com's Jon Galloway.