Angular routing first, mvc routing otherwise - angularjs

I have an application using Angular and node.js (running on IIS 7.5) for the UI, and then a .NET Web API for all the endpoint calls.
Angular routing is working as expected, and API routing is working as expected...when running the API through Visual Studio/IIS Express and ng serve to fire up the UI. Of course, they're running on two separate ports.
The goal is to deploy to a single IIS Web Site and, unfortunately, a single Application Pool.
Given the URL of http://www.mycoolapplication.com for the UI and http://www.mycoolapplication.com/api for the API, how to I get Angular to ignore routing for anything matching api and all of api's children?
I'm going through the Routes module, and would love to be able to add something to a path object, but there doesn't appear to be anything to accomplish excluding something from the Angular routing table.

Put this web.config in your frontend app (the folder with index.html). It will handle all requests except api/*.
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="API Rule" stopProcessing="true">
<match url="^(api)(.*)$" />
<action type="None" />
</rule>
<rule name="Angular" 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>
</configuration>

Related

IIS URL Rewrite for nested application

I have SPA developed in React and back-end as ASP.NET Web API. The React application is hosted in IIS and have a rewrite URL so if the page is refreshed the page stays. The URL rewrite looks like
<rules>
<rule name="ReactJS Routes" 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>
Now I hosted Web API application as a child application (nested application) in IIS with React application as parent. Now the issue is when the front-end application makes a request to Web API I get 403 - Forbidden: Access is denied.
I checked and both the parent and child applications have Require SSL unchecked. When I removed the rewrite rule in web.config everything is working except I cannot refresh the page. So how to have rewrite rule with the nested application. Just to provide more details, we are using IIS 10 and name of the site is ReactApp and WebApiApp (child application). The application runs in https.
I fixed it by adding the following in rewrite url
<match url="^((?!childapp).)*$" />
where childapp is the name of the nested application. So basically saying that if it is not Web API call then use the rule otherwise ignore the rule for the back-end API calls.

angularjs default page without having to type index.html

I'm creating an angularjs app with VS 2017 community. When I run the app locally I get the localhost with port in the address bar but it doesn't take me to index.html by default. If I type index.html in then it works, but since all routing goes through the angular app which is hooked up in index.html this ruins routing. I can't type localhost:portnumber/my_other_route_here since it then doesn't go through the angularjs app defined in index.html. How do I get IISExpress to do this automatic routing to index.html without having to type index.html?
I have the following in my config file and thought it would help with that and has in the past so not sure what is different this time.
<!-- Must have this so that direct entries in the browsers address bar get routed correctly. This routes entires that don't have physical paths to index.htm which
will route it correctly if a path is setup. Basically this allows for pretty url's like localhost:1234/red -->
<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>
<!-- END rules -->
So I used the default ASP.NET Application template for Web API (Not MVC) but it adds MVC anyway. The fact that it had a RegisterRoutes() which was doing some mapping seems to be why this was happening. When I comment out everything in here (can probably delete the entire file) then by default it would open index.html without having to put it in the address bar.

IIS URL redirect on sub application holding react SPA

I have an existing ASP.Net MVC hosted in IIS that is being extended/replaced using a react SPA which has to sit under the site in IIS in an application.
This has been done as there are many deployed instances of this for multiple clients which cannot be tenanted for business reasons and the existing system is web-forms and due to how its built there is no desire to add the SPA to the project, it was decided that the sub-app would be the easiest way to deploy the new functionality - did not want another MVC project or make the WebApi project serve the static pages due to other client related customizations that have to be accommadated.
The SPA talks to a new WebApi backend which is itself an application under the react application.
To help visulise it looks like this:
Now this all works, the SPA can be loaded from the parent app simply by a normal href and the SPA talks happily to the WebApi backend.
Where I've hit a brick wall is sorting out the IIS Url rewrite rule so that if the user hits F5 in the SPA that IIS will return the SPA index.html and then client side routing (react router v4) will handle rendering the correct components.
The url rewrite rule is defined in the v5 application.
I've followed the advice on questions such as this one and this one and if the react SPA is at the root of the site it works perfectly but as soon as I move to the sub-app all I receive is a 404 response that states the full Url cannot be found e.g. when requesting Url localhost/v5/documents IIS tries to find a v5/documents file/directory which doesn't exist.
To take the existing system out of the equation I've got the site deployed to a new folder where the top level site has no content and the react site is in the v5 application and the webapi in the api folder - again all working.
I've tried several patterns for the match, the current pattern I'm using is .*/v5/?.* which the test pattern functionality in IIS Manager tells me matches the url's I expect e.g. url of localhost/v5/documents should be matched but in practice never is.
I found this link about configuring angular and this Rick Strahl post which touches on creating the rules but with no luck.
The full config I'm using at the moment is
<rewrite>
<rules>
<rule name="Rewrite Text Requests" enabled="true" stopProcessing="true">
<match url=".*/v5/?.*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_URI}" pattern="/api(.*)$" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="{HTTP_HOST}/v5/index.html" logRewrittenUrl="false" />
</rule>
</rules>
</rewrite>
I've also installed Failed Request Tracing but when I look at the logs I don't see the url rewrite being fired for the request which is why it then tries to find the non-existent file/directory.
I've uploaded the Failed Request Tracing log here
I'm using IIS 10.0.15063.0 on windows 10, react site created with create-react-app (I'm testing using a production build not webpackdevserver) and WebApi project is .Net Framework 4.7
I just reproduced you're scenario in the simplest way I could think of.
I created a web site named MySite with two applications /v5 and /v5/api.
I put the following in the web.config for the v5 application, so the web.config was in the root directory of v5
<rewrite>
<rules>
<rule name="Rewrite Text Requests" enabled="true" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_URI}" pattern="^/v5/api(.*)$" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/v5/index.html" logRewrittenUrl="false" />
</rule>
</rules>
</rewrite>
The url for the rule matches everything under the v5 application. The conditions are used to back off if the target is a file, directory, or anything in the api application.
The host name is not needed in the rewrite action.

