Redirecting user to dynamic error page - asp.net

Can I configure ASP.NET custom errors so that it would redirect to other site when error has occurred. Even more, I would like to redirect to different web page every time.
Here is my simplified actual case:
User opens my pages with query ?urlpage=http://test.com/error.html and I would like to redirect to this page when error occurs.
How should I act in this scenario?

See http://msdn.microsoft.com/en-us/library/ed577840.aspx
And in the Page_Error method, just do:
var redirectUrl = Request.QueryString["urlpage"];
if (redirectUrl != null)
Response.Redirect(redirectUrl);

There are a number of different resources in ASP.NET that will allow you to handle errors.
I found this article on the web.config file very informative : http://articles.sitepoint.com/article/web-config-file-demystified
In addition you can setup error handling inside of the global.asax file that will trap application wide errors and allow you to send emails, log information, etc.
You can also setup page specific error handling for more custom error information - but I find that a good general purpose error handling in global.asax works for most situations.
Finally, you can go into the properties for IIS and modify where errors are redirected. For instance, set the 500 error to point to a specific file (/error.aspx or similar).

Related

ASP.NET MVC, CustomErrors & ResponseRewrite

I have an MVC website (v5, though I don't think it's related) where I have intentionally introduced an error upon when attempting to establish a database connection (wrong server IP in the connection string). When the user hits the HomeController one dependencies for the constructor is a UserRepository (to get the current user profile data) which depends on a database connection/session to be available. When it's not, the Dependency Resolver can't inject the UserRepository and when that happens it causes an error (as it does with any dependency of any controller), and I get a generic "No parameterless constructor defined for this object". Which is pretty useless.
So I'm trying to use a custom error page to retrieve the inner exception and display it in a friendly manner. (Because this error is happening when trying to acquire the HomeController, it never actually reaches the HandleErrorAttribute, hence the relying on CustomErrors).
So I have an ErrorsController with a series of actions...
Snippet from ErrorsComtroller.cs
public ActionResult Error()
{
return View("Error_500");
}
public ActionResult NotFound()
{
return View("Error_404");
}
Snippet from web.config
<customErrors mode="On">
<error statusCode="404" redirect="~/errors/notfound" />
<error statusCode="500" redirect="~/errors/error" />
</customErrors>
The Error_500 page is pretty basic, it has a model type of HandleErrorInfo, but if it's not present it checks for Exception details using Server.GetLastError(). Problem is, GetLastError() is always null, and I get my custom error page but no additional details beyond my generic feedback of "An unexpected error has occured". After doing some digging I found that the method doesn't work after a redirect, which is the default way the CustomErrors functions. So I changed the web.config to use this line instead...
Snippet from web.config
This way it won't cause a redirect and the GetLastError() should have my exception details about the database connection problem. Thing is, now I get the default ASP.NET error page with this message.
An exception occurred while processing your request. Additionally,
another exception occurred while executing the custom error page for
the first exception. The request has been terminated.
So I did some more digging using intellitrace, and I see the exception about the database connection. A little farther down I see the error about not having a parameterless constructor on HomeController and then one about encountering an error trying to create the controller of type 'HomeController'. But then I see one that says
Error executing child request for /errors/error
So I navigated directly to that path and the page works fine. But when it's used in customerrors WITH the ResponseRewrite for the redirectmode, it errors out. I put a break line on the first (and only) line of the ErrorsController.Error() action, but it never gets hit. If I substitute the redirect path in the custom errors to a static file it works, but if I change it back to the ~/errors/error it fails again.
Is there a issue when using MVC actions as url's for the CustomErrors when ResponseRewrite is specified?
"This happens because "ResponseRewrite" mode uses Server.Transfer under the covers, which looks for a file on the file system. As a result you need to change the redirect path to a static file, for example to an .aspx or .html file:"
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx"/>
See: https://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging
"Apparently, Server.Transfer is not compatible with MVC routes, therefore, if your error page is served by a controller action, Server.Transfer is going to look for /Error/Whatever, not find it on the file system, and return a generic 404 error page!"
See: CustomErrors does not work when setting redirectMode="ResponseRewrite"
In other words, you cannot use ResponseRewrite with views.
This is a well known issue that has been problematic for developers because it does not afford itself to either an easy or elegant solution. Bottom line, MVC does not play nice when using custom views for exception handling and customer user-friendly pages for HTTP errors. The stock error.cshtml file (i.e., a View) in the Views\Shared folder is a great thing to have because it maintains the layout of the web page and provides exception errors. But, when you get HTTP errors then you need to create a view to handle the status code errors (e.g., 404, 500, etc.). Note: if you go the route of sending HTTP errors to a view then the URL line will contain non-ideal info (see weblinks below for further explanation).
You could route HTTP errors to the Error view, but I don't recommend it because the Error view should be for application errors (i..e, exceptions) whereas a separate custom user-friendly page should be created for generic HTTP errors. The difference is that the former is an application problem that the site developer needs to look at whereas the latter is a user error (or at least should be) that does not require the developer to look at it (just my 2 cents).
An alternative is to bypass the views and use custom user-friendly pages for both application exceptions and HTTP errors. But, beware of two problems:
1.) The wrong status code is returned (usually 200), which can be a problem because it will be picked up and indexed by search engines (you do not want this!)
2.) The URL specifies a non-sensical URL in the web browser
These can be handled easy enough. See the following link (go down to the section customErrors in web.config): https://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging
Below are other weblinks that I also found useful:
http://benfoster.io/blog/aspnet-mvc-custom-error-pages
https://msdn.microsoft.com/en-us/library/bb397417.aspx
https://www.youtube.com/watch?v=nNEjXCSnw6w
How do I display custom error pages in Asp.Net Mvc 3?
The last one appears to be yet another alternative: a custom hack to get around the problem of not being able to couple views with ResponseRewrite. This works by completely bypassing CustomErrors (i.e., CustomErrors mode="Off"). I have not yet tried this yet, but I am looking into it.
Final thought, keep an eye on all site status codes when either error or exception codes are thrown - make sure there are no 200 (i.e., OK) codes.

