Tim

Footprints in the snow of a warped mind

Tag Cloud

AJAX (4) ASP (5) ASP.Net (36) Error Reporting (2) Atlas (2) Business (52) Business Start-up Advice (22) Client (6) Expanding Your Business (11) C# (3) Canoeing (4) Canoe Racing (5) Cheshire Ring Race (5) Racing (2) Training (4) CIMA (1) CSS (3) dasBlog (2) Design (7) Icons (1) General (34) Christmas (6) Fun and Games (10) Internet (15) Random (38) RX-8 (8) Home Cinema (2) Hosting (1) IIS (6) JavaScript (2) Multipack (1) Networking (1) Nintendo (1) OS Commerce (1) PHP (1) Press Release (1) SEO (4) Server Maintenance (2) Server Management (5) Software (7) Office (3) Visual Studio (6) Windows (3) Vista (1) SQL Server (9) The Site Doctor (68) Turnover Challenge (1) Umbraco (5) Web Development (32) WebDD (32) Wii (1)

Atom 1.0 RSS 2.0 CDF 

Search

<May 2008>
SunMonTueWedThuFriSat
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

Recent Comments

Blog Archive

Various Links

Blogs I Read

 Craig's Blog
Craig Hawker's Blog
 Google Blog
Official Google Webmaster Central Blog
 Matt Cutts
Gadgets, Google, and SEO
 Ol' Deano's Blog
My mate Dean's blog on my space, equally as random as mine but not off on as much of a tangent!
 Sam's Blog
Sam is one of my younger brothers studying Product Design and Manufacture at Loughborough, this is his blog :) Enjoy!

Recent Tracks

last.fm - The Social Music Revolution

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

newtelligence dasBlog 2.0.7226.0

Send mail to the author(s) Email Me (Tim Gaunt)

© 2008 Tim Gaunt.

Sign In

Get Windows Live Alerts

 Thursday, May 01, 2008

How to apply Heading Tags in Umbraco

Thursday, May 01, 2008 2:21:56 PM (GMT Standard Time, UTC+00:00)

I've seen a couple of posts recently about how to apply headings to text within Umbraco and the main suggestion is that you apply them by hacking about with the StyleSheets that just doesn't sit right with me.

We use a different method -that is to enable the format drop down list. To me it just seems cleaner but I get the feeling I'm about to start a big debate. The method we use was originally discussed here but in short download this zip file with the updated DLLs in and instructions.

6291-leftinymce.zip (241KB)

How to apply Heading Tags in Umbraco
Useful Links:  #  digg it!  del.icio.us  Technorati  email it!  Post CommentsComments [0]  Trackback Link
CategoriesTags: ASP.Net | Umbraco
 Wednesday, April 30, 2008

The Site Doctor is hiring!

Wednesday, April 30, 2008 3:18:00 PM (GMT Standard Time, UTC+00:00)

Despite all the doom and gloom surrounding the pending credit crunch, we're hiring as work is piling in and we need help :). So if you're a developer, designer, sales person, marketing guru -or you're just plain bored check out The Site Doctor's vacancies page for the great posts currently up for grabs!

Not sure why you should come and work with us? There are way too many reasons to list in one go but here are my top 5:

  • You'll have a great boss (ok I'm a touch biased)
  • We have 20% time (every Friday we down tools and do something cool -that doesn't relate to the main projects you're working on at the time -more about that another day)
  • We're committed to your development and will fund courses etc
  • There are bonuses to be had for referrals and working hard!
  • You get your Birthday as an additional bank holiday so you never need to worry about booking it off again!

Oh and there's free Tea and Coffee -so I guess that's 6 reasons to get in touch.

For more information about the posts available (more being added later this week) check out The Site Doctor vacancies page.

 Sunday, January 13, 2008

How to: Remove users from the ASP.Net membership database

Sunday, January 13, 2008 8:37:44 PM (GMT Standard Time, UTC+00:00)

I'm sure I've blogged about this in the past -or perhaps it's just in my "to blog about list" but I thought I would share this little ditty on the Sunday night.

If you ever need to delete a user from your ASP.Net Membership database this is a really useful SQL script to do just that (I often find that the ASP.Net web administration tool throws a SQL Exception while trying to delete a user).

