CustomErrors not redirecting to custom page but MVC default error page - model-view-controller

I have a new MVC 4.0 solution created from scratch using VS2012 web express and IIS Express.
As the tile says I changed my web.config and added the following in :
<customErrors defaultRedirect="Errors/GenericError.html" mode="On">
<error statusCode="404" redirect="Errors/Error404.html"/>
</customErrors>
Basically when I get an exception in my controller the default MVC error.cshtml is showing the error instead of my custom page GenericError.html.
If I go to a URL that doesn't exist, my Error404.html is showing correctly but not for the generic scenario.
Any ideas how I can change this behavior?

Sounds like you don't have the error attribute in your global filters. In an MVC 4 project you should be able to search for the class FilterConfig that was generated for you:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
Update:
The HandleErrorAttribute global filter is for errors that occur in the MVC pipeline, such as errors in your controller as you mention.
The customErrors element in the web.config is for everything else. The HandleErrorAttribute will not honor the value you put in the defaultRedirect attribute of customErrors.
The HandleError filter will look for a shared view which you should have in your generated project shared\Error.cshtml. You can point it to a different view by setting a property on the attribute.
For example, let's say we create a new view under Shared\Errors\CustomError.cshtml, then you could register the filter like this:
filters.Add(new HandleErrorAttribute(){View = "Errors/CustomError"});

Related

Automatically finding Thymeleaf templates with Spring Boot

How can I get Spring Boot and Thymeleaf to automatically find and map template files to be processed when accessed by the browser?
src/main/resources/templates/index.xhtml
src/main/resources/templates/bar.xhtml
src/main/resources/application.properties contains spring.thymeleaf.suffix=.xhtml
FooController.java contains #RequestMapping("/foo") and a #PostMapping method that returns bar
If I enter http://localhost:8080/ in the browser, Thymeleaf processes and displays the index.xhtml page with no extra configuration needed. But http://localhost:8080/index, http://localhost:8080/index.xhtml, and http://localhost:8080/index.html all result in 404 Not Found.
My index view does a POST to foo; FooController is activated and returns bar; and Thymeleaf processes and shows bar.xhtml, even though bar.xhtml isn't mapped anywhere in the configuration. Yet accessing http://localhost:8080/bar, http://localhost:8080/bar.xhtml, and http://localhost:8080/bar.html in a browser all result in 404 Not Found.
Why does GET http://localhost:8080/ process the index.xhtml template, but GET http://localhost:8080/index does not?
How can Thymleaf use bar as a view, but I cannot access http://localhost:8080/bar directly?
How can I configure Thymeleaf so that I can add src/main/resources/templates/example.xhtml and have it processed automatically as a template that I can access via http://localhost:8080/example in the browser, with no explicit configuration specifically for the example.xhtml file?
If I absolutely have to configure controllers (see my answer below), is there a way that I can at least do this in some declarative file, outside of my code?
As noted in Spring in Action, Fifth Edition, I can do something like this in a #Configuration class that implements WebMvcConfigurer
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
registry.addViewController("/bar");
}
That will allow me to process bar.xhtml automatically. (I presume there is some default configuration registry.addViewController("/").setViewName("index"), which is why my index.xhtml file is getting processed by accessing the root path.
And I can even use the following to automatically pick up any template:
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
registry.addViewController("/**");
}
Unfortunately this removes the mapping from / to /index, and also prevents accessing any static resources from src/main/resources. I'm not sure how to tell Thymeleaf to use a template if it can, and fall back to a static file if not.

How to modify subject of Elmah emailing when using WebApi

Normally in my Mvc project, I simply have a ErrorMail_Mailing method in Global.asax.cs which gives access to ErrorMailEventArgs.
But in WebApi, this method does not fire, so how can I access this information in Webapi?
I am currently using this methodology (which is working fine)
public class ApiErrorHandler : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
DepResolver.ExceptionHelper().LogToElmah(context.Exception);
base.OnException(context);
}
}
ELMAH doesn't fire on Web API by default. You need to either catch the error yourself and log it to ELMAH or even better, use the Elmah.Contrib.WebApi NuGet package: http://www.nuget.org/packages/Elmah.Contrib.WebApi/. With that package installed, simply add the following code to your Application_Start:
GlobalConfiguration.Configuration.Filters.Add(new ElmahHandleErrorApiAttribute());
This should trigger that your ErrorMail_Mailing method is called.

Http.EnumRouteContraint must implement System.Web.Routing.IRouteConstraint

