I'm currently a little new to Microsoft's MVC4 and I don't quite understand routing as well as I would like.
What I am trying to do is make my URLs more human readable. Currently I have URLs that look like this:
foo.com/UserProfile/Details/6
foo.com/UserExperience/Details/
foo.com/UserSpecificController/Edit/8
All of the user controllers are prefixed with "User" I was wondering if it was possible to change those URLs so they look like this:
foo.com/u/Profile/Details/6
foo.com/u/Experience/Details/
foo.com/u/SpecificController/Edit/8
My first attempt was with IIS:
<rewrite>
<rules>
<rule name="AddTrailingSlashRule1" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Redirect" url="{R:1}/" />
</rule>
<rule name="Pretty User Redirect" enabled="false" stopProcessing="true">
<match url="User(.*)/(.*)" />
<action type="Redirect" url="u/{R:1}/{R:2}" />
<conditions>
</conditions>
</rule>
<rule name="User pretty URL Rewrite">
<match url="u/(.*)/(.*)" />
<action type="Rewrite" url="User{R:1}/{R:2}" />
</rule>
</rules>
</rewrite>
This worked quite well except I would get /u/ on all of my links, everywhere...
For example:
foo.com/Home/WhatWeDo/
would come out like:
foo.com/u/Home/WhatWeDo/
This would then 404.
I am using the default routing configuration
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
And all of my links are drawn with #Html.ActionLink(...)
If anyone could shed some light on this, that would be greatly appreciated.
Remove your custom IIS rewrite rules and insert this before your Default route
routes.MapRoute(
name: "UserProfile",
url: "u/Profile/{action}/{id}",
defaults: new { controller = "Home", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "UserExperience",
url: "u/Experience/{action}/{id}",
defaults: new { controller = "Home", id = UrlParameter.Optional }
);
Edit: Areas
With Areas you group related controllers
Profile controller within a User area
/User/Profile/Details
Experience controller
/User/Experience/Details
Then just one custom rule for that area's RegisterArea to substitute the 'u' in your routes
context.MapRoute(
"UsersRoute",
"u/{controller}/{action}/{id}",
new { Controller = "Home", action = "Index", id = UrlParameter.Optional },
new string[] { "MyNamespace.MyProj.Areas.User.Controllers" }
);
Related
I have issue with url Rewrite and ajax request.
here's my config for URL Rewrite:
<rewrite>
<rules>
<rule name="RewriteASPX" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="{R:1}.aspx" />
</rule>
</rules>
</rewrite>
it works with this URL
https://www.example.com/section?data=data
or
https://www.example.com/section
but unfortunately, I have ajax request on my code :
https://www.example.com/section/method
the rule always rewrite the method to be https://www.example.com/section/method.aspx
here's my ajax request script
<script>
debugger
var phone = $('#<%=hidPhoneNO.ClientID %>').val();
var check = $('#<%=hidCheckOutID.ClientID %>').val();
var data = $('#<%=hidData.ClientID %>').val();
var fails = "/Failed?Data=".concat(data)
var suc = "/Success?Data=".concat(data)
$.ajax({
type: "POST",
data: JSON.stringify({ CheckOutID: check, PhoneNo: phone }),
url: "Section/Method",
contentType: "application/json; charset=utf-8",
dataType: "json",
complete: function (data) {
var json = JSON.parse(data.responseText);
/* alert(json["d"]);*/
if (json["d"] === "00") { location.href = fails }
else { location.href = suc }
},
});
</script>
is there any work around to keep the re-write function and done the ajax method call ?
You can use regular expressions in rewrite rules to exclude specific path: Section/Method
<match url="(.*)" /> changed to <match url="^(?!.*section/method).*" />
When the requested URL is https://www.example.com/section/method, it will not follow this rule, the request will not be rewritten.
I have developed a full-stack application with Vue 2, Node , Express and Postgres.
I could deploy the application to Azure , and the system coming up, but when I try to do register user with Register page that I have created , I get " POST … 500 (Internal Server Error) ", **as I have tried with Postman , there is no issue in saving user data with same post controller ** .
Notice that I have set BaseURL to ‘’ in Api.js ( Client ):
import axios from ‘axios’
import store from ‘#/store/store’
export default () => {
return axios.create({
baseURL: ‘’,
headers: {
Authorization: Bearer ${store.state.token}
}
})
}
this is Register controller in /Controller folder :
//Registering user
async register(req, res) {
const hash = bcrypt.hashSync(req.body.password, 10);
try {
const user = await User.create(
Object.assign(req.body, { password: hash })
);
const userJson = user.toJSON();
res.send({
user: userJson,
token: jwtSignUser(userJson),
});
} catch (err) {
res.status(500).send({
error: There is error in registering: ${err},
});
}
},
I have added the following web.config file in dist folder, but it doesn't resolve the issue :
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension="woff" mimeType="application/font-woff" />
<mimeMap fileExtension="woff2" mimeType="application/font-woff" />
</staticContent>
<rewrite>
<rules>
<clear />
<rule name="Redirect to https" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTPS}" pattern="off" ignoreCase="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" appendQueryString="false" />
</rule>
</rules>
</rewrite>
<httpErrors>
<remove statusCode="404" subStatusCode="-1" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="404" path="/survey/notfound" responseMode="ExecuteURL" />
<error statusCode="500" path="/survey/error" responseMode="ExecuteURL" />
</httpErrors>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Could you please let me know how I could resolve the issue .
I have a Node Application I'd like to run using IIS. The problem is my configuration file. I am using IIS 10.0 and don't know how to configure everything correctly? Whenever I include both of these rules in my Web.Config file...
<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
<rule name="StaticContent" patternSyntax="Wildcard">
<action type="Rewrite" url="public/{R:0}" logRewrittenUrl="true"/>
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
</conditions>
<match url="*.*"/>
</rule>
<!-- All other URLs are mapped to the Node.js application entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="server.js"/>
</rule>
...I get a 500.1000 Error that looks like this:
500.1000 ERROR
When I take one or the other out, my websites pages and links load correctly but ALL POST requests create a 404 error? Because it's searching for a physical path instead of calling a POST function in my server.js file?
Here is the 404 ERROR:
404 ERROR
I know that my site works, because it works (GET & POST requests) in the debugger for VS 2015. Here are snippets from my code and the configuration file.
Here is the full Web.Config file :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<!--
All appSettings are made available to your Node.js app via environment variables
You can access them in your app through the process.env object.
process.env.<key>
-->
<!-- Unconmment the below appSetting if you'd like to use a Virtual Directory -->
<!-- <add key="virtualDirPath" value="" /> -->
</appSettings>
<system.webServer>
<iisnode node_env="%node_env%"
nodeProcessCountPerApplication="1"
maxConcurrentRequestsPerProcess="1024"
maxNamedPipeConnectionRetry="100"
namedPipeConnectionRetryDelay="250"
maxNamedPipeConnectionPoolSize="512"
maxNamedPipePooledConnectionAge="30000"
asyncCompletionThreadCount="0"
initialRequestBufferSize="4096"
maxRequestBufferSize="65536"
uncFileChangesPollingInterval="5000"
gracefulShutdownTimeout="60000"
loggingEnabled="true"
logDirectory="iisnode"
debuggingEnabled="true"
debugHeaderEnabled="false"
debuggerPortRange="5058-6058"
debuggerPathSegment="debug"
maxLogFileSizeInKB="128"
maxTotalLogFileSizeInKB="1024"
maxLogFiles="20"
devErrorsEnabled="true"
flushResponse="false"
enableXFF="false"
promoteServerVars=""
configOverrides="iisnode.yml"
watchedFiles="web.config;*.js"
nodeProcessCommandLine="C:\Program Files\nodejs\node.exe"/>
<!--
Before the handlers element can work on IIS 8.5
follow steps listed here https://github.com/tjanczuk/iisnode/issues/52
-->
<handlers>
<add name="iisnode" path="server.js" verb="*" modules="iisnode"/>
<!-- Uncomment below handler if using Socket.io -->
<!--<add name="iisnode-socketio" path="server.js" verb="*" modules="iisnode" />-->
</handlers>
<rewrite>
<rules>
<!-- Don't interfere with requests for node-inspector debugging -->
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^server.js\/debug[\/]?"/>
</rule>
<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
<rule name="StaticContent" patternSyntax="Wildcard">
<action type="Rewrite" url="public/{R:0}" logRewrittenUrl="true"/>
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
</conditions>
<match url="*.*"/>
</rule>
<!-- All other URLs are mapped to the Node.js application entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="server.js"/>
</rule>
<rule name="SocketIO" patternSyntax="ECMAScript">
<match url="socket.io.+"/>
<action type="Rewrite" url="server.js"/>
</rule>
</rules>
</rewrite>
<directoryBrowse enabled="false"/>
</system.webServer>
</configuration>
Here is the general structure of my server.js file :
var http = require('http');
var express = require('express');
var fs = require("fs");
var sql = require("mssql");
var bodyParser = require('body-parser'); // Used to parse incoming messages
var Connection = require('tedious').Connection; // Added for Azure
var app = express();
var port = process.env.port || 1337;
// pulls the index.html file
app.use(express.static(__dirname + "/"));
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
// DATABASE configuration
var config = {
userName: 'USERNAME',
password: 'PASSWORD',
server: 'SERVER',
options: {
encrypt: true,
database: 'DATABASE',
rowCollectionOnRequestCompletion: true
}
};
var connection = new Connection(config);
// Server that listens to port 80
var server = http.createServer();
var server = app.listen(port, function () {
var host = server.address().address
var port = server.address().port
console.log("Node Js app listening at http://%s:%s", host, port)
});
app.post('/postrequest', function (req, res) {
// function
});
Thanks for the help. I can't seem to figure out this issue.
I make post requests in a separate script that is in a separate folder in this directory called scripts:
xhttp.open("POST", "http://localhost:80/My Application/postrequest", false);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("date=" + date + "&name=" + name + "&type=" + type);
I was able to successfully publish my Node Web Application to IIS by using the following configuration in my Web.Config :
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="server.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<!-- Don't interfere with requests for node-inspector debugging -->
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^server.js\/debug[\/]?"/>
</rule>
<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
<rule name="StaticContent" patternSyntax="Wildcard">
<action type="Rewrite" url="public/{R:0}" logRewrittenUrl="true"/>
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
</conditions>
<match url="*.*"/>
</rule>
<!-- All other URLs are mapped to the Node.js application entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="server.js"/>
</rule>
<rule name="SocketIO" patternSyntax="ECMAScript">
<match url="socket.io.+"/>
<action type="Rewrite" url="server.js"/>
</rule>
</rules>
</rewrite>
<iisnode promoteServerVars="LOGON_USER" />
</system.webServer>
</configuration>
AND by changing my server.js file to :
var http = require('http');
var express = require('express');
var bodyParser = require('body-parser'); // Used to parse incoming messages
var port = process.env.port;
var app = express(function(req, res){
username = req.headers['x-iisnode-auth_user'];
});
app.use(express.static(__dirname + "/ApplicationNameOnIIS/"));
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
// Start listening on server port
app.listen(process.env.PORT);
app.get('/ApplicationNameOnIIS/', function(req, res) {
res.sendfile(__dirname + '/index.html');
});
// ...The Rest Of My Code...
I have this include at the top of all of my ASP pages, to redirect to https for all pages NOT in folders called "words" and "generators". I don't want them on ssl as I heard moving to SSL can have a big impact on AdSense income.
I also redirect so that if a user ends up on an SSL version of pages in the words and generators folders, it takes them to the non ssl page.
And finally I have one that redirects from the www version of a page to the non www version, e.g. www.test.co.uk to test.co.uk
My code is below.
I wondered if I am doing this in a very resource intensive way and if there is a better way to do it using web config or something like that, or is it a case of if it isn't broken, don't fix it?
I realise my code is very basic and clunky, sorry.
SERVER_NAME = lcase(Request.ServerVariables("SERVER_NAME"))
SCRIPT_NAME = lcase(Request.ServerVariables("SCRIPT_NAME"))
QUERY_STRING = lcase(Request.ServerVariables("QUERY_STRING"))
SECURE_MODE = lcase(Request.ServerVariables("SERVER_PORT_SECURE"))
str0 = request.servervariables("url")
arrFolderData = Split(str0, "/")
strLastFolder = arrFolderData(UBound(arrFolderData)-1)
words_str = instr(strLastFolder,"words")
gens_str = instr(strLastFolder,"generators")
'' if page = http, and page is not in "words" or "generators" folder then redirect to https version of page
if SECURE_MODE = 0 AND words_str = 0 AND gens_str = 0 then
SERVER_NAME = replace(SERVER_NAME, "www.", "")
go_to_url = ""
go_to_url = go_to_url & "https://"
go_to_url = go_to_url & SERVER_NAME
go_to_url = go_to_url & SCRIPT_NAME
if QUERY_STRING <> "" then
go_to_url = go_to_url & "?" & QUERY_STRING
end if
Response.Buffer = true
Response.Status = "301 Redirect"
Response.AddHeader "Location", lcase(go_to_url)
Response.End
end if
'' if page = https, and page is in "words" or "generators" folder then redirect to http version of page
if SECURE_MODE = 1 AND (words_str = 1 OR gens_str = 1) then
SERVER_NAME = replace(SERVER_NAME, "www.", "")
go_to_url = ""
go_to_url = go_to_url & "http://"
go_to_url = go_to_url & SERVER_NAME
go_to_url = go_to_url & SCRIPT_NAME
if QUERY_STRING <> "" then
go_to_url = go_to_url & "?" & QUERY_STRING
end if
Response.Buffer = true
Response.Status = "301 Redirect"
Response.AddHeader "Location", lcase(go_to_url)
Response.End
end if
'' redirect to non "www" version of page
if left(SERVER_NAME,3) = "www" then
SERVER_NAME = replace(SERVER_NAME, "www.", "")
go_to_url = ""
go_to_url = go_to_url & "http://"
go_to_url = go_to_url & SERVER_NAME
go_to_url = go_to_url & SCRIPT_NAME
if QUERY_STRING <> "" then
go_to_url = go_to_url & "?" & QUERY_STRING
end if
Response.Buffer = true
Response.Status = "301 Redirect"
Response.AddHeader "Location", lcase(go_to_url)
Response.End
end if
Thanks to the help from #Carlos Aguilar Mares I was able to replace the code above with:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Canonical HostName" stopProcessing="true">
<!-- Redirect to the non-www host -->
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^www\.(.*)$" />
</conditions>
<action type="Redirect" url="http://{C:1}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="NON HTTPS" enabled="true" stopProcessing="true">
<!-- Redirect to HTTPS as long as pages are not in words, generators or v folders -->
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="off" />
<add input="{REQUEST_URI}" pattern="^/words/[a-z 0-9]*" negate="true" />
<add input="{REQUEST_URI}" pattern="^/generators/[a-z 0-9]*" negate="true" />
<add input="{REQUEST_URI}" pattern="^/v/[a-z 0-9]*" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Yes, that could be easily done and likely much faster (no longer in script, no longer parsing the code, regex and logic in native code, plus more maintainable, etc) if using URL Rewrite and configuring that in your web.config.
The rules would look something like the following:
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="NON HTTPS" enabled="true" stopProcessing="true">
<!-- Redirect to HTTPS as long as it does not end in words/generators -->
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="off" />
<add input="{URL}" pattern="(words|generators)$" negate="true" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="HTTPS" enabled="true" stopProcessing="true">
<!-- Redirect to HTTPS as long as it ends in words/generators -->
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="on" />
<add input="{URL}" pattern="(words|generators)$" />
</conditions>
<action type="Redirect" url="http://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
<rule name="Canonical HostName" stopProcessing="true">
<!-- Redirect to the non-www host -->
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^www\.(.*)$" />
</conditions>
<action type="Redirect" url="http://{C:1}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
What is the proper way to convert this lines to IIS web.config? I am trying to use Backbone Router with history support. It works perfect with .htaccess but i have no idea about how to do this on IIS.
.htaccess file
# html5 pushstate (history) support:
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !index
RewriteRule (.*) index.html [L]
</ifModule>
this is the script included in index.html
$(document).ready(function(){
var AppRouter = Backbone.Router.extend({
routes: {
'': 'home',
'about(/)': 'about', //about or /about/ will call the same function
'work(/:id)' : 'work',
"*path" : "notFound"
}
});
// Initiate the router
var app_router = new AppRouter;
app_router.on('route:home', function() {
$("#log").html("home");
});
app_router.on('route:about', function() {
$("#log").html("about");
});
app_router.on('route:work', function(id) {
$("#log").html("work " + id);
});
app_router.on('route:notFound', function(path) {
$("#log").html("404 " + path);
});
Backbone.history.start({pushState: true, root: "/post43/"});
$(document).on("click", "a:not([data-bypass])", function(e) {
// Get the anchor href and protcol
var href = $(this).attr("href");
// Stop the default event to ensure the link will not cause a page refresh.
e.preventDefault();
Backbone.history.navigate(href, true);
});
});
After some digging, this piece of code works on IIS for me. I was looking this guide when converting my htaccess. I hope it will help others who are looking for this kind of solution.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="history" stopProcessing="true">
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
<add input="{URL}" pattern="^index$" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="index.html" appendQueryString="true" />
</rule>
</rules>
</rewrite>
<defaultDocument>
<files>
<remove value="index.html" />
<add value="index.html" />
</files>
</defaultDocument>
</system.webServer>
</configuration>