To use the code to delete a user from the ASP.Net membership database simple identify the Guid of the user and enter it where I've written 'THE GUID OF THE USER HERE' and hit go :)

USE ASPNet
GO

DECLARE @UserId uniqueidentifier
SET @UserId = 'THE GUID OF THE USER HERE'

DELETE FROM aspnet_Profile WHERE UserID = @UserId
DELETE FROM aspnet_UsersInRoles WHERE UserID = @UserId
DELETE FROM aspnet_PersonalizationPerUser WHERE UserID = @UserId
DELETE FROM dbo.aspnet_Membership WHERE UserID = @UserId
DELETE FROM aspnet_users WHERE UserID = @UserId

The message I was referring to above usually looks something like the following:

Msg 547, Level 16, State 0, Line 9
The DELETE statement conflicted with the REFERENCE constraint "FK__aspnet_Us__UserI__17036CC0". The conflict occurred in database "ASPNetMemberships", table "dbo.aspnet_UsersInRoles", column 'UserId'.
The statement has been terminated.

I've not looked into why it's happening (I expect it's something to do with an incorrect install on my behalf) but I'm sure there's a solution for it. I know there are a couple of built in SQL scripts i.e. aspnet_Users_DeleteUser but they required more params to get working ;)

 Monday, November 26, 2007

Naming conventions for Umbraco

Monday, November 26, 2007 10:30:56 AM (GMT Standard Time, UTC+00:00)

Having only recently started to use Umbraco I've taken a couple of days to familiarise myself with the way it works and try and get a few best practices in place, I expect these will be updated over time but you've got to start somewhere ;)

As with any code, I think it's very important to follow a consistent naming convention -whether it's the same one everyone else follows or not, you need to be able to pickup code you wrote months/years/decades ago and still understand it. Your styles will no doubt change over the years but you get the idea.

I've chosen to follow the following "style":

  • Document Types: Lowercase the first letter of the aliases followed by capitals for the new words (similar to Hungarian Notation). Use descriptive names i.e. Home Page for the document type as it'll be client facing. Suffix with "Page" if it is a page document type (as opposed to i.e. a screen shot)
  • Templates: If the template is specifically for a document type, use the same name for the template, if it relates to multiple document types name it logically i.e. "Master Template" or "Left Menu"
  • Macros: Prefix the macro alias with uppercase TSD to avoid conflicts with other macros. Prefix the name with [Source of the macro] i.e. [XSLT] or [User Control]. This is something I picked up from the sample package created by Warren Buckley that I think makes it easier to understand what's going on
  • XSLT Files: Prefix the name with the site's abbreviation i.e. for www.thesitedoctor.co.uk it would be TSD or for www.wineandhampergifts.co.uk WAHG if it's a site specific XSLT file otherwise name conventionally i.e. CamelCase
Naming conventions for Umbraco
Useful Links:  #  digg it!  del.icio.us  Technorati  email it!  Post CommentsComments [0]  Trackback Link
CategoriesTags: ASP.Net | Umbraco | Web Development | WebDD
 Saturday, November 03, 2007

Umbraco and Ghost/Cached/Deleted pages appearing in menu

Saturday, November 03, 2007 1:31:42 PM (GMT Standard Time, UTC+00:00)

I'm currently investigating a new Open Source ASP.Net CMS system called Umbraco. It looks very promising as it can be fully accessible and has full support for XHTML among many other interesting features. I met with a couple of the guys that are developing the system in Manchester a couple of weeks ago and they've got big plans so keep an eye on it.

Anyway yesterday while setting up the new The Site Doctor site on Umbraco I ran into an issue where by I had "broken" the menu. Basically I had deleted the template from the system which should have deleted all copies of the pages that use that template but instead a cache remained somewhere. I ran through a number of steps to re-create the cache but nothing worked.

If you run into the same issue as I did, follow these steps:

  1. Find out the ID of the page in question (easiest way is just to add the ID to the output of the menu XSLT)
  2. Search the database for the ID using the T-SQL I posted in "How to search every table and field in a SQL Server Database"
  3. Download and install a Unicode and UTF-8 search program such as Text Workbench and search for the ID (I only found it in /data/Umbraco.config)
  4. Reset the applications cache -the easiest way to do this is to simply re-upload the web.config file

