MVC3 Custom Error Pages work in dev, not on server - asp.net-mvc-3

I am using the solution detailed in this SO Question. I've used this on other sites before and its worked fine, and it works on my dev box. However, when I publish to a our Windows VPS, errors return the standard IIS error page.
I have never administered a web server before, and I am not sure what settings I need to check to figure out why its not returning the custom errors I have set up. I have tried setting .net error pages for the app to off and on, with the default page set to the root site, as well as just '/'.
I have also tried setting the error pages (under iis in 7.5) to custom and detailed.
None of these seem to have any effect on the error page that is returned. What am I doing wrong here?

I remember having similar problem and I added this line to the code
protected void Application_Error()
{
var exc = Server.GetLastError();
var httpExc = exc as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exc;
Response.StatusCode = 500;
if (httpExc != null)
{
Response.StatusCode = httpExc.GetHttpCode();
routeData.Values["action"] = "Http404";
routeData.Values["exception"] = httpExc;
}
Response.TrySkipIisCustomErrors = true; //this fixed it
IController errorsController = new WWS_Website.Controllers.ErrorController();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
errorsController.Execute(rc);
}

You can replace the standard IIS error pages by using the httpErrors section in the system.webServer section in your web.config file. This is in addition to the customErrors section in system.web.
<system.webServer>
...
<httpErrors errorMode="Custom" defaultResponseMode="ExecuteURL">
<remove statusCode="400" subStatusCode="-1" />
<error statusCode="400" prefixLanguageFilePath=""
path="/errors/400" responseMode="ExecuteURL" />
<remove statusCode="404" subStatusCode="13" />
<error statusCode="404" subStatusCode="13" prefixLanguageFilePath=""
path="/errors/file-upload-too-large" responseMode="Redirect" />
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" prefixLanguageFilePath=""
path="/errors/404" responseMode="ExecuteURL" />
<remove statusCode="403" subStatusCode="-1" />
<error statusCode="403" prefixLanguageFilePath=""
path="/errors/403" responseMode="ExecuteURL" />
</httpErrors>

Related

Yii2 REST API IIS Object Moved

I am using Yii2 REST with ActiveController to create a new Pessoa(), on Apache works fine , but on IIS 8 an error occurs.
Does anyone know of any configuration in IIS?
REQUEST
Request URL:http://10.192.1.145/api/pessoa
Request Method:POST
Status Code:201 Created
Remote Address:10.192.1.145
Referrer Policy:no-referrer-when-downgrade
RESPONSE
<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found
here</body>{"id":"21"}
I had a similar issue to this. It seems to be related to FastCGI. Not sure about it. I know it happens when setting response headers to 201 http status code (this line in source code) which get changed by IIS later. If you have access to server try those solutions:
W7 Pro IIS 7.5 overwrites PHP Location: Header (solved)
In my case I had only FTP access to server so I overridden the Create Action by something like what follows to force a 200 status code instead of 201:
public function actions()
{
$actions = parent::actions();
unset($actions['create']);
return $actions;
}
public function actionCreate() {
$model = new Pessoa();
$model->load(Yii::$app->getRequest()->getBodyParams(), '');
if ($model->save() === false && !$model->hasErrors()) {
throw new ServerErrorHttpException('Failed to update the object for unknown reason.');
}
return $model;
}
Just in case somebody else needs to keep the status code and remove only the response part added by IIS, this is what I did to solve my problem. You may need adapt it to your needs, though:
<!-- PS: In my case, i just had a one line HEAD and a one line BODY being added. -->
<outboundRules>
<rule name="Remove the tag HEAD" preCondition="isStatus201">
<match filterByTags="None" pattern="^\<head\>.*?$" />
<action type="Rewrite" value="" />
</rule>
<rule name="Remove the tag BODY" preCondition="isStatus201">
<match filterByTags="None" pattern="^\<body\>.*?\</body\>" />
<action type="Rewrite" value="" />
</rule>
<preConditions>
<preCondition name="isStatus201">
<add input="{RESPONSE_STATUS}" pattern="^201$" />
</preCondition>
</preConditions>
</outboundRules>
Tested in IIS 8.5;
Hope it helps somebody else.
In fact, I was able to optimize the RegEx so that a single rule catches all the lines up the closing body tag:
<outboundRules>
<rule name="Remove injected 201 content" preCondition="Status 201">
<match filterByTags="None" pattern="^(?:.*[\r\n]*)*.*</body>" />
<action type="Rewrite" value="" />
</rule>
<preConditions>
<preCondition name="Status 201" patternSyntax="Wildcard">
<add input="{RESPONSE_STATUS}" pattern="201" ignoreCase="false" />
</preCondition>
</preConditions>
</outboundRules>

rewrite URl from www.m.example.com to m.example.com