ASP.NET 5 and Angular Routing not working on dnx rc1

Hi I have a project built in ASP.NET 5 (dnxcore50 and dnx451). It is serving the requests for my AngularJS scripts. When I built the project I was using the Microsoft beta 5 dependencies and using a rewrite rule to send all the requests to index.html and so my angular routing would work just fine. But today I had to upgrade to the rc1 dependencies and now my rewrite is not working and I'm just getting a 404 on my route. This new libraries added this weird lines of code to my web.config
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" forwardWindowsAuthToken="false" startupTimeLimit="3600" />
Is there a way how can I set my routing so that it works with angular for example if I go to localhost/shop it will redirect it to index.html and my angular routing will take over.
I am on similar setup and I have in Configure in Startup.cs,
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseIISPlatformHandler();
and a rewrite rule in system.webServer in web.config, needed that to be able to have both web api and index.html angular app served:
<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>
You may need something similar too with your own rules
I think there is a better way than using the url rewrite in the routing setup (So that there is no need for the url rewrite at all). E.g. I did this:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "api",
template: "api/{controller}/{action}");
routes.MapRoute(
name: "angular",
template: "{*url}",
defaults: new {controller = "Home", action = "Index"},
constraints: new {url = new DoesNotContainConstraint(".", "api/") });
});
This ensures that all /api goes to controllers and everything else goes to the Index. I had to do my own DoesNotContainConstraint to ensure that files and api with wrong url are properly handled, but it's rather easy.
If you want to use ASP.NET 5/ASP.NET Core with IIS you need to install HttpPlatformHandler. Here is a nice step by step instruction showing how to install Http Platform Handler, configure IIS and publish an APS.NET Core application to IIS.

AngularJS Hashtags, Deep links and IE9

I am currently in a situation where I have to provide support for IE9, for an AngularJS app, while keeping hashtags out of my links (Links sent out from emails etc. whatever angular does client side, doesn't matter).
I've got to a point, where almost everything works, by using:
$locationProvider.html5Mode true
.hashPrefix '!'
This works perfectly for everything, converting links:
example.com/whatever
into
example.com/index.html#!/whatever
Now I have a problem, where if I hit the route: example.com
(A url with no params at all), my application won't start, and I get this error:
TypeError: Cannot read property 'indexOf' of undefined
Everything works fine in browsers which supports the history API.
When using HTML5Mode with ui-router, it's necessary to setup URL rewrites server side. How this is done is determined by your server side technology. A variety of methods are explained here.
For instance, IIS would use something like the following:
<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>
The result is that all incoming requests will be routed to the root of the site by IIS which in turn will load the index.html page which presumably has your ng-app tag and angular.js references. This will cause client side routing to kick in (ui-router in this case) and you'll be up and running in HTML5 routing mode.
So I figured out my problem.
We had the setting base href set to index.html, which would prepend index.html to all URLs in IE9 browsing.
When I changed the base href to / everything just works.

Resources