That should sort it :)

 Friday, September 21, 2007

What have I been up to?

Friday, September 21, 2007 10:20:01 PM (GMT Standard Time, UTC+00:00)

It's been rather quiet on my blog recently, if you're wondering why (and don't chat to me on/off-line) I thought I would share with you what we've been working on recently.

For the past month or so The Site Doctor has been developing a new web site (www.wineandhampergifts.co.uk) for Porter and Woodman Gifts Ltd - a local company that produces personalised corporate hampers and gifts. It's been quite a challenge as they have a rather unusual ordering system that allows multiple recipients/addresses multiple items. Looking at it now, it's not so complicated but the delivery charge calculations and initial specs took a while to fully grasp. It's been really enjoyable.

I'll probably cover aspects of the site over the forthcoming months but there are a few really nice features to the Wine and Hamper Gifts site (or at least I think so), some of which the end user will never know about such as the use of generics to calculate the address/recipient/gift variations) and those that they may -for instance the use of the JavaScript1 Zoom function on the product details page (courtesy of LuckyZoom), also the design created by our excellent designer Gareth Brown all adds up to what has to be one of the best sites I've developed to date.

1 Yes, I did just say I've integrated some JavaScript into the site ;)

I doubt most of my readers are interested on the in's and out's of the project itself but from an SEO perspective, I for one am expecting pretty decent results. We opted to use the URL Rewriting ISAPI from Helicon this time round over our usual IISMods URL Rewriting ISAPI as for some reason the IISMods site has been offline for a while (and checking now has been converted into a very weird site).

Another aspect that some people may be unaware of is that the majority of the Wine and Hamper Gifts site operates the same without JavaScript as it does with JavaScript, this is important not only for screen readers but also search engines. There is only one area of the Wine and Hamper Gifts site that I'm aware of that doesn't operate without JavaScript and that is the "Personalise this gift" link on the cart page that allows the user to either edit the existing message or add one that doesn't already exist, that's because it uses a LinkButton, but I may find a way around that later.

Other features that I really like are little things like the way the drop down lists on the left hand menu are created -they're not actually drop down lists but unordered lists that are then manipulated using JavaScript, I think the JavaScript could do with a little tweaking but the result is superb. The Wine and Hamper Gifts site also creates a PDF receipt for the user which is emailed to them, this is something I've been meaning to look into for some time but haven't had the chance, luckily while I was developing the site, Sean Ronan posted to the MsWebDev list about an ASP.Net PDF library iTextSharp (a port from a Java library) which, despite a few oddities from the POV of the Java port does exactly what I wanted. The library is pretty easy to use once you get your head around it and certainly produces some nice results.

There's still more work that's needed to finalise the content and various aspects of the Wine and Hamper Gifts website but if you have a chance, check out the new Porter and Woodman Gifts Ltd Wine and Hamper Gifts website and leave a comment here letting me know what you think :D

Oh, and they've given us a pretty high target to get before Christmas so if you're thinking about treating your customers to a personalised corporate hamper or gift give a little thought to using www.wineandhampergifts.co.uk

What have I been up to?
Useful Links:  #  digg it!  del.icio.us  Technorati  email it!  Post CommentsComments [0]  Trackback Link
CategoriesTags: AJAX | ASP.Net | C# | CSS | Design | SEO | The Site Doctor | Web Development
 Friday, August 24, 2007

The Controls collection cannot be modified because the control contains code blocks

Friday, August 24, 2007 9:49:56 AM (GMT Standard Time, UTC+00:00)

Server Error in '/' Application.


The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>).
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Web.HttpException: The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>).

Source Error:

 

Line 132:                        metaKey.Name = "keywords";
Line 133:                        metaKey.Content = p.MetaKeywords;
Line 134:                        this.Page.Header.Controls.Add(metaKey);
Line 135:                    }
Line 136:                    if (!String.IsNullOrEmpty(p.MetaDescription))


