Programmatically configure customErrors redirects

by: Ted Nyberg (Ted & Gustaf)

I previously posted a possible solution for handling 404 exceptions in EPiServer websites, but here's an alternative and possibly more elegant way of configuring custom error redirects for EPiServer.

What I wanted to accomplish

I wanted to be able to specify a PageID for 404 File Not Found errors and another one for 500 Server Exception errors and have these EPiServer pages act as error messages. So, I started by adding the following keys to my appSettings section in web.config:

  <add key="FileNotFoundPageId" value="481"/>
  <add key="GenericErrorPageId" value="482"/>

A birds-eye view of the solution

Here's the algorithm in short:

  1. Check if customErrors is enabled in web.config
  2. If so, check if there are redirects specified for 404 and 500 errors
  3. If not, add new redirects
  4. If redirects exist, validate their respective redirect URL
  5. Add/modify custom error redirects as necessary
  6. Save web.config

The code

Here's the method that I now call from the
Application_Start() method in global.asax:

/// <summary>
/// Performs customErrors configuration based on
/// related app settings
/// </summary> public static void ConfigureCustomErrors() { Configuration config =
WebConfigurationManager.OpenWebConfiguration("~"); CustomErrorsSection section =
(
CustomErrorsSection)config.GetSection(
"system.web/customErrors");
//Verify that customErrors exists in web.config
if (section != null) {
//Only configure if customErrors is enabled
if (section.Mode != CustomErrorsMode.Off)
{ if(!section.IsReadOnly() &&
!section.SectionInformation.IsLocked) {
//Collection of new redirects to add to
//the customErrors element
CustomErrorCollection redirectsToAdd =
new CustomErrorCollection(); //Page ID of the page to be used for
//custom error redirects
int redirectPageId = 0; //Get existing redirects, if any CustomError redirect404 =
section.Errors[
"404"]; CustomError redirect500 =
section.Errors[
"500"]; //Get URL for 404 redirects int.TryParse(
ConfigurationManager.AppSettings[
"FileNotFoundPageId"],
out redirectPageId); string fileNotFoundURL =
ToolBox.GetSimpleAddress(
DataFactory.Instance.GetPage(
new PageReference(redirectPageId)); //Get URL for server error redirects int.TryParse(
ConfigurationManager.AppSettings[
"GenericErrorPageId"],
out redirectPageId); string serverErrorURL =
ToolBox.GetSimpleAddress(
DataFactory.Instance.GetPage(
new PageReference(redirectPageId))); //If the 404 redirect hasn't been
//specified or if its redirect
//URL is invalid
if (fileNotFoundURL!=string.Empty &&
(redirect404 ==
null ||
redirect404.Redirect!=
fileNotFoundURL)) {
//Add new
if (redirect404 == null)
{ CustomError fileNotFoundError =
new CustomError(404,
fileNotFoundURL);
redirectsToAdd.Add(
fileNotFoundError); }
else //Modify existing { redirect404.Redirect =
fileNotFoundURL; } }
//If the 500 redirect hasn't been
//specified or if its redirect
//URL is invalid
if (fileNotFoundURL != string.Empty &&
(redirect500 ==
null ||
redirect500.Redirect !=
fileNotFoundURL)) {
//Add new
if (redirect500 == null)
{ CustomError serverError =
new CustomError(500,
serverErrorURL);
redirectsToAdd.Add(serverError); }
else //Modify existing redirect { redirect500.Redirect =
serverErrorURL; } }
//Add any new redirects foreach (
CustomError redirectToAdd in
redirectsToAdd)
{ section.Errors.Add(redirectToAdd);
} //Save web.config if its
//contents have changed
config.Save(); } } } }
 

The result

When the EPiServer website application starts, the web.config file includes the following element within the system.web section:

<customErrors mode="On" />

After the ConfigureCustomErrors() method above has executed, web.config looks like this:

<customErrors mode="On">
  <error statusCode="404" redirect="/404" />
  <error statusCode="500" redirect="/error" />
</customErrors>

Now, if I manually modify the URLs of these redirects and save web.config the website will restart and the redirects will be re-configured with the correct friendly URLs:

Manual edit:

<customErrors mode="On">
  <error statusCode="404" redirect="/my404.aspx" />
  <error statusCode="500" redirect="/error.aspx" />
</customErrors>

After the website application has restarted:

<customErrors mode="On">
  <error statusCode="404" redirect="/404" />
  <error statusCode="500" redirect="/error" />
</customErrors>