I'm using AttributeRouting in my Web API project. I've installed the AttributeRouting for Web API. I want to define an Enum route constraint so I setup my AttributeRoutingHttpConfig config as follows:
using System.Reflection;
using System.Web.Http;
using AttributeRouting.Web.Http.Constraints;
using AttributeRouting.Web.Http.WebHost;
using MyProject.Data.Models;
[assembly: WebActivator.PreApplicationStartMethod(typeof(PhantasyTour.AttributeRoutingHttpConfig), "Start")]
namespace MyProject
{
public static class AttributeRoutingHttpConfig
{
public static void RegisterRoutes(HttpRouteCollection routes)
{
routes.MapHttpAttributeRoutes(
config =>
{
config.AddRoutesFromAssembly(Assembly.GetExecutingAssembly());
config.InlineRouteConstraints.Add("ListType", typeof(EnumRouteConstraint<ListType>));
});
}
public static void Start()
{
RegisterRoutes(GlobalConfiguration.Configuration.Routes);
}
}
}
When I fire up my application I immediately receive the following error:
The constraint "AttributeRouting.Web.Http.Constraints.EnumRouteConstraint`1[[MyProject.Data.Models.ListType, MyProject.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]" must implement System.Web.Routing.IRouteConstraint
I've looked at the source code for the AttributeRouting.Web.Http.Constraints.EnumRouteConstraint and confirmed that it implements IHttpRouteConstraint which presumably is the WebAPI equivalent of IRouteConstraint in the MVC namespace.
Does anyone know what I'm doing wrong and how I can get this working?
UPDATE:
I attempted to create a completely blank Web Application and add only WebAPI and AttributeRouting for WebAPI references. Despite having absolutely no references to MVC assemblies, I still receive the same error message. I did discover however that there is another EnumRouteConstraint found in the AttributeRouting.Web.Constraints namespace which works perfectly. It doesn't appear to be MVC specific since it is located in the Core AttributeRouting assembly. I would love to know why there are two different EnumRouteConstraint classes when only one of them works. But that is a question for another time.
It is interesting that the exception you get refers to the MVC interface from the namespace System.Web.Routing.
I would take it as a clue and look at all the references in your project, any place in the config where MVC Routes and Http Routes could have been mixed up.
If possible and if you have any at all, try removing all references to MVC (or System.Web.Routing for a start), and MVC flavour of attribute routing (if it's a separate dll).

asp.net mvc - common code to execute when loading any page from the application

Where would such code go? Is there a commonly executed block inside Asp.net mvc 3 application - something that gets executed every time any page is loaded?
You can do this by two ways:
First, you can inherit a base Controller from System.Web.Mvc.Controller. Then you use this base class inherits for your application. By this way, you can handle all action executions by overriding OnActionExecuting method of your base controller.
Second and better solution is using Custom Action Filters. Create a custom filter and register it globally in Global.asax file like this:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new YourCustomFilter());
}
Global.asax (ex: http://www.dotnetcurry.com/ShowArticle.aspx?ID=126) or inside the _Layout, it depends on what you're doing.
Just so you know the Global.asax file is also available in ASP.NET Webforms.

Showing built-in Error View for MVC 3

I followed this tutorial, but I am still receiving the ASP.NET screen that says to turn on Errors do this, or to show custom error page do this.
I have registered the HandleErrorAttribute and added the <customErrors mode="On" /> in web.config. The attribute is sitting directly on the line before the Controller class signature.
Am I still missing something?
EDIT
I removed the attribute from the class as you suggested, and this was the result. Nothing special going on I don't think.
web.config
</appSettings>
<system.web>
<customErrors mode="On" />
<compilation debug="true" targetFramework="4.0">
<assemblies>
Global.asax
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Error*
Server Error in '/' Application.
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>
Notes: The current error page you are seeing can be replaced by a custom error page by modifying the "defaultRedirect" attribute of the application's <customErrors> configuration tag to point to a custom error page URL.
<!-- Web.Config Configuration File -->
<configuration>
<system.web>
<customErrors mode="On" defaultRedirect="mycustompage.htm"/>
</system.web>
</configuration>
If you wish to see a custom error page (one that you design yourself) then you need to actually create the page and refer to in in the customErrors element;
<customErrors defaultRedirect="GenericError.htm" mode="On" />
In the example above, you would create the GernericError.htm page in your web application. This will be displayed if there is an error.
If you want to see details about the actual exception being thrown, then you need to set the mode to mode="Off" or mode="RemoteOnly"
Also, make sure that you are running the right version of asp.net (i.e. asp.net 4.0) in IIS for your application, otherwise your web.config file may not be parsed correctly, leading to this page.
Here is a conversation about Razor custom-views that works for me and many others. Test it. May be helpful to you too.

Resources