Source File: a:\xyz\ContentHandler.aspx.cs    Line: 134

Stack Trace:

 

[HttpException (0x80004005): The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>).]
   System.Web.UI.ControlCollection.Add(Control child) +2105903
   ContentHandler.Page_Load(Object sender, EventArgs e) in a:\xyz\ContentHandler.aspx.cs:134
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +15
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +34
   System.Web.UI.Control.OnLoad(EventArgs e) +99
   System.Web.UI.Control.LoadRecursive() +47
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1061


Version Information: Microsoft .NET Framework Version:2.0.50727.832; ASP.NET Version:2.0.50727.832

Another day, another issue ;)

This had me going around in circles for a while until I realised what it was, if you're getting this error you can bet your bottom dollar that you have <%= %> somewhere in your page's header -furthermore I'd hazard a guess that you've got it in some JavaScript to reference an ASP.Net control on the page- and then you're trying to add a control to the header programmatically (or a custom control from someone like Telerik is trying to). Am I right1?

1 I'm not allowed to ask you to so I won't, but if I was right, then spend that bottom dollar clicking on one of the Google Ads :P

I can't tell you exactly why this occurs but my understanding of it is that ASP.Net can't re-create the header if it has Response.Write somewhere in the header (<%=) -most likely due to when the header is created it's not available (will look into it). No doubt you want to know the fix?

The Fix
The fix is simple, remove the inline code blocks and JavaScript and move it to your code behind i.e.:

string _manageSearch = String.Format( @" 
        function ManageSearch(){{
                var lbl = document.getElementById(""lblFindAGift"");
                var txt = document.getElementById(""{0}"");
                var btn = document.getElementById(""{1}"");

                .Do Something with it..

        }}",

        txtSearch.ClientID);

this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "ManageSearch", _manageSearch, true);

Remember: You need to escape the curly brackets otherwise you will get a "String.Format- Exception of type System.Web.HttpUnhandledException was thrown"

Update: Thanks to Julian Voelcker for sending me this alternative "fix" for the problem, can't say I like it though ;) basically instead of using <%= ... %> you would write the databinding expression of: <%# ... %>

 Wednesday, August 22, 2007

String.Format- Exception of type System.Web.HttpUnhandledException was thrown.

Wednesday, August 22, 2007 8:43:12 PM (GMT Standard Time, UTC+00:00)

Type
System.FormatException
Message
Exception of type 'System.Web.HttpUnhandledException' was thrown.
StackTrace
at System.Text.StringBuilder.FormatError()
at System.Text.StringBuilder.AppendFormat(IFormatProvider provider, String format, Object[] args)
at System.String.Format(IFormatProvider provider, String format, Object[] args)
Error Line
0

Just got that message (or at most "Exception of type 'System.Web.HttpUnhandledException' was thrown")? Puzzled? I was the first time I got it, I've been meaning to post about it for quite some time now so seeing as I got it again today I took the hint.

The error is horrifingly obvious when you know about it, in short, you've no doubt got some code that looks like this:

String.Format("<html><head><style type=\"text/css\">body{color: #fff;}</style><body>...");

Can you spot it now? Notice your style declaration is using the curly brackets? Basically String.Format is interpreting that as a placeholder i.e. {0} and is throwing a wobbly.

The solution is simple too, just replace all opening/closing brackets with two i.e:

String.Format("<html><head><style type=\"text/css\">body{{color: #fff;}}</style><body>...");

I hope that helps someone out there :)

P.S. Watch out for methods that use String.Format as they may catch you out in the same way -i.e. Subject of System.Net.Mail.MailMessage

 Wednesday, August 08, 2007

'debug' is undefined with Microsoft AJAX release and TextChangedBehavior.js

Wednesday, August 08, 2007 5:20:47 AM (GMT Standard Time, UTC+00:00)

As with my previous post, we upgraded the AJAX framework on the weekend which broke a few things, but one control in particular that broke was our TextChangedTextBox which is based on Pete Kellner's timed postback control. Since updating we were receiving a "'debug' is undefined" error on line 1409 (which was in one of the JavaScript include files).

