MVC HandleError attribute not working on Controller - asp.net

I am experimenting with the relationship between Elmah and MVC's plumbed in exception handling, and am surprised at the outcome of the following code. This is a brand new, straight from project template MVC application, and I have only added Elmah modules and handlers to the web.config. And of the course the 'throw':
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
throw new Exception("Just for you Elmah!");
return View();
}
Break when error is thrown is set to off, yet the debugger still breaks. When I continue I get a YSOD, and an Elmah error log, but it seems HandleError is doing nothing.
JUST IN
I didn't think I had to have custom errors turned on, as I thought that was only for 'my' unhandled errors. I guess MVC is just as much a client of that service as I am.

So to start ASP.net MVC [HandleError] not catching exceptions and then onto the logging How to get ELMAH to work with ASP.NET MVC [HandleError] attribute?

Check HandleErrorAttribute is added to the GlobalFiltersCollection in the Global.asax.cs
public static void RegisterGlobalFilters(GlobalFiltersCollection filters)
{
filters.Add(new HandleErrorAttribute());
}

Related

Spring MVC 3 is there a common place to handle exception and display error message in the same view instead of error page

I am using spring MVC 3.2.4. I have a business exception thrown from business tier and want to display an error message in the same view instead of forwarding to an error page once it is caught. I know I could put try-catch in each handler method and then return to the same view. But I really want a common place to achieve this in Spring MVC. I tried #ExceptionHandler and #ControllerAdvice, It seems not working.
Here is what I want to do,
#SomeExceptionHandlerAnnation(BusinessException.class)??
public String handleBusinessException(Model model,
BusinessException ex)
{
//convertExceptionToMessage();
//add message to model
return userView;//stay in the same view
}
The problem is how to get model of the same view. It seems Spring MVC exception handler doesn't support it. Any idea? Thanks in advance.
Try this:
#ControllerAdvice
public class ExceptionController {
#ExceptionHandler(Exception.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ModelAndView handleAllExceptions(Exception e) {
--do something here
return new ModelAndView();
}
}

How to get exception details on shared error.cshtml

