Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET Core: Deploy Web API and Angular from the Same Project to the Same IIS Port

0.00/5 (No votes)
13 Jul 2020 1  
Deploy Web API and Angular from the same project to the same IIS port
Previously, I used to host web API and Angular in different ports at IIS, the source codes were also allocated in different projects. Then I found a way to publish and deploy things together. Let's check how we can do it.

Introduction

Previously, I used to host web API and Angular using different ports at the same IIS, the source codes were also allocated in two different Visual Studio projects. Then I found a way to publish and deploy things together. Let's check how we can do it.

Project Structure

Here is my project structure. WebApiAndAngular is the main project.

Image 1

  • Controllers: All the API controller classes
  • ClientApp: Angular web UI project
  • wwwroot: Here, we are going to publish the Angular web UI project.

Angular Project Changes

Now, we are going to make some changes to our Angular project. The aim is to change the publish location from "dist" to API projects "wwwroot" folder. So in angular.json, let's change the output path to "outputPath": "../wwwroot".

Image 2

API Project Changes

Add the below code to .csproj file to manage typescript:

<PropertyGroup>
  <!--added me-->
  <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
</PropertyGroup>

SPA Startup

There is an option in ASP.NET CORE to build a single page application, we are going to use that feature. Here is a SPA Startup class:

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace WebApiAndAngular
{
    internal class SpaStartup
    {
        internal static void Configure(IApplicationBuilder app)
        {
            app.UseStaticFiles();
            app.UseSpaStaticFiles();
            app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "ClientApp";
                //if (env.IsDevelopment())
                //{
                //    spa.UseAngularCliServer(npmScript: "start");
                //}
            });

            // here you can see we make sure it doesn't start with /api, 
            // if it does, it'll 404 within .NET if it can't be found
            app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder =>
            {
                builder.UseMvc(routes =>
                {
                    routes.MapSpaFallbackRoute(
                        name: "spa-fallback",
                        defaults: new { controller = "Home", action = "Index" });
                });
            });
        }

        internal static void ConfigureServices(IServiceCollection services)
        {
            //added me
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "wwwroot";
            });
        }
    }
}

We are going to use this new startup class inside our main Startup class like below. Check /*Spa Startup*/ section:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Swashbuckle.AspNetCore.Swagger;

namespace WebApiAndAngular
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. 
        // Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            ApiDocStartup.ConfigureServices(services);
            /*Spa Startup*/
            SpaStartup.ConfigureServices(services);
        }

        // This method gets called by the runtime. 
        // Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. 
                // You may want to change this for production scenarios, 
                // see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseMvc();
            ApiDocStartup.Configure(app);
            /*Spa Startup*/
            SpaStartup.Configure(app);
        }
    }
}

Build/Publish Process

Debug Process

First, we need to do ng build/ng serve our Angular project using Visual Code or terminal.

Then, we will run our Web API project in debug mode using Visual Studio or command.

Publish Process

First, we need to publish bg build/ng build --prod our Angular project using Visual Code or terminal.

Then, we will publish our Web API project using Visual Studio or command.

Publish Script Using Cake

This is also possible with a cake build script, I will share it soon.

Result

In debug/release mode, we will see both API and UI views working fine. Now I am running project in debug mode using Visual Studio, the port number may not be the same for you.

API

API Doc Page(swagger): https://localhost:44395/api/index.html

Value API: https://localhost:44395/api/values

Image 3

Angular UI

Page: https://localhost:44395/deshboard

Image 4

Limitations

Try not to use any route like /api/anything in the Angular app, because /api/ suffix is going to navigate things to API classes.

History

  • 13th July, 2020: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here