I have an Angular 2 application created with Angular CLI. This has to call a .NET 4.6 Web API. The route setup of this is driving me nuts.
For Angular, the default folder for output is /dist
. Angular CLI does all the minification and tree-shaking you can dream of and then outputs both its JavaScript files and index.html
to that folder.
So if I run index.html
, those files are retrieved from the same folder. Everything works well, because index.html
contains a tag like this one:
<base href="/">
The Web API project has the expected structure, with the Angular app a parasite in its root.
So it looks like this:
WebAPI_Project
|- App_Start
| |
| |-WebApiConfig.cs
|- Controllers
|- Models
|- src /* This is the root of the Angular app */
| |- app
| | |- core /* These three folders */
| | |- shared /* are for the modules */
| | |- another_module /* used in the app */
| | |- app.component.ts
| | |- app.module.ts
| |- index.html
|- dist /* This is the Angular output folder */
|- index.html
|- main.bundle.js
WebApiConfig.cs
has the default setup:
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
To run the Angular app, I use normal ng serve
, which create a web server at http://localhost:4200
. This web server knows nothing about the Web API project, so I need to run that as well from within Visual Studio, which starts up IIS Express at http://localhost:5200
.
This setup works reasonably well and allows me to take advantage of Angular CLI's live reload support.
The biggest drawback for me is that this configuration is different from what we expect for production. There, I would expect to have one web server (IIS), serving both the Web API project (at /api/
as presently) and the Angular app (at /
, preferably). Also, in dev, I'm having to think of CORS, which the production setup wouldn't.
To do this, I need to change the WebApiConfig routing to serve my static files, which will be under /dist/
.
For ASP.NET Core and for MVC 4, there are numerous articles showing how I should use Microsoft.AspNetCore.StaticFiles
(or Microsoft.AspNet.StaticFiles
) in Startup.cs
. Basically, add the following two lines to the Configure
function:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
// Other stuff
// Two new lines
app.UseStaticFiles();
app.UseDefaultFiles();
app.UseMvc(m =>
{
// Other routes specified here
});
}
The problem is that I don't use either ASP.NET Core or MVC.
Despite Web API apparently being MVC without the views, a Web API project comes with only the WebApiConfig.cs
file, no Startup.cs
and no `IApplicationBuilder'.
I tried adding this line to my Register
function:
config.Routes.IgnoreRoute("StaticFiles", "*.html");
This serves the index.html (but at localhost:5200/dist/index.html
), but it cannot find any of its assets, because base href="/"
. I can change that in index.html
, but then ng serve
breaks.
I think I need one of two things:
- A way to create a route so a reference to
/index.html
serves/dist/index.html
, or - A way to use the StaticFiles assembly mentioned before.
So how would I accomplish that?
3 Answers 3
You need first disable web api routing for angular files, add this to web.config, inside <system.webServer> </system.webServer>
:
<rewrite>
<rules>
<rule name="AngularJS" 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="/index.html" />
</rule>
</rules>
</rewrite>
And then, add <base href="/">
to your index.html.
UPD: Rewrite access to index.html
You can add another rewrite rule to override access to your /dist/
folder:
<rewrite>
<rules>
<rule name="DistAccess" stopProcessing="true">
<match url="^(.*)/dist/(.*)" />
<action type="Rewrite" url="{R:1}/{R:3}" />
</rule>
</rules>
</rewrite>
-
Great! I can now serve my Angular app from either Visual Studio or
ng serve
. Is there a way for me to rewrite it so that index.html is at/
, not/dist/
?Cobus Kruger– Cobus Kruger2017年01月26日 14:53:54 +00:00Commented Jan 26, 2017 at 14:53 -
I completely dont understand what u need, if you need to access your app like
yourdomain.com/some-angular-url
you need to change rewrite action to<action type="Rewrite" url="/dist/index.html" />
, but if you want to store your index.html out of dist folder, you need to work with your module bindlerDmitriy Kovalenko– Dmitriy Kovalenko2017年01月26日 15:01:11 +00:00Commented Jan 26, 2017 at 15:01 -
The HTML and JS files are all under
/dist/
. I want them to be served at/
, so if a user loads the site atwww.something.com/
, he'll be servedindex.html
, which should have access to all its script files.Cobus Kruger– Cobus Kruger2017年01月26日 15:13:34 +00:00Commented Jan 26, 2017 at 15:13 -
If you link your action to
/dist/index.html
you will get same result, but only data will be stored inside/dist/
, but users would seewww.something.com/
as wellDmitriy Kovalenko– Dmitriy Kovalenko2017年01月26日 15:16:24 +00:00Commented Jan 26, 2017 at 15:16 -
We're missing each other somewhere. Using your answer, I can still only access the app at
/dist/index.html
, the address bar reflects/dist/
and the resources cannot be loaded (base href = "/"). What I want is for the address bar to display/
,/dist/index.html
to be served. Its JS files to be accessed using/script.js
but actually served from/dist/script.js
.Cobus Kruger– Cobus Kruger2017年01月26日 15:29:44 +00:00Commented Jan 26, 2017 at 15:29
I just couldn't get Dmitriy's answer to work for me, but he did put me on the right track.
I needed two rules: One to serve the Angular app from the root while maintaining the Web API /api/
routing, and another to serve the default document.
Here they are:
<rewrite>
<rules>
<rule name="Serve Angular app from root" stopProcessing="true">
<match url="([\w\.]+)" />
<conditions>
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/dist/{R:1}" />
</rule>
<rule name="Default document" stopProcessing="true">
<match url="^$" />
<action type="Rewrite" url="/dist/index.html" />
</rule>
</rules>
</rewrite>
-
I have a similar situation. Adding this to web.config file doesn't seem to work for me. I added this to the <system.webServer> sectionDragoRaptor– DragoRaptor2017年06月13日 14:58:29 +00:00Commented Jun 13, 2017 at 14:58
-
This worked for me except that I deployed angular 2 files in root itself so I removed /dist from your example. Thanks.Abhi– Abhi2017年09月14日 13:27:40 +00:00Commented Sep 14, 2017 at 13:27
-
This works when used a domain name. If we have route in the URL and paste it on the address bar it still goes for a search of an API instead of loading index.html with route parametersParesh Varde– Paresh Varde2018年06月12日 06:00:33 +00:00Commented Jun 12, 2018 at 6:00
First of all you should publish your angular project like this below.
ng build --prod="true" --base-href /
Then add web config file to your angular project .
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<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>
</system.webServer>
</configuration>
notice url in <action type="Rewrite" url="/" />
is that url in --base-href /
.
Explore related questions
See similar questions with these tags.