Background
In the network, there are a lot of alike solutions to host an angular app as a SPA (Single Page web Application) in a .net core API project. Here I provide a different way to easily integrate angular into API project and run it successfully.
Pre-conditions
Here I won’t tell how to create an angular project and a .net core API project, and I assume there is a .net core API project contains an angular project inside. In the root folder of the API project, there is a folder named ‘ClientApp’ which contains an angular project inside.
Detail Steps
- Create a folder named ‘wwwroot’ in the root folder of the API project
- Set ‘wwwroot’ folder as the output folder of the angular project in angular.json
"outputPath": "../wwwroot"
- Add configurations in the API project file (.csproj) to build angular project when publishing.
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<!-- Set this to true if you enable server-side prerendering -->
<BuildServerSideRenderer>false</BuildServerSideRenderer>
</PropertyGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr -- --prod" Condition=" '$(BuildServerSideRenderer)' == 'true' " />
</Target>
- Add configurations in the API project file (.csproj) that the ‘wwwroot’ folder can be always copied into the publish folder and source files of the angular project cannot be published, but do show them in the project files list when publishing.
<ItemGroup>
<Compile Remove="ClientApp\**" />
<Content Remove="$(SpaRoot)**" />
<EmbeddedResource Remove="ClientApp\**" />
<None Remove="$(SpaRoot)**" />
<None Remove="ClientApp\**" />
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
<Content Update="wwwroot\**" CopyToPublishDirectory="Always" />
</ItemGroup>
- Add configurations in the ‘Configure’ method of the Startup.cs file
app.UseDefaultFiles();
app.UseStaticFiles();
- To avoid 404 error when refreshing page, we can add the below code in the Startup.cs file.
app.UseMvc(routes=>{
……
routes.MapSpaFallbackRoute("spa-fallback", new { controller = "Home", action = "Index" });
});
Then we need to create a mvc controller named ‘Home’ and add the below code in the ‘Index’ method.
public IActionResult Index()
{
var doc = new HtmlDocument();
doc.Load(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "index.html"));
var baseNode = doc.DocumentNode.Descendants("base").FirstOrDefault();
if (baseNode != null) baseNode.SetAttributeValue("href", Url.Content("~/"));
using (var ms = new MemoryStream())
{
doc.Save(ms);
return File(ms.ToArray(), "text/html");
}
}
Follow the above steps, an angular app can be hosted in a .net core API project successfully.