Passing Exception Information from Global.asax to ErrorPage.aspx

I have a global error handler in Global.asax and am trying to display the exception information in a page called ErrorPage.aspx. I've read Microsoft's page about passing information between asp.net pages (http://msdn.microsoft.com/en-us/library/6c3yckfw.aspx). I don't think any of these will work:
QueryString: I'm concerned that the length of the exception will
exceed the maximum length of the QueryString.
Post Information: The Global.asax page doesn't have any form fields.
Session State: Session state is not available in Global.asax
Public Values: I think this only works with .aspx pages
Control from Source Page: Global.asax can't have asp.net controls.
My current thought is that it would be logical to create an instance of the ErrorPage object and navigate to it (as you could do in a Windows Forms application), but I don't know how to do that or if it is possible in asp.net.
Ultimately, I'm looking for a way to display errors caught by a global error handler in a standard .aspx page. Any suggestions would be helpful.
What I would do:
Log exception information including stack trace in a log file,
Redirect to an ErrorPage with error code (regular http errorcodes + a generic 'unknown error' one + maybe some custom errors that make sense for the application) passed in query string parameter,
Display a predefined message for this error code.
There is little reason to display actual error messages to end users, more detailed error information not withstanding. If you want to display full information for debugging purposes, turn custom errors off in web.config

ASP.NET where does throw new exception error get displayed

Code snippet..
if (regionalApprover == null)
{
throw new Exception(string.Format("The regional approver for {0} could not be found", companyData["Country"]));
}
How does the user actually see this error ?
The result of an unhandled exception depends on a variety of factors, including
where the web request is coming from,
the settings of the <customErrors> Element in your web.config and
the contents of Application_Error in your global.asax codebehind file.
In the default configuration, IIS will log the error into the Windows event log. In addition, it is shown in the browser by ASP.NET if the web request comes from localhost.
If you're trying to display an error message on the page (that the user is supposed to see), don't use Exceptions.
It's a much better idea to add an errors section to the page that you can add the messages to before showing the page to the user.

Exception handling in ASP.NET Webforms

What is the preferred method for handling exceptions in ASP.NET Webforms?
You have the Page_Error method that you add (I think) at web.config level, and the entire site gets redirected there when an error occurs.
Does that mean you shouldn't use try-catch anywhere in a webforms application? (Assuming you don't want to hide any errors)
Only catch the errors you can handle. If you can handle them in a manner that allows the page to continue loading then do so. Any other exception that would wreck the page should not be handled in any control or page as you would not be able to do anything anyways. Let it go to the global.asax handler and make sure you log the exception.
In addition to Andrew's suggestion, make sure to update the web.config file to set CustomErrors to "On" and specify a generic error page to redirect these top level errors. Global_asax will still log the error, and then the user can see a friendly page. It will also allow you to configure a few of the standard type errors, such as 404s and 200s, plus much more.
Web Application will normally consists of UI, Business and Data access layer.Each layer must do its part regarding exception handling. Each layer must (for code re usability) check for error condition and wrap exception(after logging it) and maybe propagated to the calling layer. The UI layer should hide exception and display a friendly message. Catching all exception in UI maybe not a good idea. Exceptions if possible should be logged in Database. This will allow ease of maintainence and correction of bugs
Avoid catching exceptions as far as possible. Try and validate all inputs before you use them. Rigorously validation( both client and server side) inputs with help of validation controls, custom controls and regular expression is a must.
string fname = "abc";
//Always check for condition, like file exists etc...
if (System.IO.File.Exists(fname))
{
}
else
{
}
Always make sure clean up code is called. Using statement or try finally.
You can catch all exceptions in Global.asax (asp.net application file)
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
Exception objErr = Server.GetLastError().GetBaseException();
string err = "Error Caught in Application_Error event\n" +
"Error in: " + Request.Url.ToString() +
"\nError Message:" + objErr.Message.ToString()+
"\nStack Trace:" + objErr.StackTrace.ToString();
EventLog.WriteEntry("Sample_WebApp",err,EventLogEntryType.Error);
Server.ClearError();
//additional actions...
}
and add <customerror> section in your web config to redirect user to a separate page
<customErrors defaultRedirect="error.htm" mode="On">
</customErrors>
Useful links
MSDN
MSDN
Exception Logging- Peter Bromberg
You should use try/catch in places where you can do something meaningful with error, like fixing it or taking a different approach.
For all other cases you should use global try/catch using web.config custom errors page or Application_Error event to log the error and possibly to show it to the user.
If you use validation controls or check and validate user input in your code behind that will go a long way to preventing errors. I do recommend having a generic error page that can log the error for you. In cases where you are unsure of what will happen i suggest catching the error and handling it if at all possible and work on finding a way to know that what you are going to run will work before doing it.
Do you have a specific example in mind of where you might expect to encounter an error of this sort. One that I know of is when a session expires and you can no longer process the page. I check for this on every page load before anything else is run and then redirect the user if this has occurred.