And to sum up

Pretty slick, huh?

Update

Don't forget to configure file permissions for web.config so that the ASPNET account is able to modify it.

Update #2

Unless you use wildcard mapping for all MIME types in IIS 6, you may have to set the 404 Custom Error property in IIS to an .aspx URL which does not exist. This will cause requests that are not handled by ASP.NET to trigger another request that will - and result in a 404. This 404 will in turn be handled by the custom error handling we've painstakingly implemented above! :)

09 February 2008


Comments

  1. Is this valid for all version of EPiServer or specifically for 5xx +? could I suggest that the environment this has been developed for is mentioned: - .net framework? - IIS
  2. Regarding Update #2, this results in having the querystring key aspxerrorpath to that wrong aspx page instead of the real page the user was trying to access. With "Unless you use wildcard mapping for all MIME types in IIS 6" do you mean i should remove all entries in the Applicatin extensions to make this work without using a wrongful url as a 404 page?
  3. About Redirect to other web address // html code -- http://html-lesson.blogspot.com/2008/06/redirect-to-web-addres.html
  4. I've tried implementing this method of custom error pages, however I can't seem to find the GetSimpleAddress method. Is this method just changing a normal link into a url friendly link?
  5. The GetSimpleAddress() method is not included in the source code above and is not a standard EPiServer method, but yes, it simply gets the friendly URL of a specific page. If you want the source code for that method, please see my post on getting the friendly URL of a page!
  6. "Pretty slick, huh?" No - It's 121 lines of code + several changes in the web.config + making it writable from the ASPNET account? How is that SLICK? It's horribly stupid and UN-slick. ASP.NET/EPiServer piece of crap.
  7. gS92hp llpuxknnbuyo, [url=http://bfjatxnmlmwj.com/]bfjatxnmlmwj[/url], [link=http://adhsseanljwm.com/]adhsseanljwm[/link], http://mqxrfbgbubcz.com/
  8. Hi Ted.. When I put call to above method within the Application_Start, it throws exception in the DataFactory.Instance.GetPage(new PageReference(redirectPageId)) line... It says "ClassFactory not initialized". Are you sure that you tried the call of this method from Application_Start?
  9. Vlada, I'm guessing you're running IIS7? Sounds like a configuration issue.
  10. I'm testing it in this moment... and the test is under IIS5 (XP). If test passes ok I will put it under IIS6(2003). My EPiServer version is 5.2.375.133. When I put call of above code via event like this: protected void Application_Start(Object sender, EventArgs e) { InitializationModule.FirstBeginRequest += InitializationModule_FirstBeginRequest; } void InitializationModule_FirstBeginRequest(object sender, EventArgs e) { CustomErrorsRedirector.ConfigureCustomErrors(); } or via HttpModule like this: public void Init(HttpApplication context) { EPiServer.Web.InitializationModule.FirstBeginRequest += new EventHandler(InitializationModule_FirstBeginRequest); } void InitializationModule_FirstBeginRequest(object sender, EventArgs e) { CustomErrorsRedirector.ConfigureCustomErrors(); }. it DOESN'T RAISE exception :). BUT it always enters into this ConfigureCustomErrors() method (infinite loop). Probabbly "EPiServer.Web.InitializationModule.FirstBeginRequest" has some bug in the 5.2.375.133. version. After update of EPiServer on 5.2.375.236. (5.2 SP2), it enters only one as it should be (I guess, that is the right). But, it is still the question how did you make it to work with direct call from Application_Start because if I put there call of ConfigureCustomErrors(), the "ClassFactory not initialized" will be raised again (in the newer version of EPiServer too). Please Ted, could you tell me your EPiServer version, your IIS version and exactly your code line that calls above "ConfigureCustomErrors()" within Application_Start method. Thanks
  11. Hi, I think I might be missing something because IIS is still handling the error pages. Even when I don't use your code and manually enter the error pages in web.config they aren't being hit. Any suggestions? I'm using IIS6 Thanks
Post a comment    
User verification Image for user verification  
Ted Nyberg (Ted & Gustaf)

About me

I'm an EPiServer solution architect and web developer at Ted & Gustaf in Stockholm, Sweden.

I cross-post and publish additional articles on tedgustaf.com.

You'll find my contact details here.

EMVP, EPiServer Most Valued Professional

MCPD, MCTS and MCP logos

Follow me on Twitter

Bloggtoppen.se

Add to Technorati Favorites

Syndications


Archive


Tag cloud

EPiTrace logger