I implemented a custom error handler for my MVC5 project and everything would be fine if it wasn't of the customErrors attribute. I'll explain: When I got an error in the application, I catch it inside void Application_Error from Global.asax like this:
protected void Application_Error(object sender, EventArgs e)
{
var httpContext = ((HttpApplication)sender).Context;
ExecuteErrorController(httpContext, Server.GetLastError());
}
public static void ExecuteErrorController(HttpContext httpContext, Exception exception)
{
if (!exception.Message.Contains("NotFound") && !exception.Message.Contains("ServerError"))
{
var routeData = new RouteData();
routeData.Values["area"] = "Administration";
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "Insert";
routeData.Values["exception"] = exception;
using (Controller controller = new ErrorController())
{
((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
}
}
}
Then, inside my ErrorController I do:
public ActionResult Insert(Exception exception)
{
ErrorSignal.FromCurrentContext().Raise(exception);
Server.ClearError();
Response.Clear();
switch (Tools.GetHttpCode(exception)) // (int)HttpStatusCode.NotFound;
{
case 400:
return RedirectToAction("BadRequest");
case 401:
return RedirectToAction("Unauthorized");
case 403:
return RedirectToAction("Forbidden");
case 404:
return RedirectToAction("NotFound");
case 500:
return RedirectToAction("ServerError");
default:
return RedirectToAction("DefaultError");
}
}
public ActionResult Unauthorized()
{
return View();
}
...
So the first time, everything works perfectly
But !! The code repeat itself because the NotFound or ServerError page aren't in the Shared folder. Those page are supposed to be set in customErrors attribute BUT the thing is I don't need it at all. I finally got this error: ERR_TOO_MANY_REDIRECTS because of that.
I read all day to find any answer about that, and it seams that everyone who published their code do the same kind of pattern as mine, and no matter what I tried, nothing works.
Notice my desperate if condition: if (!exception.Message.Contains("NotFound") && !exception.Message.Contains("ServerError"))
I also comment those two lines in the global.asax because everywhere I read, it says we need to remove them in order to get this done.
//GlobalConfiguration.Configure(WebApiConfig.Register);
//FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
Also, because of the desparate if, I got this answer:
Runtime Error
Description: An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed.
Details: To enable the details of this specific error message to be viewable on the local server machine, please create a <customErrors> tag within a "web.config" configuration file located in the root directory of the current web application. This <customErrors> tag should then have its "mode" attribute set to "RemoteOnly". To enable the details to be viewable on remote machines, please set "mode" to "Off".
<!-- Web.Config Configuration File -->
<configuration>
<system.web>
<customErrors mode="RemoteOnly"/>
</system.web>
</configuration>
I also tried Response.TrySkipIisCustomErrors = true; and it doesn't work!
So, how can I get ride of customErrors completely and manage my own error handler in my project?
Alright, thanks to the comment of RoteS. I finally found what I need to get this done !
The way I did it by Executing the ErrorController wasn't good.
using (Controller controller = new ErrorController())
{
((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
}
I found that by using ServerTransfert instead, we can get ride of customErrors attribute. Here is the final solution (tested):
protected void Application_Error(object sender, EventArgs e)
{
// Response.TrySkipIisCustomErrors = true; I don't know if I will need it someday.
var httpContext = ((HttpApplication)sender).Context;
var exception = Server.GetLastError();
ErrorSignal.FromCurrentContext().Raise(exception);
Server.ClearError();
Response.Clear();
string relativePath = "~/Administration/Error/{0}";
switch (Tools.GetHttpCode(exception))
{
case (int)HttpStatusCode.BadRequest:
Server.TransferRequest(string.Format(relativePath, "BadRequest"));
break;
case (int)HttpStatusCode.Unauthorized:
Server.TransferRequest(string.Format(relativePath, "Unauthorized"));
break;
case (int)HttpStatusCode.Forbidden:
Server.TransferRequest(string.Format(relativePath, "Forbidden"));
break;
case (int)HttpStatusCode.NotFound:
Server.TransferRequest(string.Format(relativePath, "NotFound"));
break;
case (int)HttpStatusCode.InternalServerError:
Server.TransferRequest(string.Format(relativePath, "ServerError"));
break;
default:
Server.TransferRequest(string.Format(relativePath, "DefaultError"));
break;
}
}
Thanks to RoteS for the comment that pointed me in the right direction.
David
Related
I am developing an API using C# and .net 4.5.2; The API methods can return a handled BadRequest error or OK with an object response as per the below example:
[Authorize]
[RoutePrefix("api/Test")]
public class TestController : ApiController
{
[HttpGet]
[Route("TestMethod")]
public IHttpActionResult TestMethod()
{
MyProvider op = new MyProvider();
var lstResults = new List<Result>();
try
{
lstResults = op.TestMethod();
}
catch (Exception ex)
{
return BadRequest(ParseErrorMessage(ex.Message.ToString()));
}
return Ok(lstResults);
}
}
All errors are returned in a message object as below JSON:
{
Message: "Username or password is incorrect!"
}
The above was working perfectly until we added the below new configuration to redirect all 404 errors to a custom page for security issues. Now anybody (more specifically a hacker) who tries to call the API randomly, will be redirected to a custom 404 error page instead of the original .NET 404 page.
Web.config:
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<error statusCode="404" path="404.html" responseMode="File"/>
</httpErrors>
The problem is:
BadRequest errors are not handled anymore as it was mentioned in the beginning, the custom JSON structure is not returned anymore, custom messages like "Username or password is incorrect!" are not taken into consideration, just the same simple text is always returned: Bad Request as per below screenshot:
The solution should be running on windows server 2016 IIS version 10.
How to solve the issue by keeping both working?
Update:
If I remove existingResponse="Replace", the badrequest message is returned, but the 404 custom error is not working anymore as per below screenshot
If I set errorMode="Detailed" the 404 custom error won't work anymore, and HTML description is returned for a bad request as you can see here:
I ended up using the below to solve the issue; Thus I won't mark it as the perfect answer since it didn't solve the above issue and I didn't know yet why the configuration did not work properly as excepted. So any answer that can solve the issue is more than welcomed, below is what worked as excepted for me:
Remove the httpErrors configuration from web.config
Use Global.asax file and add the below method to handle any error not handled in the API solution:
protected void Application_Error(object sender, EventArgs e)
{
try
{
try
{
Response.Filter = null;
}
catch { }
Exception serverException = Server.GetLastError();
//WebErrorHandler errorHandler = null;
//Try to log the inner Exception since that's what
//contains the 'real' error.
if (serverException.InnerException != null)
serverException = serverException.InnerException;
// Custom logging and notification for this application
//AppUtils.LogAndNotify(new WebErrorHandler(serverException));
Response.TrySkipIisCustomErrors = true;
string StockMessage =
"The Server Administrator has been notified and the error logged.<p>" +
"Please continue on by either clicking the back button or by returning to the home page.<p>";
// Handle some stock errors that may require special error pages
var HEx = serverException as HttpException;
if (HEx != null)
{
int HttpCode = HEx.GetHttpCode();
Server.ClearError();
if (HttpCode == 404) // Page Not Found
{
Response.StatusCode = 404;
//Response.Write("Page not found; You've accessed an invalid page on this Web server. " + StockMessage);
Response.Redirect("404.html");
return;
}
}
Server.ClearError();
Response.StatusCode = 500;
// generate a custom error page
Response.Write("Application Error; We're sorry, but an unhandled error occurred on the server." + StockMessage);
return;
}
catch (Exception ex)
{
Server.ClearError();
Response.TrySkipIisCustomErrors = true;
Response.StatusCode = 500;
Response.Write("Application Error Handler Failed; The application Error Handler failed with an exception.");
}
}
It worked like a charm:
user is redirected to 404.html custom page
Any 400 error is being thrown properly with the JSON format and proper message
I've developed an MVC 4 site which runs correctly on my local Win 7 workstation. My workstation has MVC 4 installed as part of the Visual Studio 2010 bolt-on.
I've deployed the app to my DEV server, which is Windows Server 2008 R2. Note that MVC 4 is NOT installed onto the DEV server, instead the app uses the MVC bin deployables. In some cases my error controller gets called but I'm not sure why. Here's the exception:
System.InvalidOperationException: The view 'Error' or its master was
not found or no view engine supports the searched locations. The
following locations were searched:
~/Views/Customer/Error.cshtml
~/Views/Customer/Error.vbhtml
~/Views/Shared/Error.cshtml
~/Views/Shared/Error.vbhtml
The stack trace does not show any line numbers as to where the exception originates. By the exception it appears MVC is expecting to find view associated with the Customer controller first then checks shared. However, there is no view in either path and there SHOULDN'T be.
The site uses a global error handler via Application_Error in global.asax.cs:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError().GetBaseException();
ILogger httplog = new HttpLogIt(new HttpContextWrapper(Context));
if (new HttpRequestWrapper(Request).IsAjaxRequest())
{
httplog.Error(1, Enums.ErrorCode.INTERNAL_SERVER_ERROR, "An application error occurred during an AJAX request. See exception for details.", ex, false);
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
Response.ContentType = "application/json";
Response.Write(new JavaScriptSerializer().Serialize(new
{
errorMessage = "We apologize, the website has experienced an error. Please try again."
}));
return;
}
else
{
httplog.Error(1, Enums.ErrorCode.INTERNAL_SERVER_ERROR, "An application error occurred. See exception for details.", ex, false);
}
Response.Clear();
// Clear the error on server.
Server.ClearError();
// Avoid IIS7 getting in the middle
Response.TrySkipIisCustomErrors = true;
// try to send error info to Error controller
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
// maintain current url, even if invalid, when displaying error page
routeData.Values.Add("url", Context.Request.Url.OriginalString);
if (ex is HttpException)
{
HttpException httpException = ex as HttpException;
switch (httpException.GetHttpCode())
{
case 404:
// Page not found.
routeData.Values.Add("action", "Http404");
break;
default:
routeData.Values.Add("action", "Unavailable");
break;
}
}
else
{
routeData.Values.Add("action", "Unavailable");
}
// Pass exception details to the target error View.
var model = new HandleErrorInfo(ex, routeData.Values["controller"].ToString(), routeData.Values["action"].ToString());
routeData.Values.Add("errorinfo", model);
// Call target Controller and pass the routeData.
IController errorController = new ErrorController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
The re-route from the global handler to the Error controller lands in the the Error controller where it explicitly sets the views to use:
[SessionState(SessionStateBehavior.Disabled)]
public class ErrorController : Controller
{
private ILogger _httplog;
public ErrorController()
{
_httplog = new HttpLogIt(this.HttpContext, this.RouteData);
}
public ActionResult Http404()
{
if (this.ControllerContext.RouteData.Values["errorinfo"] != null)
{
HandleErrorInfo errorinfo = null;
errorinfo = (HandleErrorInfo)this.ControllerContext.RouteData.Values["errorinfo"];
_httplog.Warn(1, Enums.WarningCode.PAGE_NOT_FOUND, "A global application exception was handled and the end user was redirected to the Error Controller with Http404 Action.");
}
Response.StatusCode = (int)HttpStatusCode.NotFound;
// explicitly set the View below
return View("Error404");
}
public ActionResult Http500()
{
if (this.ControllerContext.RouteData.Values["errorinfo"] != null)
{
HandleErrorInfo errorinfo = null;
errorinfo = (HandleErrorInfo)this.ControllerContext.RouteData.Values["errorinfo"];
_httplog.Error(1, Enums.ErrorCode.INTERNAL_SERVER_ERROR, "A global application exception was handled and the end user was redirected to the Error Controller with Http500 Action.", errorinfo.Exception, true);
}
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
// explicitly set the View below
return View("Unavailable");
}
public ActionResult Unavailable()
{
if (this.ControllerContext.RouteData.Values["errorinfo"] != null)
{
HandleErrorInfo errorinfo = null;
errorinfo = (HandleErrorInfo)this.ControllerContext.RouteData.Values["errorinfo"];
_httplog.Error(1, Enums.ErrorCode.INTERNAL_SERVER_ERROR, "A global application exception was handled and the end user was redirected to the Error Controller with Unavailable Action.", errorinfo.Exception, true);
}
Response.StatusCode = (int)HttpStatusCode.OK;
// explicitly set the View below
return View("Unavailable");
}
}
I added add'l logging in each method to try to find the culprit but to no avail. What's odd is that, thru adding extra logging, the global error handler is NOT firing when this exception is thrown and logged!
Has anyone encountered something like this?
Try to add this line in your web.config
<customErrors mode="On" />
Added some more logging and found the culprit. In the Error controller, Http404 action, I added the following logging block
_httplog.Info(String.Format("Controller is {0}, Action is {1} and URL is {2}.",
RouteData.Values["controller"].ToString(),
RouteData.Values["action"].ToString(),
RouteData.Values["url"].ToString()));
The resulting log showed:
Message: Controller is Error, Action is Http404 and URL is __utm.gif.
This is a Google Analytics image file and I had seen this gif call in my server dumps during performance monitoring, however, didn't correlate it with my Error controller firing. Since my site is a subsite and the parent site uses GA, the urchin script was enabled in the DEV env.
Here's why it fired - in the RouteConfig.cs, the very last entry handles all bad URLs and routes them to the Error controller, Http404 action, like so:
routes.MapRoute("BadRoute", "{*url}", new { controller = "Error", action = "Http404" });
This is to handle any bad URL path and keep the current URL in place - instead of showing an IIS 404 or a customerror html page.
This answers the question as to why my Error controller got called outside of the code, however does not answer why the MVC framework went looking for a different error controller with a matching default view. The fix for that entailed disabling the following line in my FilterConfig.cs
filters.Add(new HandleErrorAttribute());
This was firing despite the app handling errors in the global.asax. Hope this helps!
I've made some modifications to Global.asax so that I can show custom error pages (403, 404, and 500) Here's the code:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
//FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
protected void Application_Error(object sender, EventArgs e)
{
if (Context.IsCustomErrorEnabled)
{
ShowCustomErrorPage(Server.GetLastError());
}
}
private void ShowCustomErrorPage(Exception exception)
{
HttpException httpException = exception as HttpException;
if (httpException == null)
{
httpException = new HttpException(500, "Internal Server Error", exception);
}
Response.Clear();
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("fromAppErrorEvent", true);
switch (httpException.GetHttpCode())
{
case 403:
routeData.Values.Add("action", "AccessDenied");
break;
case 404:
routeData.Values.Add("action", "NotFound");
break;
case 500:
routeData.Values.Add("action", "ServerError");
break;
default:
routeData.Values.Add("action", "DefaultError");
routeData.Values.Add("httpStatusCode", httpException.GetHttpCode());
break;
}
Server.ClearError();
IController controller = new ErrorController();
controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
}
I've also added the following to my Web.Config:
<customErrors mode="On">
<!-- There is custom handling of errors in Global.asax -->
</customErrors>
The custom error pages show up correctly, and ELMAH will correctly log the error that was (purposefully) thrown. But ELMAH also catches and logs an additional error:
System.InvalidOperationException: The view 'Error' or its master was not found or no view engine supports the searched locations. The following locations were searched: ~/Views/account/Error.aspx ~/Views/account/Error.ascx ~/Views/Shared/Error.aspx ~/Views/Shared/Error.ascx ~/Views/account/Error.cshtml ~/Views/account/Error.vbhtml ~/Views/Shared/Error.cshtml ~/Views/Shared/Error.vbhtml
My first instincts led me to disabling the global HandleErrorAttribute in the filter configuration. And, similar SO questions such as:MVC problem with custom error pages led me to believe my suspicions were right. But even after disabling the global HandleErrorAttribute I am still getting the Error that the Error view could not be found! What gives? My only other hunch is that my base controller derives from System.Web.Mvc.Controller I tried to examine the source to see if the HandleErrorAttribute is applied to System.Web.Mvc.Controller but couldn't glean anything...
UPDATE:
I tried overriding my base controller to mark exceptions as handled like this:
protected override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
base.OnException(filterContext);
}
but that didn't solve the problem.
UPDATE2:
I placed an Error.aspx file into the shared views, just to see what would happen. When it's there, ELMAH logs the forced exception, and then the shared view is served up - it never reaches Application_Error() .... not too sure what to make of it.
Finally got it working to my satisfaction...
The Elmah.Mvc package applies a "hidden" error handler. I've disabled this by adding the following line in web.config <appSettings> (the value was set to "false" by default from nuget install)
<add key="elmah.mvc.disableHandleErrorFilter" value="true" />
So, now my errors propagate up to Application_Error and are logged by Elmah, bypassing the Elmah filter, and display the proper error page (not the one in /shared/error.cshtml)
If you are running in IIS 7 integrated mode, you will need to add Response.TrySkipIisCustomErrors = true; in Application_Error. Otherwise IIS will still redirect the client to a custom error page, despite anything you do in code.
See here for additional details: http://www.west-wind.com/weblog/posts/2009/Apr/29/IIS-7-Error-Pages-taking-over-500-Errors
Edit: here's the body of my Application_Error:
if (HttpContext.Current != null)
{
Server.ClearError();
Response.TrySkipIisCustomErrors = true;
RouteData data = new RouteData();
data.Values.Add("controller", "Error");
data.Values.Add("action", "Error");
IController controller = new MyApp.Controllers.ErrorController();
controller.Execute(new RequestContext(new HttpContextWrapper(Context), data));
}
I am using ASP.NET MVC3 and running the website on Windows Server 2003. I'm trying to figure out how to handle all HTTP errors. I have implemented code but I sometimes get a 403 error displayed in the browser when a 404 error is returned.
Here is my code that I have implemented:
In my global.asax.cs:
protected void Application_Error(object sender, EventArgs e)
{
MvcApplication app = (MvcApplication)sender;
HttpContext context = app.Context;
Exception exception = app.Server.GetLastError();
context.Response.Clear();
context.ClearError();
HttpException httpException = exception as HttpException;
RouteData routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "Index";
routeData.Values["httpException"] = httpException;
Server.ClearError();
IController errorController = new ErrorController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
ErrorController.cs file:
public class ErrorController : Controller
{
public ActionResult Index()
{
ErrorModel model = new ErrorModel();
HttpException httpException = RouteData.Values["httpException"] as HttpException;
int httpCode = (httpException == null) ? 500 : httpException.GetHttpCode();
switch (httpCode)
{
case 403:
//Response.StatusCode = 403;
model.Heading = "Forbidden";
model.Message = "You aren't authorised to access this page.";
break;
case 404:
//Response.StatusCode = 404;
model.Heading = "Page not found";
model.Message = "We couldn't find the page you requested.";
break;
case 500:
default:
Response.StatusCode = 500;
model.Heading = "Error";
model.Message = "Sorry, something went wrong. It's been logged.";
break;
}
Response.TrySkipIisCustomErrors = true;
return View(model);
}
}
I have nothing set in my web.config.
I want it to display the correct error when the user is trying to access my directories such as app_code and similar directories. Is this possible?
When I type in http://localhost:43596/app_code then I see that it seems to be a 404 error but it displays the default 403 error page of IE. How do I get my code to display the correct HTTP error message?
The reason why I want it this way is because I need to log all attempts if a user is trying to sabotage the site in any way. I want to be able to see who is doing the wrong accessing.
When I type in http://localhost:43596/app_code then I see that it
seems to be a 404 error but it displays the default 403 error page of
IE.
What's wrong with 403?
In the HTTP used on the World Wide Web, 403 Forbidden is an HTTP
status code returned by a web server when a user requests a web page
or media that the server does not allow them to access. In other
words, the server can be reached, but the server declined to allow
access to the page. Microsoft IIS responds in
the same way when directory listings are denied.
Wikipedia
When an user is trying to access the App_Data folder and if you return 404 it means to the user that the folder not exists in the server but the truth is the folder may or may not exists and since it is a special folder ASP.NET doesn't allow any one to access that and it is forbidden so I think returning 403 is perfectly valid in this case.
404 vs 403 when directory index is missing
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Try to review web.config section "customErrors" set "mode=Off"
<configuration>
<system.web>
<customErrors defaultRedirect="GenericError.htm" mode="RemoteOnly">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
In my ASP.NET web application, I have defined custom error pages in my web.config file as follows:
<customErrors mode="On" defaultRedirect="~/default.html">
<error statusCode="404" redirect="~/PageNotFound.html" />
</customErrors>
In the case of a 404 error, my site redirects to the default.html page, but it passes "aspxerrorpath" as a query string parameter to the custom error page as follows:
http://www.example.com/default.html?aspxerrorpath=/somepathcausederror/badpage.aspx
I don't want that behavior. I want the redirect URL to simply read:
http://www.example.com/default.html
Is there a way to achieve this?
If you supply your own query string variable when specifying the path, then .NET will NOT tack on the "aspxerrorpath". Who knew?
For example:
<customErrors mode="On" defaultRedirect="errorpage.aspx?error=1" >
This will do the trick.
I had to add this to a bunch of apps since URLScan for IIS by default rejects anything with "aspxerrorpath" in it anyway.
In the global.asax, catch the 404 error and redirect to the file not found page. I didn't require the aspxerrorpath and it worked a treat for me.
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
{
Response.Redirect("~/filenotfound.aspx");
}
else
{
// your global error handling here!
}
}
You could just send your own url params to the error page
<customErrors mode="On" defaultRedirect="~/default.html?404">
<error statusCode="404" redirect="~/PageNotFound.html?404" />
</customErrors>
My first thought would be to create a HttpHandler which catches url's with aspxerrorpath in it, and strips it. You could probably do the same with the rewrite module in IIS7 as well.
I think you'd instead implement/use the Application_Error event in Global.asax, and do your processing/redirects there.
Providing you call Server.ClearError in that handler, I don't think it will use the customErrors config at all.
I use javascript like
if (location.search != "") { window.location.href = "/404.html"; }
If you remove aspxerrorpath=/ and you use response redirect during error handling you'll get exception there will be redirection loop.
Add redirectMode="ResponseRewrite" in the Custom Error like this,
<customErrors mode="On" defaultRedirect="~/NotFound">
<error statusCode="404" redirect="~/NotFound" redirectMode="ResponseRewrite"/>
</customErrors>
this solution works for me.
The best solution (more a workaround..) I implemented since now to prevent aspxerrorpath issue continuing to use ASP.NET CustomErrors support, is redirect to the action that implements Error handling.
These are some step of my solution in an ASP.NET MVC web app context:
First enable custom errors module in web.config
<customErrors mode="On" defaultRedirect="~/error/500">
<error statusCode="404" redirect="~/error/404"/>
</customErrors>
Then define a routing rule:
routes.MapRoute(
name: "Error",
url: "error/{errorType}/{aspxerrorpath}",
defaults: new { controller = "Home", action = "Error", errorType = 500, aspxerrorpath = UrlParameter.Optional },
);
Finally implement following action (and related views..):
public ActionResult Error(int errorType, string aspxerrorpath)
{
if (!string.IsNullOrEmpty(aspxerrorpath)) {
return RedirectToRoute("Error", errorType);
}
switch (errorType) {
case 404:
return View("~/Views/Shared/Errors/404.cshtml");
case 500:
default:
return View("~/Views/Shared/Errors/500.cshtml");
}
}
In my case, i prefer not use Web.config. Then i created code above in Global.asax file:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
//Not Found (When user digit unexisting url)
if(ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
{
HttpContextWrapper contextWrapper = new HttpContextWrapper(this.Context);
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("action", "NotFound");
IController controller = new ErrorController();
RequestContext requestContext = new RequestContext(contextWrapper, routeData);
controller.Execute(requestContext);
Response.End();
}
else //Unhandled Errors from aplication
{
ErrorLogService.LogError(ex);
HttpContextWrapper contextWrapper = new HttpContextWrapper(this.Context);
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("action", "Index");
IController controller = new ErrorController();
RequestContext requestContext = new RequestContext(contextWrapper, routeData);
controller.Execute(requestContext);
Response.End();
}
}
And thtat is my ErrorController.cs
public class ErrorController : Controller
{
// GET: Error
public ViewResult Index()
{
Response.StatusCode = 500;
Exception ex = Server.GetLastError();
return View("~/Views/Shared/SAAS/Error.cshtml", ex);
}
public ViewResult NotFound()
{
Response.StatusCode = 404;
return View("~/Views/Shared/SAAS/NotFound.cshtml");
}
}
And that is my ErrorLogService.cs
//common service to be used for logging errors
public static class ErrorLogService
{
public static void LogError(Exception ex)
{
//Do what you want here, save log in database, send email to police station
}
}
If you want to resolve or handle error request you can insert into Handler try catch statement.
like this:
try {
// Block of code that generate error
}
catch(Exception e) {
// Block of code to handle errors ||| HERE you can put error in your response and handle it without get xhr redirect error.
}