Error controller not hit when using httpErrors in web.config - c#

I am struggling to setup the httpErrors section correctly in my web.config to capture both ASP.NET MVC errors and IIS errors. I am getting 403 status codes and blank pages. I am testing with 404 errors by typing incorrect URLS and file names in the URL, for example:
www.mywebsite.com/test
www.mywebsite.com/test.html
I am using the latest version of ASP.NET MVC 5. This web application is running on IIS 7.5 with an application pool using integrated mode.
This is what my web.config looks like at the root of the application (this is all that I currently have):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="webpages:Version" value="3.0.0.0"/>
<add key="webpages:Enabled" value="false"/>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
<system.web>
<customErrors mode="Off" />
<compilation debug="true" targetFramework="4.5.2"/>
<httpRuntime targetFramework="4.5.2"/>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<remove statusCode="500" />
<error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
<error statusCode="500" responseMode="ExecuteURL" path="/Error" />
</httpErrors>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0"/>
</dependentAssembly>
<!-- ...and so forth... -->
</assemblyBinding>
</runtime>
</configuration>
My global.asax.cs file:
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
protected void Application_Error()
{
// Break point has been set here for testing purposes
}
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
// Break point has been set here for testing purposes
}
}
}
My error controller:
public class ErrorController : Controller
{
public ActionResult Index()
{
// Break point has been set here for testing purposes
Response.StatusCode = 500;
return View();
}
public ActionResult Forbidden()
{
// Break point has been set here for testing purposes
Response.StatusCode = 403;
return View();
}
public ActionResult NotFound()
{
// Break point has been set here for testing purposes
Response.StatusCode = 404;
return View();
}
}
They have their corresponding views in the Views folder.
My break points are never hit in my error controller. I don't understand why? I have looked at many examples on Stackoverflow and this is how every suggests that I do it. When would the break points not be reached given my code? All that happens is a 403 error status and a BLANK white page. The break points in Application_Error() and Application_EndRequest() are hit, but not the break points in the error controller.
There is code that I can write in Application_Error() and Application_EndRequest() that lets me set the error controller and action method, but why do that if I can use the web.config? This should also work?

Man, you have mentioned statusCode as 404 then how can you expect as 200 OK ? :)
just remove Response.StatusCode = 404; line from action method
Bellow code should work
public ActionResult NotFound()
{
return View();
}

Related

How to allow anonymous authentication for index in owin pipeline?

My index page in a MVC 5 Application return an unauthorized status code.
I have configured my application under IIS 10.0 with none authentication to manage the authentication in the owin pipeline :
<system.web>
<compilation debug="true" targetFramework="4.7.1" />
<httpRuntime targetFramework="4.7.1" />
<authentication mode="None" />
<pages>
<namespaces>
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
</namespaces>
</pages>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<clear />
<add name="Owin" verb="" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb"/>
</handlers>
</system.webServer>
Here my controller to allow anonymous on index action :
[Authorize]
public class SPAController : Controller
{
[AllowAnonymous]
public ActionResult Index()
{
return View();
}
}
And my owin pipeline where i suspect that i miss something :
// Enable static file serving for the current application before authentication phase
app.UseStaticFiles(new StaticFileOptions() {
RequestPath = new PathString(""),
FileSystem = new PhysicalFileSystem(HostingEnvironment.MapPath("~/"))
});
Update
I also tried this without success :
[Authorize]
public class SPAController : Controller
{
[OverrideAuthorization]
[AllowAnonymous]
public ActionResult Index()
{
return View();
}
}
and without attributes

Cannot make custom error pages work in ASP.NET MVC application when running in application folder

I have an ASP.NET MVC application, that is deployed in the Default web site in IIS and it runs inside an application folder, e.g. http://localhost/appfolder.
I have two error pages and I tried to set them using the <httpErrors> section in web.config.
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="401" />
<remove statusCode="500" />
<error statusCode="401" responseMode="ExecuteURL" path="/appfolder/Home/NoAccess" />
<error statusCode="500" responseMode="ExecuteURL" path="/appfolder/Home/Error" />
</httpErrors>
The above setup works, but I could not make it work without using the folder name inside the paths. Based on the documentation the path attribute is relative to the site root.
If you choose the ExecuteURL response mode, the path has to be a
server relative URL (for example, /404.htm).
So, with the above in mind, the following should work, but it doesn't.
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="401" />
<remove statusCode="500" />
<error statusCode="401" responseMode="ExecuteURL" path="/Home/NoAccess" />
<error statusCode="500" responseMode="ExecuteURL" path="/Home/Error" />
</httpErrors>
Also, using ~/Home/NoAccess does not work at all, it seems that IIS simply puts ~ in the URL.
My question: Is it possible to have the above setup without having to use application folder name?
Edit: See in this snippet how my application is authorizing each request.
public class AppAutorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorized = false;
// Business logic to decide if authorized
return authorized;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
base.HandleUnauthorizedRequest(filterContext);
}
}
And its use in a controller is:
[HttpGet]
[AppAutorize]
public ActionResult Item(int id)
{
Models.Home.Item model = new Models.Home.Item(id);
return View("Item", model);
}
Because your web application is hosted under another website the correct site relative path for the error pages would be the one you said works. I know this isn't what you was hoping to see but the best way of handling this is to replace that httpErrors element in the Web.Release.config file like the following:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document Transform">
<system.webServer>
<httpErrors xdt:Transform="Replace">
<remove statusCode="401" />
<remove statusCode="500" />
<error statusCode="401" responseMode="ExecuteURL" path="/appfolder/Home/NoAccess" />
<error statusCode="500" responseMode="ExecuteURL" path="/appfolder/Home/Error" />
</httpErrors>
</system.webServer>
</configuration>
And keep the standard Web.config with the path excluding the appfolder path.
How I tend to do it
I tend to shy away from using the web config and instead set the HTTP errors to the following:
<httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough" />
I then have a base controller which all my controllers inherit from with methods for each error code which I want a custom page for. So in your case:
public ViewResult NoAccess()
{
Response.StatusCode = (int) HttpStatusCode.Unauthorized;
return View("NoAccess");
}
Then the usage in any of your controllers is very simple:
public ActionResult Test()
{
return NoAccess();
}
This will then render your custom view. This method of doing error pages depends on your use case but that's how I've managed to get custom error pages to work.

