Rewrite rules for angular and ASP.NET MVC - asp.net

I'm following this article (the bottom section about using the URL Rewrite). My IIS Express (launched from VS) config file seems to be located C:\Users[usernamehere]\documents\IISexpress\applicationhost.config.
I place the rewrite rule inside the <system.webServer> tag like that article (and a lot of other articles I've read) say to. So it looks like:
<system.webServer>
<rewrite>
<rules>
<rule name="angularjs routes"
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}"
pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
... all the other crap that was already there
</system.webServer>
In my VS project I have index.htm off the root and my test views under a Views folder. This is the index.htm and it works when I click the link just fine.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-route.js"></script>
<head>
<base href="/">
<title></title>
<meta charset="utf-8" />
</head>
<body ng-app="myApp">
<p>Main</p>
Red
Green
Blue
<!-- below is where the partial pages will replace -->
<div ng-view></div>
<script>
var app = angular.module("myApp", ["ngRoute"]);
app.config(function($routeProvider, $locationProvider) {
$routeProvider
.when("/red", {
templateUrl: "Views/red.htm",
controller: "redController"
})
.when("/green", {
templateUrl: "Views/green.htm",
controller: "greenController"
})
.when("/blue", {
templateUrl: "Views/blue.htm",
controller: "blueController"
});
$locationProvider.html5Mode(true);
});
app.controller("redController", function($scope){
//alert("Red");
});
app.controller("blueController", function ($scope) {
//alert("Blue");
});
app.controller("greenController", function ($scope) {
//alert("Green");
});
</script>
</body>
</html>
The problem comes when I try to type in one of those pages direction: ie. http://localhost:60553/red
I get a 404. Which tells me that rewrite rule isn't being hit and doing it's job. Why am I getting a 404 even with that rewrite rule?

I am guessing this is because your Views folder has a web.config that explicitly blocks request to it. That is placed there by default in MVC projects for security reasons.
Note the following code in Views/Web.Config
<system.webServer>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
If you comment this out, your code should work.
However, I would advise moving your angular views to a different folder that isn't sort of a de-facto reserved folder for MVC. Change to something like ngView and this code will work. It will be cleaner and clearer that way, and you don't run the risk of exposing your razor code to snooping users.
UPDATE
The above is not the issue, per comments. The issue is that the rewrite rules were not being used from the file mentioned. Move them to web.config if possible - that will avoid setting up global rules that will apply to all iis express apps anyway.

Related

Routing issue in Aurelia with route params

Using Aurelia CLI 0.32, I have this route config
public configureRouter(config: RouterConfiguration, router: Router): void {
this.router = router;
config.options.pushState = true;
config.options.root = '';
config.map([
{ route: ['', 'home'], name: "home", moduleId: 'home/index', title: 'Main page' },
{ route: 'editroute/:id', name: "editroute", moduleId: 'edit/index', title: 'Edit Page' }
]);
config.fallbackRoute('');
}
Using a link
<a route-href="route: editroute; params.bind: {id:item.id}">Edit ${item.name}</a>
I can navigate to the route. But refreshing the page in the browser causes an error as seen in the screenshot
It is running on asp.net and there is a rewrite rule to support pushstate
<rewrite>
<rules>
<rule name="Main 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="{URL}" matchType="Pattern" negate="true" pattern=".*\/((api|signalr)\/.*|loaderio.*)" ignoreCase="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
What am I doing wrong?
Thanks
EDIT: This error only occurs on routes with routeparameters
In order for server-side page refresh to work when you are on deep URL, you have to modify your aurelia_project/aurelia.json to use absolute paths when bundling modules:
{
"build": {
"targets": [
{
// ...
"baseUrl": "/scripts",
"useAbsolutePath": true
}
],
// etc...
Another place, which is maybe not necessary to change, but contains same properties is:
{
"platform": {
// ...
"baseUrl": "/scripts",
"useAbsolutePath": true
}
Also, make sure you test Internet Explorer 11, since it's more picky then other browsers.
Of course, as already mentioned, you will also have to make sure that you use absolute paths for other resources as well (/scripts/vendor-bundle.js, font paths, etc..)
1st step is to try to change relative path to scripts/vendor-bundle.js to absolute /scripts/vendor-bundle.js
If it won't fix your problem - it will at least prevent downloading all the scripts for every route (-:
The rule is at fault. Since your html asks for a script with a relative path - the server looks in "the directory" and there is no file. So it gives up your index.html (or whatever is served # the root of site) instead of the script.

Can't add rewrite rules to web.config .net core

I have created a new web project with .net core.
The default web config looks like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
-->
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
</system.webServer>
</configuration>
When I open this config file I get a warning stating:
The element 'system.webServer' has invalid child element 'aspNetCore'.
But it let's me build and run my project.
My project is an angular application, so I want to add html5mode.
To do this, I should be able to add my rewrite rules:
<rewrite>
<rules>
<!-- AngularJS Html5model -->
<rule name="AngularJS Html5model" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="/index.html" />
</rule>
</rules>
</rewrite>
The problem is, as soon as I add my rules to my web.config file, like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
-->
<system.webServer>
<rewrite>
<rules>
<!-- AngularJS Html5model -->
<rule name="AngularJS Html5model" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Rewrite" url="/index.html" />
</rule>
</rules>
</rewrite>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
</system.webServer>
</configuration>
My application stops working. It's like it can't figure out what is a static file or not. Any static file can't be found now.
Looking at the rule, it statics that any file should be redirected to "/".
Does anyone know how to fix this issue?
It appears that this is a known error and won't be fixed until the end of this year. There is a workaround though.
I needed to add a RouteBuilder to my Startup class:
var routeBuilder = new RouteBuilder(app);
routeBuilder.MapGet("{*anything}", context =>
{
context.Response.Redirect("/index.html");
return Task.FromResult(0);
});
var routes = routeBuilder.Build();
app.UseRouter(routes);
This won't work by itself, you need to add the:
services.AddRouting();
to the ConfigureServices method.
here is my Startup class in its entirety:
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseDefaultFiles();
app.UseStaticFiles();
// Set up our images
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), #"images")),
RequestPath = new PathString("/images")
});
var routeBuilder = new RouteBuilder(app);
routeBuilder.MapGet("{*anything}", context =>
{
context.Response.Redirect("/index.html");
return Task.FromResult(0);
});
var routes = routeBuilder.Build();
app.UseRouter(routes);
}
}