I am using ASPNet MVC4 with HandleErrorAttribute filter configured on Global.asax
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
On my web.config I have configured customError mode to RemoteOnly:
<customErrors mode="RemoteOnly" />
So, the user are redirected to ~/Shared/Error.cshtml when a exception are raised on any View, that`s ok.
Now, I can catch this exception for log:
~/Shared/Error.cshtml code:
#{
log4net.LogManager
.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)
.Fatal("Not captured exception", ex);
}
Actually this code are working fine (without EX parameter), but I need to improve my log including exception details.
How I can get exception details on this page?
Just make your Error.cshtml view strongly typed to HandleErrorInfo which is the model being passed to this view by the HandleErrorAttribute:
#model System.Web.Mvc.HandleErrorInfo
#{
log4net
.LogManager
.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)
.Fatal("Not captured exception", Model.Exception);
}
And by the way, logging inside a view doesn't seem like the cleanest thing you could do. I'd rather write my custom error handler attribute and log the exception there.
I'd recommend writing a custom handler and log within, e.g.
[AttributeUsage(AttributeTargets.All, Inherited = true)]
public class HandleErrorAttributeCustom : HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
base.OnException(context);
log4net.LogManager
.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)
.Fatal("Not captured exception", context.Exception);
}
}

No type was found that matches the controller named 'help'

I have been following this guide to add a help page to document my Web API project. My Controller is named HelpController and I have a route that I am trying to use to map the Index action to /Help. This is the only MVC controller in the project. Because the rest are Web API controllers, we removed the "/api" prefix from the default route in WebAPIConfig.cs.
The HelpController:
public class HelpController : Controller
{
public ActionResult Index()
{
var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();
return View(apiExplorer);
}
}
And route config:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "help",
defaults: new { controller = "Help", action = "Index"});
}
}
In Global.asax.cs
protected void Application_Start()
{
// ..
WebApiConfig.Register(GlobalConfiguration.Configuration);
RouteConfig.RegisterRoutes(RouteTable.Routes);
// ..
}
But when I try to navigate to /help in the browser I get the following error message.
<Error>
<Message>No HTTP resource was found that matches the request URI 'http://localhost/ws/help'.</Message>
<MessageDetail>No type was found that matches the controller named 'help'.</MessageDetail>
</Error>
EDIT: The message contains /ws/help as the application is hosted at localhost/ws in IIS.
Does anyone know what could be causing ASP.NET to not find my HelpController?
UPDATE: If I change the order of RouteConfig and WebApiConfig registration calls in Application_Start I get a 404 instead.
protected void Application_Start()
{
// ..
RouteConfig.RegisterRoutes(RouteTable.Routes);
WebApiConfig.Register(GlobalConfiguration.Configuration);
// ..
}
The request for help is being matched by Web API's route as you have removed api from its route template. if a request matches a route, further probing is not done on rest of the routes.
You probably have the default order in Global.asax where Web API routes are registered first and then the MVC routes. Could you share how your Global.asax looks like?
EDIT:
Based on your last comment, if you install HelpPage nuget package, make sure that the order in your Global.asax looks like this:
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
RouteConfig.RegisterRoutes(RouteTable.Routes);
I had this same error today.
<Error>
<Message>No HTTP resource was found that matches the request URI 'xxx'.</Message>
<MessageDetail>No type was found that matches the controller named 'xxx'.</MessageDetail>
</Error>
In my case after 2 days of debuging I finally solved it by setting the microsoft report viewer dll to "Copy to local". Makes no sense to me how it could be related, but maby this will help someone.
I was getting the same error:
Error><Message>No HTTP resource was found that matches the request URI 'http://localhost:53569/api/values'.</Message><MessageDetail>No type was found that matches the controller named 'values'.</MessageDetail></Error>
By default when I created new controller in asp.net web forms application, it was like this:
ValuesController1 : ApiController
I just simply removed "1", and make it:
ValuesController : ApiController
And it works, don't know if it is a bug or whatever, but it made big trouble for me.

Application_Error isn't triggered in asp.net web api

How do I get the Application_Error triggered in an ASP.NET WebAPI application? The error I'm having now is that when we resolve a controller through NInject and fails it won't got into Application_Error and we can't log the error since we are doing the global logging in Application_Error.
We also have a global filter for handling error, but that is only triggered if we have found a controller but since we are failing we instantiating the controller we won't go through any filters.
So how do I catch an Exception raised why trying to create the controller handling the response?
ASP.Net Web API has its own Exception Handler, you can override it and re-throw exception from there in order to handle it in Application_Error
public class MyExceptionHandler : IExceptionHandler
{
public virtual Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
ExceptionDispatchInfo.Capture(context.Exception).Throw();
return Task.CompletedTask;
}
}
you also need to add MyExceptionHandler class to Web API services.
httpConfiguration.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());

Pure ASP.NET routing to a class not an aspx page

I need to do routing in an existing asp.net app - not an asp.net mvc (yeah I know I should convert but let's say it's not possible right now so don't tell me :) ) - how can I do routing to a normal class instead of an aspx page as all sample code I see is always with aspx page like here:
http://msdn.microsoft.com/en-us/magazine/dd347546.aspx
To precise, I want to do a bit like in MVC Controller routing : the controller for example product is a pure class you access through http://domain.com/product
ASP.NET MVC and ASP.NET Web Forms share the same routing infrastructure in that both frameworks ultimately need to come up with an IHttpHandler to handle the HTTP request:
The IHttpHandler interface has been a part of ASP.NET since the
beginning, and a Web Form (a System.Web.UI.Page) is an IHttpHandler.
(From the MSDN article linked in the question)
In ASP.NET MVC the System.Web.Mvc.MvcHandler class is used, which then delegates to a controller for further handling of the request. In ASP.NET Web Forms usually the System.Web.UI.Page class that represents an .aspx file is used, but a pure IHttpHandler associated with .ashx file can also be used.
So you can route to an .ashx handler as an alternative to an .aspx Web Forms page. Both implement IHttpHandler (as does MvcHandler), but with the former that's all it does. And that's as close as you can get to a 'pure class' handling a (routed) request. And since the handler part is just an interface, you are free to inherit from your own class.
<%# WebHandler Language="C#" Class="LightweightHandler" %>
using System.Web;
public class LightweightHandler : YourBaseClass, IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("Hello world!");
}
public bool IsReusable { get { return false; } }
}
Notice that an IRouteHandler just needs to return an instance of IHttpHandler:
public IHttpHandler GetHttpHandler(RequestContext requestContext);
You may need to jump through some hoops to instantiate your handler using the BuildManager* if you use .ashx files. If not, you can just new up an instance of your class and return it:
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
// In case of an .ashx file, otherwise just new up an instance of a class here
IHttpHandler handler =
BuildManager.CreateInstanceFromVirtualPath(path, typeof(IHttpHandler)) as IHttpHandler;
// Cast to your base class in order to make it work for you
YourBaseClass instance = handler as YourBaseClass;
instance.Setting = 42;
instance.DoWork();
// But return it as an IHttpHandler still, as it needs to do ProcessRequest
return handler;
}
See the answers to this question for much more in-depth analysis of routing pure IHttpHandlers: Can ASP.NET Routing be used to create “clean” URLs for .ashx (IHttpHander) handlers?
**I'm not entirely sure about the BuildManager example, someone please correct me if I got that part wrong*
If you can't switch to ASP.NET MVC and routing .ashx handlers doesn't meet your requirements, you may want to look into Nancy, a 'lightweight web framework'.
Here's an example from the introduction (see link in previous paragraph):
public class Module : NancyModule
{
public Module() : base("/foo")
{
Get["/"] = parameters => {
return "This is the site route";
};
Delete["/product/{id}"] = parameters => {
return string.Concat("You requested that the following product should be deleted: ", parameters.id);
};
}
}
This class will handle requests to /foo and /foo/product/42. You can also use views with this framework to render a more complex (HTML) response.
If you can update from 3.5 to 4.0, WebForms supports routing better. In Global.asax, you only need to do things like this:
void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapPageRoute("default", string.Empty, "~/default.aspx");
}
I don't really understand the "pure class" part, but hopefully if updating to 4.0 is an option this can get you going.

Resources