404 not found error when locally testing web api

This is my first time trying to use the WEB API in a project and am not having any success with it...
I keep getting 404 errors when I try and reach my api route in Fiddler.
I tried looking a lot on the web and even here at the following link, but there are so many combinations, that I'm not sure what would work.
HTTP 404 Page Not Found in Web Api hosted in IIS 7.5
If somebody can please help me with this to get the right settings I would really appreciate it.
Here is my code:
Web.config file:
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301879
-->
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="FuelTicketImageRetrievalSvc.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="AssignedGroup" value="FMS Maintenance Level 3" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.1" />
<httpRuntime targetFramework="4.5.1" />
</system.web>
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<system.serviceModel>
<bindings />
<client />
</system.serviceModel>
<applicationSettings>
<FuelTicketImageRetrievalSvc.Properties.Settings>
<setting name="FuelTicketImageRetrievalSvc_IncidentService_HPD_IncidentInterface_Create_WSService" serializeAs="String">
<value>http://miavsbremweb/arsys/services/ARService?server=miavsbremapp.ryder.com&webService=HPD_IncidentInterface_Create_WS</value>
</setting>
</FuelTicketImageRetrievalSvc.Properties.Settings>
</applicationSettings>
</configuration>
WebApiConfig.cs file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace FuelTicketImageRetrievalSvc
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
Global.asax.cs file:
using FuelTicketImageRetrieval;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace FuelTicketImageRetrievalSvc
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}
Controller method that I'm trying to call. It's just a dummy method that simply returns null with no parameters. It's name is FuelTicketImageRetrievalController:
public string GetSpecificFuelTicket()
{
try
{
return null;
}
catch (Exception ex)
{
return null;
}
}
The name of my project is called FuelTicketImageRetrievalSvc. I have verified through the web settings in the project that IIS Express is being used and is set to
http://localhost:11581/
url path call.
http://localhost:11581/FuelTicketImageRetrievalSvc/api/GetSpecificFuelTicket
You don't need FuelTicketImageRetrievalSvc in uri, it should work simply with /api/...
that's what your route matches, having svc name there causes it to not match.
You need to add your controller in the path and remove your project
http://localhost:11581/api/FuelTicketImageRetrieval/GetSpecificFuelTicket
You remove the Controller part when referencing it - the /FuelTicketImageRetrieval/ is from the FuelTicketImageRetrievalController not the project. Web API will auto add the controller back on the name when looking for the correct class.
For a quick guaranteed run (and sometimes preferred approach), add HTTP action prefix and route attributes before your method:
[HttpGet]
[Route("api/Products/SpecificFuelTicket")]
public string GetSpecificFuelTicket()
{
try
{
return null;
}
catch (Exception ex)
{
return null;
}
}
Now, you can access it using URL:
http://localhost:xxxx/api/products/SpecificFuelTicket
Points to note:
HTTPGet ensures that only Get action is mapped to this method
Route value ensures a direct mapping to a URL. As REST standard, "Get", "Delete" etc.. are not used as prefix in URL. The HTTP action is used for that.
Some methods are automatically mapped to suitable URLs, but since your class name is "FuelTicketImageRetrievalController" and method name is "GetSpecificFuelTicket", it is not trivial.
Returning null is not an issue. it is returned serialized as "null".
For your another question to Charles, if you want to use URL "localhost:xxxx/api/GetSpecificFuelTicketAsync/6460194", and your method signature takes int, you can change the route prefix as following (again, not using "Get" in the route):
[HttpGet]
[Route("api/Products/SpecificFuelTicket/{value}")]
public string GetSpecificFuelTicket(int value)
{
try
{
return "Your ticket is " + value.ToString();
}
catch (Exception ex)
{
return null;
}
}
However, as Charles suggested, using "api/Products/SpecificFuelTicket?value=6460194" format is perhaps better. Any parameter name in the method is automatically mapped to similar name query parameter. So, your method'd look like:
[HttpGet]
[Route("api/Products/SpecificFuelTicket")]
public string GetSpecificFuelTicket(int value)
{
....
}
For, a detailed understanding of URL mapping and routing web-API, refer to link:
Attribute Routing in Web API 2
Routing and Action Selection
I originally had a 404 error when I added WebApi support to my Mvc solution.
My global.asax.cs contained the lines:
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalConfiguration.Configure(WebApiConfig.Register);
What I found is that when I changed he WebApiConfig line, so that the code block became:
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
it fixed my problem