Having had this issue before I updated the TextChangedBehavior.js but that didn't sort it, I have the latest version of the Futures on the server too so I was lost. Turns out I had an old version of the AJAX Futures DLL within the Bin folder of the project.

So as with my post on the ASP.Net forums before -make sure you update your AJAX Futures when updating your Microsoft AJAX framework!

 Monday, August 06, 2007

Server cannot modify cookies after HTTP headers have been sent (RoleManagerModule.OnLeave)

Monday, August 06, 2007 12:52:08 PM (GMT Standard Time, UTC+00:00)

Over the weekend we had to upgrade the server's version of ASP.Net AJAX which went fine until this morning when we started receiving the error "Server cannot modify cookies after HTTP headers have been sent."

Luckily this wasn't bubbled up to the UI but incase other people are getting the error I thought I would share the fix. The error is apparently a known error with ASP.Net AJAX and the RolesManager. To fix the error all you need to do is add the following to your RolesManager web.config node:

cacheRolesInCookie="false"


The full error message was

Message:
Server cannot modify cookies after HTTP headers have been sent.

StackTrace:
at System.Web.HttpCookieCollection.Add(HttpCookie cookie)
at System.Web.Security.RoleManagerModule.OnLeave(Object source, EventArgs eventArgs)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

 Tuesday, May 01, 2007

ASP.Net Membership SQL Roles access

Tuesday, May 01, 2007 7:41:48 AM (GMT Standard Time, UTC+00:00)

We have recently moved over to SQL Server 2005 and as part of this transfer I decided to aggregate two separate ASP.Net Membership databases that were created purely out of error.

For those of you who don’t already know, you can happily run more than application’s security from a single membership database as long as you correctly configure the web.config’s security settings –for more information on doing that see my post on having dual records in the ASP.Net authentication table (see: Dual Records In The ASPNet Authentication Table). The important attribute/value set to configure if you are planning on running more than one application from the same roles database is “applicationName”. If you do not set “applicationName” you will find that users can log in across all your applications, roles/access levels will get mixed up and a whole bunch of other hullabaloo!

Luckily for me, the only records stored in one of the membership databases were two users, both of which I knew the password to so I decided I would simply update the web.config with the new database connection string and add them manually.

The next thing I wanted to sort however was the specific SQL Login’s access to the membership database, previously I simply added the user to all the various aspnet_ roles that were in the database which worked fine. As I’m looking to use this database for other applications in the future and I don’t like sharing usernames/passwords across applications, adding the roles each time would become a real PITA so I decided to add a new role with all the access required for the database so I could simply add the user to this new role. I called the role IIS_User.

A number of our applications build on the foundation of the ASP.Net Membership database with application specific values and so I tend to have another table for the application’s users within the applications specific database to store these values. The user has the usual UserId (usually an int) and a uniqueidentifier which allows me to link the two database together. With this in mind, I need additional access to the ASP.Net Membership database –SELECT permission on the tables. I don’t like adding more permissions to a role than needed but I needed a method of doing this quickly –assigning EXECUTE and SELECT permissions to the new role on the various tables/stored procedures. In time I’ll revisit this and work out which are needed by the role and remove the permissions not needed but for now this’ll do :)

The quick and dirty T-SQL

DECLARE @SQL nvarchar(4000),
    @Owner sysname,
    @objName sysname,
    @Return int,
    @objType nvarchar(5),
    @rolename nvarchar(255)

SET @rolename = 'IIS_User'

-- Cursor of all the stored procedures in the current database
DECLARE cursStoredProcedures CURSOR FAST_FORWARD
FOR
SELECT 
    USER_NAME(uid) Owner, 
    [name] StoredProcedure,
    xtype
FROM
    sysobjects
WHERE
(
    xtype = 'U'
  OR
    xtype = 'P'
)
  AND
    LEFT([name], 7) = 'aspnet_'

OPEN cursStoredProcedures

-- Get the first row
FETCH NEXT FROM cursStoredProcedures
INTO @Owner, @objName, @objType

-- Set the return code to 0
SET @Return = 0

-- Encapsulate the permissions assignment within a transaction
BEGIN TRAN