I am trying to do a redirect in ASP.NET web.config which contains like www.m.example.com to m.example.com; I have tried different approaches but wasn't able to do it.
Instead of the web.config, you could apply the following to your page:
<script runat="server">
private void Page_Load(object sender, System.EventArgs e)
{
Response.Status = "301 Moved Permanently";
Response.AddHeader("Location","http://www.new-location.com");
}
</script>
Read more here
If you do still want to use the web.config file, you can do the following:
Open web.config in the directory where the old pages reside
Then add code for the old location path and new destination as follows:
<configuration>
<location path="services.htm">
<system.webServer>
<httpRedirect enabled="true" destination="http://domain.com/services" httpResponseStatus="Permanent" />
</system.webServer>
</location>
<location path="products.htm">
<system.webServer>
<httpRedirect enabled="true" destination="http://domain.com/products" httpResponseStatus="Permanent" />
</system.webServer>
</location>
</configuration>

MVC 5.1 debug enabled doesn't disable Bundling and minification

Running in debug from VS 2013.2RTM Pro, MVC 5.1 app.
If the compilation mode is set to debug="true" it is supposed to disable Bundling and minification but it does not. When I examine the View source on a page the styles and scripts are bundled.
<script src="/bundles/modernizr?v=K-FFpFNtIXjnmlQamnX3qHX_A5r984M2xbAgcuEm38iv41"></script>
If I set BundleTable.EnableOptimizations = false; in the BundleConfig.cs it does disable Bundling and minification but that is not how it is supposed to work. I shouldn't have to remember to toggle the EnableOptimizations setting!
Things are working properly in VS 2012 MVC 4 apps.
Is this a MVC 5.1 bug? Has anyone else had this problem? Is there a way to get debug to disable the Bundling and minification?
web.config:
<system.web>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" useFullyQualifiedRedirectUrl="true" maxRequestLength="100000" enableVersionHeader="false" />
<sessionState cookieName="My_SessionId" />
<httpModules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
</httpModules>
</system.web>
_Layout.cshtml:
In header
#Styles.Render("~/Content/css") #Styles.Render("~/Content/themes/base/css")
#Scripts.Render("~/bundles/modernizr")
At end of body
#Scripts.Render("~/bundles/jquery") #Scripts.Render("~/bundles/jqueryui") #Scripts.Render("~/bundles/jqueryval")
You may have a look at this article
http://codemares.blogspot.com.eg/2012/03/disable-minification-with-mvc-4-bundles.html
or you can use this simple implementation
public class NoMinifyTransform : JsMinify
{
public override void Process(BundleContext context, BundleResponse response)
{
context.EnableOptimizations = false;
var enableInstrumentation = context.EnableInstrumentation;
context.EnableInstrumentation = true;
base.Process(context, response);
context.EnableInstrumentation = enableInstrumentation;
}
}
and then when defining your script bundles in (App_Start) you can use the base Bundle class like this
IBundleTransform jsTransformer;
#if DEBUG
BundleTable.EnableOptimizations = false;
jsTransformer = new NoMinifyTransform();
#else
jstransformer = new JsMinify();
#endif
bundles.Add(new Bundle("~/TestBundle/alljs", jsTransformer)
.Include("~/Scripts/a.js")
.Include("~/Scripts/b.js")
.Include("~/Scripts/c.js"));
I'm seeing this as well in the release version. To get around it, I'm using conditional flags to achieve the same effect.
BundleTable.EnableOptimizations = true;
#if DEBUG
BundleTable.EnableOptimizations = false;
#endif

ASP.NET MVC Custom Error Pages with Magical Unicorn

