I want to do like this -
but I cent rite razor by web config.
Is there a way to write razor or do it in a different way to my goal will only manager see the errors
Apologize in advance for my English
#using Or50Core.Controllers;
#if ((BaseController)this.ViewContext.Controller).IsAdministrator())
{
<system.web>
<customErrors mode="Off"></customErrors>
</system.web>
}else{
<system.web>
<customErrors mode="On"></customErrors>
</system.web>
}
"if" do the work in views
you would be far better off using logging. That way you catch all the errors (not just ones the administrator gets) in the log files/DB but the users only get a friendly error.
You can use this code:
#{
var configuration = WebConfigurationManager.OpenWebConfiguration("~");
var section = (CustomErrorsSection)configuration.GetSection("system.web/customErrors");
if (section != null)
{
#if ((BaseController)this.ViewContext.Controller).IsAdministrator())
{
section.Mode = CustomErrorsMode.Off;
}
else
{
section.Mode = CustomErrorsMode.On;
}
}
configuration.Save();
}
this code needs to add #using System.Web.Configuration; to view.
Edit:
For manage users you can use ASP.NET Identity and for manage error page you can use Custom Error Page.
You have to write Application_Error method in your Global.ascx. In this method you can check if current user is in Admin role or not and based on that you can show the real error or just a simple error page.
protected void Application_Error()
{
if (!User.IsInRole("Administrator"))
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "Errors";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 403:
routeData.Values["action"] = "Http403";
break;
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
IController errorsController = new ErrorsController();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
errorsController.Execute(rc);
}
}
Here you determine what users see based on each error
public class ErrorsController : Controller
{
public ActionResult General(Exception exception)
{
return Content("General failure", "text/plain");
}
public ActionResult Http404()
{
return Content("Not found", "text/plain");
}
public ActionResult Http403()
{
return Content("Forbidden", "text/plain");
}
}
BTW I find the answer in Here
Related
I have stitched together an error handling for my application using a solution in this post Link. The problem I am getting is that the app is still routing to the default error page. The code goes all the way to the Global.asax when I breakpoint it, but when the view custom error page should load it loads the default error page from the solution. I tried to remove the default error page, I then got the yellow error page from IIS. Searched the web tirelessly, But to no result. Grateful for all the help. If you think I can tweak the question or Title better, I am open to suggestions.
Error controller:
public class ErrorController : Controller
{
public ActionResult PageNotFound(Exception ex)
{
Response.StatusCode = 404;
return View("Error", ex);
}
public ActionResult ServerError(Exception ex)
{
Response.StatusCode = 500;
return View("Error", ex);
}
public ActionResult UnauthorisedRequest(Exception ex)
{
Response.StatusCode = 403;
return View("Error", ex);
}
//Any other errors you want to specifically handle here.
public ActionResult CatchAllUrls()
{
//throwing an exception here pushes the error through the Application_Error method for centralised handling/logging
throw new HttpException(404, "The requested url " + Request.Url.ToString() + " was not found");
}
}
Code in Global.asax.cs:
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
//Error logging omitted
HttpException httpException = exception as HttpException;
RouteData routeData = new RouteData();
IController errorController = new Controllers.ErrorController();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("area", "");
routeData.Values.Add("ex", exception);
if (httpException != null)
{
//this is a basic example of how you can choose to handle your errors based on http status codes.
switch (httpException.GetHttpCode())
{
case 404:
Response.Clear();
// page not found
routeData.Values.Add("action", "PageNotFound");
Server.ClearError();
// Call the controller with the route
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
break;
case 500:
// server error
routeData.Values.Add("action", "ServerError");
Server.ClearError();
// Call the controller with the route
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
break;
case 403:
// server error
routeData.Values.Add("action", "UnauthorisedRequest");
Server.ClearError();
// Call the controller with the route
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
break;
//add cases for other http errors you want to handle, otherwise HTTP500 will be returned as the default.
default:
// server error
routeData.Values.Add("action", "ServerError");
Server.ClearError();
// Call the controller with the route
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
break;
}
}
//All other exceptions should result in a 500 error as they are issues with unhandled exceptions in the code
else
{
routeData.Values.Add("action", "ServerError");
Server.ClearError();
// Call the controller with the route
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
}
RouteConfig.cs
routes.MapRoute("CatchAllUrls", "{*url}", new {controller = "Error", action = "CatchAllUrls"});
The catch block:
throw new HttpException(404, "Unable to write to list" + ", " + e.InnerException);
With the help of #GeorgPatscheider and #AliAshraf I finally solved my issue.I got it to work by changing this return View("Error", ex.Message); to this return View("Error", ex); and added <customErrors mode="On"/>. Now I can also add additional HTTP errorcodes. I had added Message to ex after the initial post Thanks for all the help!!!
I have searched the web and stitched together an error handling solution that doesn't work mainly because I don't understand fully how the exception pipeline works. I used different guides, but I didn't get any of theme to work for me. What I want the error handler to do is this. I have a class called workplanRepo where all my queries are executed. I have covered all queries with a try and catch block. What I want is when an error occurs is for an exception to be thrown that allows me to customize a specific message for each query and the default exception message. I then want to be able to retrieve the messages in the error view that the exception handler has redirected the user to. I would also like a default handler that catches all other errors. but don't necessarily have the custom message part. If anybody could explain or show me how I can achieve this. I would be very grateful!. This is one of the query methods:
try {
newItem["Author"] = _user.Id;
newItem["Title"] = _user.Title;
newItem.Update();
clientContext.ExecuteQuery();
}
catch (Exception e) {
throw new HttpException("Oops, there must have been an error: " + e.Message);
}
In ASP.NET MVC 5, we can catch error inside Global.asax.cs's Application_Error event instead of using try catch block in every query. From then redirect to custom error page.
In addition, we can also use logging framework like Log4Net and NLog.
For example,
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
LogException(exception);
if (exception is HttpAntiForgeryException)
{
Response.Clear();
Server.ClearError();
Response.TrySkipIisCustomErrors = true;
// Call target Controller and pass the routeData.
IController controller = EngineContext.Current.Locator.GetInstance<CommonController>();
var routeData = new RouteData();
routeData.Values.Add("controller", "Common");
routeData.Values.Add("action", "AntiForgery");
var requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);
controller.Execute(requestContext);
}
else
{
// Process 404 HTTP errors
var httpException = exception as HttpException;
if (httpException != null && httpException.GetHttpCode() == 404)
{
Response.Clear();
Server.ClearError();
Response.TrySkipIisCustomErrors = true;
// Call target Controller and pass the routeData.
IController controller = EngineContext.Current.Locator.GetInstance<CommonController>();
var routeData = new RouteData();
routeData.Values.Add("controller", "Common");
routeData.Values.Add("action", "PageNotFound");
var requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);
controller.Execute(requestContext);
}
}
}
private void LogException(Exception ex)
{
if (ex == null)
return;
// Ignore 404 HTTP errors
var httpException = ex as HttpException;
if (httpException != null &&
httpException.GetHttpCode() == 404)
return;
try
{
// Log error message
}
catch (Exception)
{
// Don't throw new exception if occurs
}
}
You can view sample project which use Log4Net at GitHub.
I'm making a single-page-application and the way I have it set up is that using a base controller in the OnActionExecuting() method I redirect non-ajax requests to the home index action. The path will still be there and used as an indicator to tell the javascript what to do.
That works fine for something like /login where there is actually a /login page that would normally be accessible if I hadn't blocked it using the technique I mentioned.
However when I take it a step further and use /some/other/meaningful/but/bogus/url which has no route/controller but has some meaning to the javascript, I get a 404 error.
So obviously what I'd like to do, is in that 404 situation I would like to just load the home index action instead. Alternatively a replacement for my ajax blocking that redirects all paths to the home index action (unless they're valid routes called with ajax) would have the same result.
I've searched for similar answers, unfortunately the same wording is frequently used to describe questions regarding custom 404 pages, so it's a tough one to search for.
You do want a custom error page. The difference is your custom error page is a controller/action. A custom error page doesn't have to be a page like notfound.html it is just a url so you can set the url to a controller action.
The code below will redirect unhandled status codes to "/home" i.e. the home controller. Then for 404 it will go to /controller/action which could be /home/notfound.
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="/home">
<error statusCode="404" redirect="/controller/action"/>
</customErrors>
</system.web>
The non-redirect route, in your global.asax.cs add the following code. This example maybe a little heavy but essentially achieves what you want in that the custom error controller is executed but the URL is unchanged.
protected void Application_Error(object sender, EventArgs e)
{
var httpContext = ((MvcApplication)sender).Context;
var currentController = " ";
var currentAction = " ";
var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
if (currentRouteData != null)
{
if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
{
currentController = currentRouteData.Values["controller"].ToString();
}
if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
{
currentAction = currentRouteData.Values["action"].ToString();
}
}
var ex = Server.GetLastError();
var controllerFactory = ControllerBuilder.Current.GetControllerFactory();
var controller = (Controller)controllerFactory.CreateController(httpContext.Request.RequestContext, "Error");
var routeData = new RouteData();
var action = "Index";
if (ex is HttpException)
{
var httpEx = ex as HttpException;
switch (httpEx.GetHttpCode())
{
case 401:
action = "Unauthorized";
break;
case 403:
action = "Forbidden";
break;
case 404:
action = "NotFound";
break;
default:
break;
}
}
httpContext.ClearError();
httpContext.Response.Clear();
httpContext.Response.StatusCode = ex is HttpException ? ((HttpException)ex).GetHttpCode() : 500;
httpContext.Response.TrySkipIisCustomErrors = true;
routeData.Values["controller"] = "Error";
routeData.Values["action"] = action;
controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
}
I brand new to ASP.NET MVC3. How would I create a global custom error page for MVC3? The general idea is when an exception is thrown it would show a generic message to the user and it would log the exception to a database for developers to investigate later.
Thanks in advance for your help.
Here is what I ended up doing in global.asax.cs:
protected void Application_Error()
{
var exception = Server.GetLastError();
Log.Error("Exception", exception);
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 403:
routeData.Values["action"] = "Http403";
break;
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
IController errorsController = new ErrorController();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
errorsController.Execute(rc);
}
In your Global.asax file implement the Application_Error method:
protected void Application_Error() {
HttpContext ctx = HttpContext.Current;
var error = ctx.Server.GetLastError();
ctx.Response.Clear();
ctx.Response.End();
}
Following up on Maess' comment:
Read this: Error Handling in asp.net mvc 3
What I've done in my project is I created a BaseController and overridden the OnException event as below,
protected override void OnException(ExceptionContext filterContext)
{
// do some logging using log4net or signal to ELMAH
filterContext.ExceptionHandled = true;
var exModel = new HandleErrorInfo(filterContext.Exception,
filterContext.RouteData.Values["controller"].ToString(),
filterContext.RouteData.Values["action"].ToString());
View("Error", exModel).ExecuteResult(ControllerContext);
}
Also I removed the HandleError action filter registered in the Global.asax.cs.
Note: You should have a view with name Error in shared folder.
Update: To extract the error information from the Error view you have to bind the Error view to the model HandleErrorInfo.
#model System.Web.Mvc.HandleErrorInfo
Then you can easily access the exception anywhere in the view as
#Model.Exception
Create a view called Error and add it to your Views\Shared folder. Then in your catch blocks, after you have logged the error, redirect the action to the error view. If you want to display a sophisticated message create an Error model and pass it to the view, or put the information into the ViewBag.
For information on unhandled exceptions and HTTP errors see Ropstah's post.
I have an HttpHandler with the following code:
using System;
using System.Web;
using Company.Cms;
using Company.Web.Handlers.Console;
namespace Company.Web.Handlers
{
/// <summary>
/// Summary description for AdminHandler
/// </summary>
public class AdminHandler : IHttpHandler
{
public bool IsReusable
{
get
{
return false;
}
}
public void ProcessRequest(HttpContext context)
{
HttpRequest request = context.Request;
HttpResponse response = context.Response;
string action = request.QueryString["action"];
if (!HttpContext.Current.User.CanAdminister())
{
response.StatusCode = 403;
response.Status = "403 Access Denied";
response.End();
return;
}
if (String.IsNullOrEmpty(action))
{
response.StatusCode = 404;
response.Status = "404 Not Found";
response.End();
return;
}
IHttpHandler handler = null;
switch (action)
{
case "menu":
handler = new MenuHandler();
break;
case "tree":
handler = new TreeHandler();
break;
case "grid":
handler = new GridHandler();
break;
case "list":
handler = new ListHandler();
break;
case "drop":
handler = new DropHandler();
break;
case "edit":
handler = new EditHandler();
break;
case "new":
handler = new InsertHandler();
break;
}
if (handler == null)
{
response.StatusCode = 404;
response.Status = "404 Not Found";
response.End();
}
else
{
handler.ProcessRequest(context);
}
}
}
}
Unfortunately when I intentionally specify an invalid action, the browser just displays a blank page. Non of the browser error messages are displayed both in Firefox and IE.
What could I be doing wrong?
EDIT - IE shows the error message, but Firefox does not.
First Try this:
protected void Page_Load(object sender, EventArgs e)
{
Response.StatusCode = 404;
Response.SuppressContent = true;
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
:)~
Firebug shows the correct status. Does
this mean that if I want the browser
to display a message, I have to render
it myself? – deverop
Absolutely it does. What the browser does based on an error code received is up to the browser. But you can still provide HTML to go along with the 404. Case in point... take a look at Stack Overflow's 404 page. That error message is entirely hand crafted.
Typically, however, you want to limit the amount of data returned from an error status; the more data you return from an erroneous request, the larger the surface of attack for denial of service.
I had a similar problem, which occures in IIS 7.0 only. What you could also try is to set
Response.TrySkipIisCustomErrors = true;
For 301 redirects use Response.RedirectPermanent().
For 302 redirects use Response.Redirect()
if (isPermanentRedirect)
{
// 301 Redirect
args.HttpContext.Response.RedirectPermanent(targetUrl);
}
else
{
// 302 Redirect
args.HttpContext.Response.Redirect(targetUrl);
}