MVC 3, Elmah and The view 'Error' or its master was not found

I am working on a legacy website that uses MVC 3, elmah and nhibernate. The Elmah log has literally thousands of " The view 'Error' or its master was not found" errors. I assume that it is covering up the real error. I cannot figure out how to have the real error get logged by Elmah.
As a means to attempt to debug, I added - return RedirectToAction("noWhere"); - to force an error. Locally I get a .net screen that simply says "An exception occurred while processing your request..." on staging I get YOSOD screen telling me to set the web.config customerrors node. Both have the customerrors set to on.
The web config has the following:
<pages>
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.Helpers" />
<add namespace="System.Web.WebPages" />
</namespaces>
</pages>
<httpModules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
</httpModules>
<customErrors mode="On" defaultRedirect="~/Views/Shared/PageNotFound">
<error statusCode="404" redirect="~/Views/Shared/PageNotFound" />
<error statusCode="500" redirect="~/Views/Shared/PageNotFound" />
</customErrors>
The Global.asax has:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ElmahHandleErrorAttribute());
}
The Elmah class has
public class ElmahHandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute
{
public override void OnException(ExceptionContext context)
{
base.OnException(context);
var e = context.Exception;
if (!context.ExceptionHandled // if unhandled, will be logged anyhow
|| RaiseErrorSignal(e) // prefer signaling, if possible
|| IsFiltered(context)) // filtered?
return;
LogException(e);
}
and the baseController class has:
protected ViewResult PageNotFound()
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View("PageNotFound", PageViewModelBuilder.UpdateSiteProperties(new PageViewModel()));
}
protected ViewResult PageBadRequest()
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return View("PageNotFound", PageViewModelBuilder.UpdateSiteProperties(new PageViewModel()));
}
Any help on getting the correct errors to log would be appreciated....
Change "~/Views/Shared/PageNotFound" to "~/Views/Shared/PageNotFound.aspx” (or "~/Views/Shared/PageNotFound.chtml”) in your web.config and make sure you have PageNotFound.aspx in your Shared folder.

IIS overriding custom 404 error page in ASP.NET

I am trying to create a 404 error page and currently I have all of the following/tried all of the following to try and accomplish this. When the user types in :
http://name/something.aspx
It works just as its supposed to. But if the user types in:
http://name/NotAFile
with no .aspx then IIS7 takes matters into its own hands and I get the lovely error page that IIS7 comes with. The goal is that the site redirects with only a 404 status code (so not a 200, or a 302 redirect). I have tried in both the web config with:
<customErrors mode="On" defaultRedirect="~/error/Default.aspx redirectMode="ResponseRewrite">
<error statusCode="404" redirect="~/error/NotFound.aspx" />
</customErrors>
This works for the url with a .aspx file extension but not for no extension. Same with this approach in the global.asax
void Application_Error(object sender, EventArgs e)
{
var serverError = Server.GetLastError() as HttpException;
if (serverError != null)
{
if (serverError.GetHttpCode() == 404)
{
Server.ClearError();
Server.Transfer("~/error/NotFound.aspx");
}
Server.Transfer("~/error/Default.aspx");
}
}
The same results are present for this :( My final attempt was to apply this to the web config:
<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
With this I just get a plain white screen with nothing on it...
Any thoughts or comments would be greatly appreciated!! Thanks in advance!
The following codes works with both .aspx and other file types:
Global.asax
void Application_Error(object sender, EventArgs e)
{
var serverError = Server.GetLastError() as HttpException;
if (serverError != null)
{
if (serverError.GetHttpCode() == 404)
{
Server.ClearError();
Response.Redirect("~/NotFound.aspx?URL=" + Request.Url.ToString());
}
Response.Redirect("~/Default.aspx");
}
}
Web.config
<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
It seems that your application is running in classic pipeline mode. Change it to integrated and your problem will be fixed. Here is an article about pipeline modes and their differences - http://learn.iis.net/page.aspx/508/wildcard-script-mapping-and-iis-7-integrated-pipeline/
For classic asp you can use this
<system.webServer>
<httpErrors>
<clear />
<error statusCode="404" subStatusCode="-1" path="/404.html" responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
<system.webServer >
<httpErrors errorMode="Custom">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="http://www.seair.co.in/Page-not-found.aspx" responseMode="Redirect" />
</httpErrors>
</system.webServer>
use the code in your config and give complete path of error page

Categories