ASP.Net MVC Authorisation action filter

I'm trying to understand how error handling works when using the Authorize [Authorize] Action Filter in MVC Preview 4.
I have an action that looks like this:
[Authorize(Roles = "DOMAIN\\NOTAUTHORISED_ROLE" )]
[HandleError]
public ActionResult NeedAuthorisation()
{
throw new NotImplementedException();
}
When I visit the url: http://localhost:2197/testAuthorisation/NeedAuthorisation, I get a blank page in my browser. In Firebug I can see that a request was made and a response-status of 401 - Unauthorised has been returned. But I'm not being redirected or having a customError returned. Everything works as expected when using a role that I'm authorized for.
This is using Windows authentication. I'm in the middle of writing some code to try out Forms authentication to see if I get the same issue.
I have <customerrors mode="On"/> set and have created error pages, both in the testAuthorisation folder and the Shared folder.
I eventually found this MVC tutorial which solved my problem:
Exactly what happens when you attempt to invoke a controller action
without being the right permissions depends on the type of
authentication enabled. By default, when using the ASP.NET Development
Server, you simply get a blank page. The page is served with a 401 Not
Authorized HTTP Response Status.
If you've got CustomErrors set to Off or RemoteOnly then you won't get re-directed to the page specified by HandleError (default is Error.aspx). Set it to "On" and then see what happens. Any custom error pages you specify explicitly will take precedence, however, so you need to remove these, and have just:
<customErrors mode="On" />
You need an error view in the corresponding view folder, i.e. you need the file Views/TestAuthorization/Error.aspx in order to have anything show up.
You can also customize this behaviour by what view that you want to use and to what exception you want it to be triggered with.
[HandleError(ExceptionType = typeof(SqlException), View = "DatabaseError")]]
[HandleError(ExceptionType = typeof(NullReferenceException), View = "LameErrorHandling")]]

Resources