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);
}
})
Related
I'm attempting to use Ajax to capture a submit event and then send the form elements formatted as JSON to a asp.net Web API 2. I am using the latest version of FireFox. Ad blocker is disabled. I have an SSL on both origin and destination. I have followed the steps in this guide to Enable cross-origin requests.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api
I have tested that my form with out javascript can send to the API no problem and recieve results.
I have also tested using Postman.
I would like to capture the response from the API and show it in an alert message.
here is a screen shot of the error in the browser
https://imgur.com/a/3wM7M1Y
here is a screen shot from postman of the server response confirming it accepts all
https://imgur.com/a/1MZ9dGE
Here is my HTML
`
<!DOCTYPE html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TLogin</title>
<link rel="stylesheet" href="CSS/main.css">
<script src="JS/main.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var form = $('#login_form')[0];
form.onsubmit = function (e) {
var data = $("#login_form :input").serializeArray();
console.log(data);
$.ajax({
type: 'POST',
url: "https://api.website.org/api/users/login",
xhrFields: {
withCredentials: false
},
data: data,
processData: false,
contentType: "application/json; charset=utf-8",
success: function (data) {
alert(data);
},
error: function (xhrRequest, status, error) {
alert(JSON.stringify(xhrRequest));
}
});
return false;
}
});
</script>
</head>
<html>
<body>
<form id="login_form">
<div class="master_container">
<div id="views_container" class="clear">
<div class="view_container">
<span>Username :</span>
<input type="text" id="username" name="username">
</div>
<div class="view_container">
<span>Password :</span>
<input type="password" id="password" name="password">
</div>
<div class="view_container">
<input id="ip" type="hidden" value="myip" />
<input type="submit" id="Button_Login" value="Login" />
</div>
<div class="view_container">
</div>
</div>
</div>
</form>
</body>
</html>
`
Here is my API Controller Info
`
[EnableCors(origins: "*", headers: "*", methods: "*", exposedHeaders: "*", SupportsCredentials = false)]
public class UsersController : ApiController
{
//user login
[Route("api/Users/Login")]
[HttpPost]
public UsersSession Login(Users users)
{
UsersSession UsersSession = new UsersSession();
UsersSession.result = new Result();
try
{
if (users != null && !string.IsNullOrWhiteSpace(users.username) && !string.IsNullOrWhiteSpace(users.password))
{
var v_meta_list = new List<string>();
var v_search_results = new List<string>();
v_meta_list.Add("username=" + users.username);
v_meta_list.Add("password=" + users.password);
v_search_results = CL_db.db_search("4", v_meta_list, true);
if (v_search_results != null && v_search_results.Count > 0)
{
UsersSession.userid = v_search_results[0];
UsersSession.result.result = true;
UsersSession.result.message = "success";
}
else
{
UsersSession.result.result = false;
UsersSession.result.message = "Invalid user";
}
}
else
{
UsersSession.result.result = false;
UsersSession.result.message = "Please enter username and password";
}
}
catch (Exception ex)
{
UsersSession.result.result = false;
UsersSession.result.message = "Error occurred: " + ex.Message.ToString();
}
return UsersSession;
}
}
Here is the web.config
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="*" />
<add name="Access-Control-Allow-Methods" value="*" />
</customHeaders>
</httpProtocol>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
`
So the issue was that I had the cors stuff defined in too many locations.
The solution was simply to only have the code for the WebApiConfig.cs
I removed the code from the web.config and the controller.
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 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
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.