How to enable $locationProvider.html5Mode for modern browser only?

I'm working on the web app using ASP.Net 5 and AngularJS. I have completed it and it works great, but when it was released live I found out it doesn't work in IE9 which is a big part in our company.
I'm using ui-router and I was fallowing Stephen Walter tutorial for the client routing: link here
Unfortunately his method to remove # from the URL works only for IE10+, because IE9 do not support HTML5 History API.
Spend few days on this one already and cannot find what step I have to keep using clean url for the modern browsers but not IE9?
My web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<rewrite>
<rules>
<!--Redirect selected traffic to index -->
<rule name="Index Rule" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="^/api/" negate="true" />
</conditions>
<action type="Rewrite" url="/index.html" />
</rule>
</rules>
</rewrite>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" startupTimeLimit="3600" forwardWindowsAuthToken="true" />
</system.webServer>
</configuration>
My app.js:
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', '$sceDelegateProvider',
function ($stateProvider, $urlRouterProvider, $locationProvider, $sceDelegateProvider) {
$locationProvider.hashPrefix('!').html5Mode({
enabled: true,
requireBase: false
});
$stateProvider
.state('app', {
abstract: true,
url: '',
templateUrl: '/templates/appcontainer.html',
controller: 'indexController'
})
.state('app.stateIndex', {
url: '/',
templateUrl: '/templates/list.html',
controller: 'dashListController'
})
.state('app.stateList', {
url: '/list',
templateUrl: '/templates/list.html',
controller: 'dashListController'
})
.state('app.stateDashboard', {
url: '/dashboard/:id',
templateUrl: '/templates/dashboard.html',
controller: 'dashboardController'
})
});
When I launch it in IE9, a blank page is displayed and when I check the source code index.html is loaded, but the content of <ui-view class="main-view"></ui-view> is not.
what step I have to keep using clean url for the modern browsers but not IE9?
Use a conditional statement in the config block to exclude IE9 from html5Mode via feature detection. For example:
if(!!$window.innerWidth && !$window.matchMedia)
{
$locationProvider.html5Mode({enabled: false, requireBase: false});
$locationProvider.hashPrefix("search");
}
else
{
$locationProvider.html5Mode({enabled: true, requireBase: false});
}
References
angular.js issue 10002: ng-controller on <html> tag fails on IE9

asp.net mvc hosting angular app with html5mode and routing