-- Cycle through the rows of the cursor
-- And grant permissions
WHILE ((@@FETCH_STATUS = 0) AND (@Return = 0))
  BEGIN

    --Determine the object's type (table/stored procedure) -could 
    --be done using a case too if more objects are added later
    IF @objType = 'P'
    BEGIN
        SET @SQL = 'GRANT EXECUTE ON [' + @Owner + '].[' + @objName  + '] TO ' + @rolename
    END

    IF @objType = 'U'
    BEGIN
        SET @SQL = 'GRANT SELECT ON [' + @Owner + '].[' + @objName  + '] TO ' + @rolename
    END

    -- Execute the SQL statement
    EXEC @Return = sp_executesql @SQL

    -- Get the next row
    FETCH NEXT FROM cursStoredProcedures
    INTO @Owner, @objName, @objType
  END

-- Clean-up after the cursor
CLOSE cursStoredProcedures
DEALLOCATE cursStoredProcedures

-- Check to see if the WHILE loop exited with an error.
IF (@Return = 0)
  BEGIN
    -- Exited fine, commit the permissions
    COMMIT TRAN
  END
ELSE
  BEGIN
    -- Exited with an error, rollback any changes
    ROLLBACK TRAN
    
    -- Report the error
    SET @SQL = 'Error granting permission to ['
    + @Owner + '].[' + @objName + ']'
    RAISERROR(@SQL, 16, 1)
  END
GO
ASP.Net Membership SQL Roles access
Useful Links:  #  digg it!  del.icio.us  Technorati  email it!  Post CommentsComments [0]  Trackback Link
CategoriesTags: ASP.Net | SQL Server | Web Development
 Monday, March 19, 2007

How to use Phil's error reporting code

Monday, March 19, 2007 7:34:20 PM (GMT Standard Time, UTC+00:00)

I’ve done a number of posts now on Phil Whinstanley’s error reporting class and this blog appears to be getting a lot of hits because of that which is pretty neat, as a result I’ve had a couple of people write to me asking similar questions about the code so I thought it would be an idea to write a little summary.

Where can I download the code?

It would appear that most of the old copies of Phil’s code have disappeared from the web, I’m not sure why so I’ve uploaded the versions I’ve got below. For convenience I have compiled the code into DLLs for those that don’t know/want to do this and I’ve also included the Visual Studio solutions. I’m not sure if these are based on the original codebase but I don’t think I’ve made any major alterations to these versions:

1 This is a version I was sent as his original including changes and example email was lost...

DLLs only:

If you have Visual Studio:

If you don’t have Visual Studio you can either download one of the above projects and delete the solution/project files or download the original WebException code. Ok, now you have the files :) -FWIW I can accept no responsibility for any of the files or the code, I just zipped them!

How to do I use the WebException class?

I’m now using a slightly modified version of the code to enable error reporting within AJAX (see: Reporting errors from AJAX using the WebException Class) which I’ll try and upload later but whichever version of the code you choose the use is pretty much the same.

Once you have referenced the DLL in your project (see: Importing/Referencing DLLs in Visual Studio) you will be able to use the WebException. As I’ve covered what you need to do to use the code from within an AJAX application in another post (see: Reporting errors from AJAX using the WebException Class) I’ll just cover how to use it to report global errors. To capture and respond to all application errors you will need to place this code within the global.asax, your project should automatically have one, if it doesn’t then you will need to add one.

Using the global.asax file, the first thing you need to do is add a reference to the DLL at the top of your code (this will allow you to call the methods and access the properties):

<%@ Import Namespace="ErrorReporting" %>

Next locate the Application_Error event handler, this is the method that handles all errors within the application (with exception of those thrown from within an AJAX application, read this post to report errors from within an AJAX application). Now replace your Application_Error and Application_PreRequestHandlerExecute handlers with (for more information on what I'm doing here see: ASP.Net WebException and Error Reporting useful code):

void Application_Error(object sender, EventArgs e)
{
    bool reportErrors = Convert.ToBoolean(System.Configuration.ConfigurationManager.AppSettings["SendErrors"]);

    if (reportErrors)
    {
        Exception currentError = Server.GetLastError();

        #region Deal with 404's

        //Redirect the user to a friendly page