I have mvc 3 application which when a Standard generic throw new Exception is thrown in code the error page from Views\Shared\error.cshtml is shown. This is done by simply setting <customErrors mode="On"/>. (This is As expected and as Desired)
The application is using WCF services in middle tier which when these services generate FaultException MVC is not showing up the error page it is showing details of the web service call to the user on screen. All I want to do is handle the error in my code and show the user the Error.cshtml. I have tried changing global asax but this dosent work.
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
if (exception.GetType() == typeof(FaultException))
{
throw new Exception("There was a fault exception that i do not want to show details of to user.");
}
}
Try creating an ErrorController as asp.net MVC will try to resolve the link you specified in the web.config as {Controller}/{View} unless you specify it to ignore that page. Also, you may want to apply an attribute to handle exceptions instead.
You can also create a error controller/view and in your catch block redirect to the custom error page of your choosing
try
{
foo.bar()
}
catch(SpecificException)
{
RedirectToAction("500", "Error");
}
Related
I saw similar post Error Handling with WCF Service and Client Application to my question but I needed more help.
I have a MVC project with the WCF Service. I understand that WCF needs to throw a FaultException. But my question is what is the best way to show the error message created by an error in WCF. I just want to redirect all the errors (possibly all FaultException) to one error page (will be generic) but message will be different.
I also would like to use [HandleError] attribute so that I don't have to implement catching FaultException for all the methods calling the WCF service.
As you know how you can handle WCF exceptions but in my opinion this is better to observe these:
1-This not good idea to show user exactly exception message, this is better to show very understandable message for example "Operation get failed there is may problem with back-end service, try again or notify admin"
2- It's is boring end user to redirect to public error page.
3- This is better show the public prompt to user which tell user that the operation get failed exactly where the user do action not redirect it to another page.
4- At the end If you want to do what you want try these:
try
{
//Call your wcf
}
catch(Exception exp)
{
//Logging.Log(LoggingMode.Error, "You message , EXP:{0}...", exp.ToString());
Response.Redirect("~/ErrorPages/Oops.aspx?Error=WCfOperationFailed", false);
}
in your error page page_load:
switch (Request.QueryString["Error"].ToString())
{
case "WCfOperationFailed":
litError.Text = string.Format("<h2>Error!.</h2><br/><p>{0}.</p>",GetError());
break;
default:
break;
}
public string GetError()
{
Exception lastError = Server.GetLastError();
return lastError.ToString();
}
or you can redirect error message as a QueryString to error page and show it to user in Page_load like:
//in catch block
Response.Redirect("~/ErrorPages/Oops.aspx?Error="+exp.Message, false);
in error page Page_load :
txtError.Text = Request.QueryString["Error"].ToString();
However, you can trap errors that occur anywhere in your application by adding code to the Application_Error handler in the Global.asax file:
void Application_Error(object sender, EventArgs e)
{
Exception exc = Server.GetLastError();
if (exc is HttpUnhandledException)
{
// Pass the error on to the error page.
Server.Transfer("ErrorPage.aspx?Error="+exc.Message, true);
}
}
This link can be helpful there are some examples
Error Handling
I have enabled the global error handling for an application by applying the HandleError attribute within the filterConfig registration.
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
I am then using the custom errors (web.config) to hopefully display a friendly error message for each server error.
<customErrors mode="On" ></customErrors>
This seemed to be working fine for most exceptions and I was getting the expected behaviour in that the custom error page View (Error.cshtml in the shared view folder) was being displayed.
However I have recently noticed that this is not the behaviour I see if the error thrown is an UnauthorizedAccessException.
I am a bit stumped with this, as looking in fiddler I see that this UnauthorizedAccessException exception returns a plain 500 internal server error as a standard exception does.
So how come the standard exception abides by my customError setup but the UnauthorizedAccessException does not?
ANd how can I get them to behave the same, as they are both essentially an error which I want to prevent the end user from seeing.
This blog post provided me with the overview of exception handling to enable me to decide how to handle the unauthorizedAccessException, which essentially means handling them within the Application_OnStart.
http://prideparrot.com/blog/archive/2012/5/exception_handling_in_asp_net_mvc
For my purposes there doesn't seem much point in handling the errors with the HandleErrorAttribute and in the global Application_OnStart so for my purposes I decided it was best to handle everything in the Application_OnSTart,
If you just want to force 'unhandled' exceptions like UnauthorizedAccessException to go through the normal custom-error page then you can override the controller's OnException method similar to the following:
protected override void OnException(ExceptionContext filterContext)
{
base.OnException(filterContext);
if (!filterContext.ExceptionHandled && filterContext.RequestContext.HttpContext.IsCustomErrorEnabled)
{
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
filterContext.Result = View("Error",
new HandleErrorInfo(filterContext.Exception, filterContext.GetCurrentControllerName(), filterContext.GetCurrentActionName()));
}
}
The article that you referenced is an excellent resource for a more thorough explanation of error-handling techniques, though, and should be considered as well.
I am initializing FluentNHibernate from Application_Start event like so:
Fluently.Configure()
.Database(OracleDataClientConfiguration.Oracle10
.Driver<NHibernate.Driver.OracleDataClientDriver>()
.ConnectionString("MyConnectionString")
.DefaultSchema("MySchema")
)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<SomeClass>())
.BuildConfiguration()
.BuildSessionFactory();
If the connection string is bad, or connection to the DB fails for some other reason, I get a TNS No listener exception. I would like to display/log this exception but Application_Start (and Applicaiton_Error) doesn't have an HttpContext or Response object in IIS7 Integrated mode. The user gets a yellow screen of death telling them to turn custom errors On. Elmah doesn't log the message either. I would like to solve the problem in one of two possible ways:
Disable nhibernate configuration from connecting to the database on configuration.
Provide custom user feedback based on the error and get Elmah working (somehow). This would be my ideal choice.
I was able to move NHibernate configuration to run on Session_Start, as described here, which gets exception handling working for this error, but then I get other exceptions that can be misleading to the root cause of the problem. Does anyone have a good solution for this scenario?
Thank you.
This is what I do:
void Application_Start() {
try {
// setup your app / nhibernate
} catch(Exception ex) {
Application["StartupError"] = ex
}
}
void Application_BeginRequest() {
var startupError = Application["StartupError"] as Exception;
if (startupError != null)
throw new Exception("Error starting application", startupError);
}
In your BeginRequest method you have access to the Request and can do what you want to show the error (or show a nice page)
I have read articles on exception handling in ASP.NET MVC. I want to make sure I am doing right by presenting it briefly. Could anyone please comment.
Catch the exceptions in controller actions, if necessary.
[HttpPost]
public ActionResult Insert()
{
try
{
}
catch
{
//ModelState.Error -> display error msg to the user.
}
}
Override the "OnException" method of controller in basecontroller and "log" the exceptions raised in step 1 and other MVC exceptions
Logged the global exceptions in application_onerror.
I would definitely recommend ELMaH instead of writing this code yourself, and also over Log4Net for your MVC apps. I personally avoid any exception handling, unless I have a specific functional response to it. In this way, I don't "eat" any of the errors that an application-wide tool such as ELMaH will handle gracefully for me.
ELMaH also has nice built-in web reporting, and there are third-party tools specifically for ELMaH that can give you statistics, e.g. the most frequent errors.
You might start with a custom error redirect...
<customErrors defaultRedirect="~/site/error" mode="RemoteOnly">
<error statusCode="404" redirect="~/site/notfound" />
</customErrors>
...to a controller that is aware you are using ELMaH...
public virtual ActionResult Error() {
System.Collections.IList errorList = new System.Collections.ArrayList();
ErrorLog.GetDefault(System.Web.HttpContext.Current).GetErrors(0, 1, errorList);
ErrorLogEntry entry = null;
if (errorList.Count > 0) {
entry = errorList[0] as Elmah.ErrorLogEntry;
}
return View(entry);
}
...backed by a view that helps the visitor get the specific error ID to you:
#model Elmah.ErrorLogEntry
#if (Context.User.Identity.IsAuthenticated) {
<p>Since you are signed in, we've noted your contact information,
and may follow up regarding this to help improve our product.</p>
} else {
<p>Since you aren't signed in, we won't contact you regarding this.</p>
}
<p>Error ID: #Model.Id</p>
I also notice this is an HttpPost in this example. If you are doing AJAX, then you'll want to handle errors for those in a unique way. Pick a standard response you can send to browsers that all of your AJAX code handles gracefully. Perhaps by displaying the ELMaH error ID in a javascript alert (as a simple example).
I also handle a few special types of AJAX errors via Global.asax:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302 &&
Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
HandleErrorAttribute is a nice feature, but it is well-known that there is extra work to use it in conjunction with ELMaH. How to get ELMAH to work with ASP.NET MVC [HandleError] attribute?
If you want handle exceptions in your Actions you can override "OnException" in your Controller like so:
protected override void OnException(ExceptionContext filterContext)
{
logging or user notification code here
}
You can put it in your BaseController class to prevent duplication
try and catch are for expected exceptions ie your user has entered a file name and it might not exist so you want to catch the FileNotFoundException.
For unexpected exceptions use either the Error event in the MvcApplication object e.g.
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
this.Error += MvcApplication_Error;
// Other code
}
private void MvcApplication_Error(object sender, EventArgs e)
{
Exception exception = this.Server.GetLastError();
// Do logging here.
}
}
or as Dima suggested you have controller level execption handling using
protected override void OnException(ExceptionContext filterContext)
{
// Do logging here.
}
Keep the trys and catches on code where you want to catch something expected and can handle.
"Generic" error handling just obfuscates the underlying problem, which you will have to dig for later.
I am using the following code to capture exceptions in the application, and save them in the Session object. The exception is then retrieved from Session in the error handler page to which the app automatically redirects:
protected virtual void Application_Error(Object sender, EventArgs e)
{
try
{
Exception ex = Server.GetLastError();
Session["exception"] = ex;
}
catch { }
}
I have one problem with this code:
Session is not available if a malformed path gets in: "example.com/"foo" - Exception is thrown when accessing it, and NULL is retrieved from Session object in the error page
What is a better way to save exception information in the application and pass it to the error handler action?
If you are trying to log exceptions then take a look at the elmah project.
Scott Hanselman has a good introduction
If you can't use ELMAH for any reason,
http://www.genericerror.com/blog/2009/01/27/ASPNetMVCCustomErrorPages.aspx