Alright, so I am hosting an angularjs inside asp.net mvc 5 and are using the html5mode(true) in my angular app to get rid of all hash signs in the url.
Everything works great, however, with my current setup that looks like this:
RouteConfig.cs:
routes.MapRoute(
name: "Default",
url: "app/{angular}",
defaults: new { controller = "Ng", action = "Index", angular= UrlParameter.Optional }
);
So that when I navigate to http://url/app/myangularroute my Ng/Index action returns the view which contains the ng-view container and the angular app is now active and working with the route provided
Now, my problem here is, when I navigate to http://url/app/ it returns a dir listning not allowed error which I cannot understand. Shouldn't my index action be returned as the angular parameter is set to optional?
And can I somehow avoid the "app" completely and still get my angular app to work? I have tried some rewrite rules but that gives me alot of errors because I am making use of the mvc bundling and minification functionality.
I could live with the url being the format it currently is but without the need to provide the optional parameter, like http://url/app/
Also, it's only an angular app, no other mvc view than the index.cshtml wrapper.
This guy seems to get it to work, but I can't see his mvc routes
Try adding this in your web.config sytem.webserver settings.
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<system.webServer>
EDIT:
Try changing your RouteConfig.cs, like this:
routes.MapRoute(
name: "Default",
url: "app/{*.}",
defaults: new { controller = "Ng", action = "Index" }
);
EDIT2:
I had completely forgoten about this question, but now I just realized that maybe the problem is that you haven't configured your IIS Server to work with Html5Mode, have a look at this: https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode
Concretelly this part:
Azure IIS Rewrites:
<system.webServer>
<rewrite>
<rules>
<rule name="Main Rule" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
I hope that this helps.
This is my solution. I am using ASP.NET MVC + Web API.
ASP.NET MVC always returns the same HTML page for any URL, so AngularJS can take over in $locationProvider.html5Mode(true);
RouteConfig.cs
routes.MapRoute(
name: "Default",
url: "{*anything}",
defaults: new
{
controller = "Home",
action = "Index",
}
);
WebApiConfig.cs
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}/{id1}",
defaults: new
{
action = RouteParameter.Optional,
id = RouteParameter.Optional,
id1 = RouteParameter.Optional,
}
);
HomeController.cs
public ActionResult Index()
{
return File("~/index.html", "text/html");
}
Alright, I got it to work.
By doing this:
Remove the "app" route completely, and use the standard route.
Add the rewrite rule
Remove the base href from the layout
Ohh wow, I turned off the bundling and minification, that was actually what made it work in the end. When I turn it on I get an angular error.
I honestly thought I tried this like 10 times without success. It started to show signs of working when I removed the base href.
Old question but still valid, this is my solution :
<rewrite>
<rules>
<rule name="Main Rule" stopProcessing="true">
<match url=".*"/>
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<!--for local dev enviroment-->
<add input="{REQUEST_URI}" pattern="^/(__browserLink)" negate="true" />
<!--if the url does not match a valid file we don't want it to be redirected to the index page-->
<add input="{REQUEST_URI}" pattern="\.(png|jpg|gif|css|js|html)$" negate="true" />
<!--web api route-->
<add input="{REQUEST_URI}" pattern="^/api/" negate="true" />
<!--ASP.NET Web API Help Page-->
<add input="{REQUEST_URI}" pattern="^/Help" negate="true" />
<!--Swagger-->
<add input="{REQUEST_URI}" pattern="^/apimap" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
With my ASP.NET 5 RC site - has WebAPI but not MVC - the solution was to up a default rewrite rule in wwwroot\web.config's system.webserver tag:
<rewrite>
<rules>
<clear />
<rule name="API" stopProcessing="true">
<match url="^(api)(.*)$" />
<action type="None" />
</rule>
<rule name="Main Rule" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
I am facing the same problem, i have set the base href in layout.cshtml ,put the webconfig rewrite rule, when loading the app,In bundle config i have set the all the scripts and css when launch the app ,its not get loaded . unexpected syntax error < is displayed in console.
when i remove the rule and base href and location provider is false , it working fine .
Angular Js Strange issue Ui Router Html5mode enabled page refresh issue in mvc 500 error

IIS 7 Rewrite web.config serverVariables directive not working in sub folder

I have the following code in my web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="IP Correction">
<match url="(.*)" />
<serverVariables>
<set name="REMOTE_ADDR" value="{HTTP_X-Forwarded-For}"/>
</serverVariables>
<action type="None" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
This works perfectly on the root of my site, however, the rule isn't being triggered in any of the sub folders.
I figured this out. The problem was in this line of code
<action type="None" />
You have to specify the rewrite action
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="IP Correction">
<match url="(.*)" ignoreCase="true" />
<serverVariables>
<set name="REMOTE_ADDR" value="{HTTP_X-Forwarded-For}" replace="true"/>
</serverVariables>
<action type="Rewrite" url="{R:0}" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
I faced a similar issue and created an IHttpModule to address it, which you can find here. URL Rewrite seems to have a bug where it won't execute on default document requests. The module doesn't have that issue. To implement it on your site, you'd add it to the <modules> section of your web.config, or if you want it to run server-wide, to your applicationHost.config.
The relevant bit of code is that you're hooking into HttpApplication's BeginRequest event, and running:
void OnBeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
string headervalue = app.Context.Request.Headers["X-Forwarded-For"];
if (headervalue != null)
{
Match m = REGEX_FIRST_IP.Match(headervalue);
if (m.Success)
{
app.Context.Request.ServerVariables["REMOTE_ADDR"] = m.Groups[1].Value;
app.Context.Request.ServerVariables["REMOTE_HOST"] = m.Groups[1].Value;
}
}
}
The Regex is ^\s*(\d+\.\d+\.\d+\.\d+). Full code at the gist.
If you compiled this code into a class library called HttpModules and put it in your GAC, you could then add this to your <modules> section, something like:
<add name="ClientIP" type="YourLibrary.ClientIP, YourLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=00DEADBEEF00" />

Resources