my question is regarding Pure.Kromes answer to this post. I tried implementing my pages' custom error messages using his method, yet there are some problems I can't quite explain.
a)
When I provoke a 404 Error by entering in invalid URL such as localhost:3001/NonexistantPage, it defaults to the ServerError() Action of my error controller even though it should go to NotFound(). Here is my ErrorController:
public class ErrorController : Controller
{
public ActionResult NotFound()
{
Response.TrySkipIisCustomErrors = true;
Response.StatusCode = (int)HttpStatusCode.NotFound;
var viewModel = new ErrorViewModel()
{
ServerException = Server.GetLastError(),
HTTPStatusCode = Response.StatusCode
};
return View(viewModel);
}
public ActionResult ServerError()
{
Response.TrySkipIisCustomErrors = true;
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
var viewModel = new ErrorViewModel()
{
ServerException = Server.GetLastError(),
HTTPStatusCode = Response.StatusCode
};
return View(viewModel);
}
}
My error routes in Global.asax.cs:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{*favicon}", new { favicon = #"(.*/)?favicon.ico(/.*)?" });
routes.MapRoute(
name: "Error - 404",
url: "NotFound",
defaults: new { controller = "Error", action = "NotFound" }
);
routes.MapRoute(
name: "Error - 500",
url: "ServerError",
defaults: new { controller = "Error", action = "ServerError" }
);
And my web.config settings:
<system.web>
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="/ServerError">
<error statusCode="404" redirect="/NotFound" />
</customErrors>
...
</system.web>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="/NotFound" responseMode="ExecuteURL" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500" path="/ServerError" responseMode="ExecuteURL" />
</httpErrors>
...
The Error views are located in /Views/Error/ as NotFound.cshtml and ServerError.cshtml.
b)
One funny thing is, When a server error occurs, it does in fact display the Server Error view I defined, however it also outputs a default error message as well saying that the Error page could not be found.
Here's how it looks like:
Do you have any advice how I could fix these two problems? I really like Pure.Kromes approach to implementing these error messages, but if there are better ways of achieving this don't hestitate to tell me.
Thanks!
**EDIT : **
I can directly navigate to my views through the ErrorController by accessing /Error/NotFound or Error/ServerError.
The views themselves only contain some text, no markup or anything.
As I said, it actually works in some way, just not the way I intended it to work. There seems to be an issue with the redirect in the web.config, but I haven't been able to figure it out.
there is one more issue with that setup, when you have more complex routes and have several segments ex.
http://localhost:2902/dsad/dadasdmasda/ddadad/dadads/ddadad/dadadadad/
I got server error ->
Sorry, an error occurred while processing your request.
Exception: An error occured while trying to Render the custom error view which you provided, for this HttpStatusCode. ViewPath: ~/Views/Error/NotFound.cshtml; Message: The RouteData must contain an item named 'controller' with a non-empty string value.
Source:
my solution for that was to add additional route at the end after default route
routes.MapRoute(
"Default Catch all 404",
"{controller}/{action}/{*catchall}",
new { controller = "Error", action = "NotFound" }
);
hope it could help someone:-)
I got it to work. It seems my understanding of the problem was somewhat wrong to begin with.
In the web.config, I changed the following:
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Views/Error/ServerError.cshtml">
<error statusCode="404" redirect="~/Views/Error/NotFound.cshtml" />
</customErrors>
...
and
...
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="/NotFound" responseMode="ExecuteURL" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500" path="/ServerError" responseMode="ExecuteURL" />
</httpErrors>
This directly redirects to the views. My understanding was that I had to redirect to the error controller which in turn would redirect to the views, but apparently this was not the case. I'd like to thank you for your comments as they have made me analyze the problem again when I was already about to just ditch the custom error stuff and simply be lazy and display YSOD's. :)

asp.net mvc 3 and elmah.axd - yet another 404

Hi all I know that this has been posted as a prior question several times, but I've gone through each question and their proposed solutions and I'm still not able to surmount my 404 issue. I'm running Elmah 1.1 32-bit. I've referred to ASP.NET MVC - Elmah not working and returning 404 page for elmah.axd but I haven't had any luck after applying the suggestions.
I'm running ASP.NET MVC 3. Here's my web.config:
...
<httpHandlers>
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>
<httpModules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
</httpModules>
...
<errorLog type="Elmah.SqlErrorLog, Elmah"
connectionStringName="dbconn" />
<errorFilter>
<test>
<jscript>
<expression>
<![CDATA[
// #assembly mscorlib
// #assembly System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// #import System.IO
// #import System.Web
HttpStatusCode == 404
|| BaseException instanceof FileNotFoundException
|| BaseException instanceof HttpRequestValidationException
/* Using RegExp below (see http://msdn.microsoft.com/en-us/library/h6e2eb7w.aspx) */
|| Context.Request.UserAgent.match(/crawler/i)
|| Context.Request.ServerVariables['REMOTE_ADDR'] == '127.0.0.1' // IPv4 only
]]>
</expression>
</jscript>
</test>
</errorFilter>
I have my .axd routes ignored using:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
I'm running the site on IIS7, 32 bit mode enabled. I've tried many different configuration options but all to no avail. Any ideas?
Thanks
Shan
My bad. My .axd ignore route rule was ordered after the default route mapping. The default route mapping rule was matching the URL elmah.axd. I guess I didn't realize that the ignore rules had to be listed above this route. Thanks everyone for your help!
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
} // Parameter defaults
);
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
Simply moving routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); before the Default route mapping resolved this issue.
Copy the .dll to your bin and reference... add the elmah defaults to configSections
Don't put the handler inside the system.webServer as mentioned above, try system.web section like this instead in your web.config.
<system.web>
<httpHandlers>
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>
</system.web>
just leave your global.asax as default:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
browse to the axd locally
then if working, lock it down with the config section Gedas mentioned above.
Have you tried this?
<configuration>
<system.webServer>
<handlers>
<add name="elmah" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</handlers>
</system.webServer>
</configuration>
also make sure to secure elmah.axd location from regular users:
<location path="elmah.axd">
<system.web>
<authorization>
<allow roles="Admin" />
<deny users="*" />
</authorization>
</system.web>
</location>
I was getting a 404 error due to the SQLServer Compact database being over the default max file size. Just deleted the SDF data file and 404 went away.
In asp.net mvc 3 global.asax.cs file
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//filters.Add(new HandleErrorAttribute());
}
HandleErrorAttribute will swallow all exceptions, leaving nothing for ELMAH to handle.
See Joe's blog http://joel.net/wordpress/index.php/2011/02/logging-errors-with-elmah-in-asp-net-mvc3-part1/

Resources