I have an asp.net MVC 5 project and I'm trying to throw a 404 error instead of 500.
The errors are
A public action method 'something' was not found on controller
'ProjetX.Controllers.HomeController'
and
The controller for path '/something' was not found or does not implement
IController
I understand why it's an error 500 but I would like to throw a 404. It would be better for SEO.
I can't figure out how to
Here's my code
My ExceptionHandler class for elmah
public class HandleCustomError : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
//If the exeption is already handled we do nothing
if (filterContext.ExceptionHandled)
{
return;
}
else
{
//Log the exception with Elmah
Log(filterContext);
Type exceptionType = filterContext.Exception.GetType();
//If the exception is while an ajax call
if (exceptionType == typeof(ExceptionForAjax))
{
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.ContentEncoding = Encoding.UTF8;
filterContext.HttpContext.Response.HeaderEncoding = Encoding.UTF8;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.HttpContext.Response.StatusDescription = filterContext.Exception.Message;
}
else
{
base.OnException(filterContext);
}
}
//Make sure that we mark the exception as handled
filterContext.ExceptionHandled = true;
}
private void Log(ExceptionContext context)
{
// Retrieve the current HttpContext instance for this request.
HttpContext httpContext = context.HttpContext.ApplicationInstance.Context;
if (httpContext == null)
{
return;
}
// Wrap the exception in an HttpUnhandledException so that ELMAH can capture the original error page.
Exception exceptionToRaise = new HttpUnhandledException(message: null, innerException: context.Exception);
// Send the exception to ELMAH (for logging, mailing, filtering, etc.).
ErrorSignal signal = ErrorSignal.FromContext(httpContext);
signal.Raise(exceptionToRaise, httpContext);
}
}
How I add the custom errors
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleCustomError());
}
The routes config
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Robots.txt",
"robots.txt",
new { controller = "robot", action = "index" });
routes.MapRoute(
name: "Localization",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { lang = #"^[a-zA-Z]{2}$" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"NotFound",
"{*url}",
new { controller = "Error", action = "Error404" }
);
routes.MapMvcAttributeRoutes();
}
My webconfig
<system.web>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.5" />
<!-- 2MB-->
<httpRuntime targetFramework="4.5" maxRequestLength="2097152" />
<httpModules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
</httpModules>
<!-- Set mode to RemoteOnly in production -->
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="/Error/Error500">
<error statusCode="400" redirect="/Error/Error400" />
<error statusCode="404" redirect="/Error/Error404" />
<error statusCode="500" redirect="/Error/Error500" />
</customErrors>
</system.web>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="400" subStatusCode="-1" />
<error statusCode="400" path="/Error/Error400" responseMode="ExecuteURL" />
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="/Error/Error404" responseMode="ExecuteURL" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500" path="/Error/Error500" responseMode="ExecuteURL" />
</httpErrors>
<modules>
<remove name="FormsAuthenticationModule" />
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
</modules>
<validation validateIntegratedModeConfiguration="false" />
<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" />
<add name="Robots-ISAPI-Integrated-4.0" path="/robots.txt" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<staticContent>
</staticContent>
</system.webServer>
I wanted to handle the error in the HandleCustomError class but the problem is that it goes straight to my Error500 action in the error controller.
What's weird is that the error is still logged in elmah.
It doesn't hit any breakpoint inside the HandleCustomError class, how can the error be logged?
Thank you
Here's the final code that works
I had to add 2 functions to generate a regex with all the name of my controllers and actions
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Localization",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { lang = #"^[a-zA-Z]{2}$", controller = GetAllControllersAsRegex(), action = GetAllActionsAsRegex }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { controller = GetAllControllersAsRegex(), action = GetAllActionsAsRegex() }
);
routes.MapRoute(
"NotFound",
"{*url}",
new { controller = "Error", action = "Error404" }
);
routes.MapMvcAttributeRoutes();
}
private static string GetAllControllersAsRegex()
{
var controllers = typeof(MvcApplication).Assembly.GetTypes()
.Where(t => t.IsSubclassOf(typeof(Controller)));
var controllerNames = controllers
.Select(c => c.Name.Replace("Controller", ""));
return string.Format("({0})", string.Join("|", controllerNames));
}
private static string GetAllActionsAsRegex()
{
Assembly asm = Assembly.GetExecutingAssembly();
var actions = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type)) //filter controllers
.SelectMany(type => type.GetMethods())
.Where(method => method.IsPublic && !method.IsDefined(typeof(NonActionAttribute)))
.Select(x=>x.Name);
return string.Format("({0})", string.Join("|", actions));
}
}
See Also
https://stackoverflow.com/a/4668252
Related
GET works fine.
But in Chrome with POST method I have:
Failed to load resource: the server responded with a status of 405 (Method Not Allowed).
Failed to load http://localhost:49834/api/Rest/: Response for preflight has invalid HTTP status code 405.
In InterntExplorer I have: SCRIPT7002: XMLHttpRequest: Network error 0x80070005, Access denied.
Controller:
[EnableCors("*", "*", "*")]
public class RestController : ApiController
{
// POST: api/Rest
[HttpPost]
public void Post([FromBody]Request Request)
{
if (ModelState.IsValid)
{
db.Requests.Add(Request);
db.SaveChanges();
}
}
}
WebApiConfig.cs
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
Web.config:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="*" />
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
</customHeaders>
</httpProtocol>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/> <!-- add this -->
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="WebDAV" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
AJAX POST:
var url = "http://localhost:49834/";
$.ajax({
type: "POST",
url: url + "api/Rest/",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(submitData),
success: function (data) {
},
error: function (err) {
console.log(err);
alert(err.status + " - " + err.statusText);
}
})
I use IIS Express: applicationHost.config file in %userprofile%\documents\IISExpress\config folder => ExtensionlessUrl-Integrated-4.0 handler is configured like this verb="GET,HEAD,POST,DEBUG,PUT,DELETE"
GET works fine:
$.getJSON(url + "api/Rest").done(function (data) {
var mass = new Array();
$(data).each(function (index, e) {
ReqArray.push(e);
})
vm.requests(ReqArray);
});
There was some problem with my ajax, like this it works good:
var url = "http://localhost:49834/";
$.ajax({
type: "POST",
url: url + "api/Rest",
dataType: "json",
data: submitData,
success: function (data) {
},
error: function (err) {
console.log(err);
alert(err.status + " - " + err.statusText);
}
})
I'm using angularJS and C#,
Due to my superior demand, i have to use HTML5 mode at all cost, mean no '#' sign.
And Again do to his request, i Used rewrite to provide ability to access the angular page even on page refresh.
Recently we implement phantomJS, the first page did worked well, till i notice other page doesn't, after digin-in in codes, i found out that, NO, it wont capture the whole URL, for example, for: http://localhost:xyzw/flights?_escaped_fragment_= it only capture the http://localhost:1350/?_escaped_fragment_=, which doesn't contain the 'flights' part. i also made some change in my rewrite config, which the last one was adding following rule to ignore these path for angular app, and process them directly: <add input="{REQUEST_URI}" matchType="Pattern" pattern="(.*)_escaped_fragment_=(.*)" ignoreCase="false" />
I separate my code for those who come and say hey shorten your issue, as whole of it can be,...
first part, my configs and small codes
second the tutorial i read about PhantomeJS
other files which may be required
Here are my main setup:
WebConfig Rewrite:
<rewrite>
<rules>
<!--<rule name="Seo rewrite rule" stopProcessing="true">
<conditions>
<add input="{QUERY_STRING}" pattern="(.*)_escaped_fragment_=(.*)" ignoreCase="false" />
</conditions>
<action type="Rewrite" url="http://service.prerender.io/http://{HTTP_HOST}{REQUEST_URI}" appendQueryString="false" />
</rule>-->
<rule name="Index Rule" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/api/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Token" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/bundles/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Content/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Scripts/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/SiteMap/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/CallBackBank/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Error/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="(.*)_escaped_fragment_=(.*)" ignoreCase="false" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/HtmlSnapshot[^s]?/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Flight[^s]?/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Hotel[^s]?/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Tour[^s]?/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/TravelAgency[^s]?/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Users[^s]?/" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
Phantom JS required Filter:
public class AjaxCrawlableAttribute : System.Web.Mvc.ActionFilterAttribute
{
private const string Fragment = "_escaped_fragment_";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.RequestContext.HttpContext.Request;
var url = request.Url.ToString();
if (request.QueryString[Fragment] != null && !url.Contains("HtmlSnapshot/returnHTML"))
{
url = url.Replace("?_escaped_fragment_=", string.Empty).Replace(request.Url.Scheme + "://", string.Empty);
url = url.Split(':')[1];
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary { { "controller", "HtmlSnapshot" }, { "action", "returnHTML" }, { "url", url } });
}
return;
}
}
Route Config:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.LowercaseUrls = true;
//PhantomJS
routes.MapRoute(
name: "HtmlSnapshot",
url: "HtmlSnapshot/returnHTML/{*url}",
defaults: new {controller = "HtmlSnapshot", action = "returnHTML", url = UrlParameter.Optional});
////PhantomJS
//routes.MapRoute(
// name: "SPA",
// url: "{*catchall}",
// defaults: new {controller = "Home", action = "Index"});
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional});
}
PhantomJS for C# The tutorial that i read:
OK, since the tutorial i read about phantomjs is in non-english i post the thing i wrote for my later usage:
1.Install Package
Install-Package PhantomJS.exe -version 1.9.2.1
2.Create Helper
public class AjaxCrawlableAttribute : System.Web.Mvc.ActionFilterAttribute
{
private const string Fragment = "_escaped_fragment_";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.RequestContext.HttpContext.Request;
var url = request.Url.ToString();
if (request.QueryString[Fragment] != null && !url.Contains("HtmlSnapshot/returnHTML"))
{
url = url.Replace("?_escaped_fragment_=", string.Empty).Replace(request.Url.Scheme + "://", string.Empty);
url = url.Split(':')[1];
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary { { "controller", "HtmlSnapshot" }, { "action", "returnHTML" }, { "url", url } });
}
return;
}
}
3.Replace Default Routes With:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "HtmlSnapshot",
url: "HtmlSnapshot/returnHTML/{*url}",
defaults: new { controller = "HtmlSnapshot", action = "returnHTML", url = UrlParameter.Optional });
//If doesn't work, use default route instead...:
routes.MapRoute(
name: "SPA",
url: "{*catchall}",
defaults: new { controller = "Home", action = "Index" });
}
4.Add AjaxCrawlableAttribute As A Filter
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AjaxCrawlableAttribute());
}
}
5.Create HtmlSnapshot Controller
public ActionResult returnHTML(string url)
{
var prefix = HttpContext.Request.Url.Scheme + "://" + HttpContext.Request.Url.Host + ":";
url = prefix + url;
string appRoot = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
var startInfo = new ProcessStartInfo
{
Arguments = string.Format("{0} {1}", "\"" + Path.Combine(appRoot, "Scripts\\seo.js") + "\"", url),
FileName = "\"" + Path.Combine(appRoot, "bin\\phantomjs.exe") + "\"",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
StandardOutputEncoding = System.Text.Encoding.UTF8
};
var p = new Process();
p.StartInfo = startInfo;
p.Start();
string output1 = p.StandardOutput.ReadToEnd();
p.WaitForExit();
var removeNgUiView = output1.Replace("<!-- ngView: -->", "").Replace("ng-view=\"\"", "");
removeNgUiView = Regex.Replace(removeNgUiView, "<!--\\suiView:\\s\\w*\\s-->", "");
removeNgUiView = Regex.Replace(removeNgUiView, "(<\\w+[^>]*)(ui-view(=\"\\w*\")?)([^<]*>)", "$1$4");
removeNgUiView = Regex.Replace(removeNgUiView, "(<\\w+[^>]*)(ng-app(=\"\\w*\")?)([^<]*>)", "$1$4");
ViewData["result"] = removeNgUiView;
return View();
}
6.Create Views of Controller
#{
Layout = null;
}
#Html.Raw(ViewData["result"])
7.Create seo.js in Script (!Important) Folder
var page = require('webpage').create();
var system = require('system');
var lastReceived = new Date().getTime();
var requestCount = 0;
var responseCount = 0;
var requestIds = [];
var startTime = new Date().getTime();;
page.onResourceReceived = function (response) {
if (requestIds.indexOf(response.id) !== -1) {
lastReceived = new Date().getTime();
responseCount++;
requestIds[requestIds.indexOf(response.id)] = null;
}
};
page.onResourceRequested = function (request) {
if (requestIds.indexOf(request.id) === -1) {
requestIds.push(request.id);
requestCount++;
}
};
function checkLoaded() {
return page.evaluate(function () {
return document.all["compositionComplete"];
}) != null;
}
// Open the page
page.open(system.args[1], function () {
});
var checkComplete = function () {
// We don't allow it to take longer than 5 seconds but
// don't return until all requests are finished
if ((new Date().getTime() - lastReceived > 300 && requestCount === responseCount) || new Date().getTime() - startTime > 10000 || checkLoaded()) {
clearInterval(checkCompleteInterval);
console.log(page.content);
phantom.exit();
}
}
// Let us check to see if the page is finished rendering
var checkCompleteInterval = setInterval(checkComplete, 300);
8.Layout.cshtml Based On:
<!DOCTYPE html>
<html ng-app="appOne">
<head>
<meta name="fragment" content="!">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta charset="utf-8" />
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
<base href="/">
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
<script src="~/Scripts/angular/angular.js"></script>
<script src="~/Scripts/angular/angular-route.js"></script>
<script src="~/Scripts/angular/angular-animate.js"></script>
<script>
angular.module('appOne', ['ngRoute'], function ($routeProvider, $locationProvider) {
$routeProvider.when('/one', {
template: "<div>one</div>", controller: function ($scope) {
}
})
.when('/two', {
template: "<div>two</div>", controller: function ($scope) {
}
}).when('/', {
template: "<div>home</div>", controller: function ($scope) {
}
});
$locationProvider.html5Mode({
enabled: true
});
});
</script>
</head>
<body>
<div id="body">
<section ng-view></section>
#RenderBody()
</div>
<div id="footer">
<ul class='xoxo blogroll'>
<li>one</li>
<li>two</li>
</ul>
</div>
</body>
</html>
NOTE: PhantomJS cannot process Persian Links(UTF-8)
Third part, other things you may required to know...
I don't see any other thing that may be involved, if you saw one ask me i'll edit my question.
I wrote a small article on it, just some simple settings, it is tested and working see this
Add in your routing:
$locationProvider.html5Mode(true);
Index Page:
<base href="/">
And web.config:
<system.webServer>
...........
</system.webServer>
You are done.
Here's what i did:
for configuration:
<rule name="Crawler" stopProcessing="false">
<match url=".*"/> <!-- rule back-reference is captured here -->
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_URI}" matchType="Pattern" pattern="(.*)_escaped_fragment_=(.*)" ignoreCase="true" negate="true" /><!-- condition back-reference is captured here -->
</conditions>
<action type="Rewrite" url="{R:0}" /><!-- rewrite action uses back-references to condition and to rule when rewriting the url -->
</rule>
<rule name="Index Rule" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/api/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Token" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/bundles/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Content/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Scripts/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/SiteMap/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/CallBackBank/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Error/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/HtmlSnapshot[^s]?/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Flight[^s]?/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Hotel[^s]?/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Tour[^s]?/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/TravelAgency[^s]?/" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/Users[^s]?/" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
And here's for Filter:
var request = filterContext.RequestContext.HttpContext.Request;
if (request.Url == null)
return;
var url = request.Url.Scheme + "://" + request.Url.Authority + request.RawUrl; //THIS LINE (`RowUrl` contains rest of the path)
I have setup Custom Errors for my site as my Web.config shows below:
<system.web>
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Error/Error400">
<error statusCode="400" redirect="~/Error/Error404"/>
<error statusCode="404" redirect="~/Error/Error404" />
<error statusCode="403" redirect="~/Error/Error403" />
<error statusCode="500" redirect="~/Error/Error500" />
</customErrors>
</system.web>
And also
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="400" />
<error statusCode="400" path="/Error/Error400" responseMode="ExecuteURL" />
<remove statusCode="403" />
<error statusCode="403" path="/Error/Error403" responseMode="ExecuteURL" />
<remove statusCode="404" />
<error statusCode="404" path="/Error/Error404" responseMode="ExecuteURL" />
<remove statusCode="500" />
<error statusCode="500" path="/Error/Error500" responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
I am throwing errors like this from my controllers:
throw new HttpException((int)HttpStatusCode.BadRequest, "The checklist Id is not specified. EntityId: " + this.LoggedInEntity.EntityId + "; userId: " + this.LoggedInUser.UserId);
The Error controller that handles the custom error page requests is:
public class ErrorController : Controller
{
public ActionResult Error400()
{
ErrorViewModel error = new ErrorViewModel();
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return View(error);
}
public ActionResult Error403()
{
ErrorViewModel error = new ErrorViewModel();
Response.StatusCode = (int)HttpStatusCode.Forbidden;
return View(error);
}
public ActionResult Error404()
{
ErrorViewModel error = new ErrorViewModel();
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View(error);
}
public ActionResult Error500()
{
ErrorViewModel error = new ErrorViewModel();
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return View(error);
}
}
However, in the example thrown exception which is a 400 Error, the 400 action doesn't get called. Instead, the 500 action gets called. How can I make it call the correct 400 action instead for the thrown error?
I am using ELMAH for my error logging and it is showing the correct error code:
According to the following answer, ResponseRewrite won't work with MVC routes:
https://stackoverflow.com/a/3770265/758765
If you read through Bens (awesome) blog post, he's using actual files to represent the 404 and 500 responses and not an MVC controller.
I'm trying to show a complete URL with MVC 4 web application like: localhost:8888/index.aspx, i want to show the complete URL in the browser. I found similar questions here and in this answer: https://stackoverflow.com/a/8557085 They say that the file extension can be seen.
But when i change the routes objetc like this:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}.aspx",
defaults: new { controller = "PaymentPortal", action = "PaymentPortal", id = UrlParameter.Optional }
);
or
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}.aspx",
defaults: new { controller = "PaymentPortal", action = "PaymentPortal", id = UrlParameter.Optional }
);
I get the next error: Error HTTP 403.14 - Forbidden
I try the next fixes, in the class RegisterRoutes i add the next line: routes.RouteExistingFiles = true;
In web.config i add, remove and change a few things like:
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<modules runAllManagedModulesForAllRequests="true"/>
I play with the ExtensionlessUrlHandler adding, deleting and changing the tags and the values but nothing. I add the modules runAllManagedModulesForAllRequests="true" but nothing either.
I'm working with VS2012 in Windows 8, MVC 4 with ASPX engine. Any help would be appreciate, thank you very much!
P.D.: My apologies if i made some mistake with my english.
I've just made a new MVC 4 application and created the routes:
routes.MapRoute(
name: "Test",
url: "{controller}/{action}.aspx",
defaults: new {controller = "Home", action = "Index"}
);
routes.MapRoute(
name: "TestId",
url: "{controller}/{action}/{id}.aspx",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
And the these url work
http://localhost:62312/Home/index/123test.aspx
http://localhost:62312/Home/index.aspx
Remember the order in which you create routes is important as well.
I have just change framework of my website from 2.0 to 4.0. And I am getting error HTTP Error 404.0 - Not Found whenever I try to open URL Rewriting webpage.
It was working fine at a time of Framework 2.0, don't know what is the wrong now. I have google many things but din't get any proper solution.
Please help me to solve the problem.
My Code is as below :
http://www.theprojectjugaad.com/PlacementAssistance.html -> Not Working
http://www.theprojectjugaad.com/PlacementAssistance.aspx -> Working
Global.asax :
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
void Application_BeginRequest(object sender, EventArgs ex)
{
if (!Request.Url.Host.Equals("localhost")
&& !Request.Url.Host.ToString().Contains("www.theprojectjugaad.com")
&& Request.Url.Host.ToString().Contains("theprojectjugaad.com"))
{
string Result = string.Concat(
"http://",
Request.Url.Authority.Replace("theprojectjugaad.com", "www.theprojectjugaad.com"),
HttpContext.Current.Response.ApplyAppPathModifier(Request.Path),
Request.Url.Query);
HttpContext.Current.Response.Redirect(Result, true);
}
}
private static void RegisterRoutes()
{
System.Web.Routing.RouteTable.Routes.Add(
"PlacementAssistance", new System.Web.Routing.Route("PlacementAssistance.html",
new RouteHandler("~/PlacementAssistance.aspx")));
}
RouteHandler.cs :
public RouteHandler(string virtualPath)
{
_virtualPath = virtualPath;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var display = BuildManager.CreateInstanceFromVirtualPath(
_virtualPath, typeof(Page)) as IDisplay;
return display;
}
string _virtualPath;
IDisplay.cs :
public interface IDisplay : IHttpHandler
{
}
web.config :
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="Session" />
<add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition="" />
</modules>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="UrlRoutingHandler" />
</handlers>
<rewrite>
<rules>
<remove name="Plesk. SEO-safe redirect for http://www.theprojectjugaad.com" />
<rule name="Plesk. SEO-safe redirect for http://www.theprojectjugaad.com" enabled="false" patternSyntax="Wildcard" stopProcessing="true">
<match url="*" />
<conditions>
<add input="{HTTP_HOST}" pattern="www.theprojectjugaad.com" />
<add input="{HTTPS}" pattern="OFF" />
</conditions>
<serverVariables />
<action type="Redirect" url="http://theprojectjugaad.com/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>
What is the URL that is not working?
What I see is you've corrected the URL from .html to .aspx and it works.