After using both Angular and Visual Studio together for quite a while I figured I’d start writing a post about getting everything going. Why, aren’t there are many tutorials out there that deal with this already? Yes, but (me personally) I’ve always had to pull together various aspects from many of them and/or end up adding or changing parts to suit what I was trying to do. I’m hoping that most developers have hit the same issues as I have so this is to help them…

The other issue I have, at least from my point of view, is that quite a lot of development and tutorials out there regarding Angular are done using an editor such as Visual Studio Code, which is a fantastic editor and great for pure Angular development, but it’s not a full on IDE like Visual Studio itself. So whilst developing a pure Angular app using Visual Studio Code is a most excellent experience, it’s unlikely to be an all encompassing experience if your particular project say also involves something like a .NET Core API for example and likely some kind of database too. Lastly creating a .NET Core API (IMHO) is a much better experience using full fat Visual Studio.

This leads me onto my own personal problem, I’m lazy… I would much rather just be able to use one or the other, rather than having to switch between them. In fact, to be honest, I’d love to just stay in Visual Studio for everything and not have to come out and write my T-SQL in SSMS (SQL Server Management Studio) either. Yes, yes, yes, I know you can do that in Visual Studio but I’ve been using SSMS for years and Visual Studio has never matched it (yet).

I know what you’re thinking…

If you’re switching between Visual Studio and SSMS, why not Visual Studio Code?

Good point, but my personal development routine (at least) involves working on front end (Angular) and back end (.NET Core) more or less at the same time. The database side of things is usually something that I only flit into occasionally, quite often it already exists or I’ve mostly developed it before hand.

That’s my excuse and I’m sticking to it…

So let’s get moving, first you’ll need to install Visual Studio 2017 community edition (or higher) if you’ve not already. If you’ve not got Visual Studio 2017 installed you can download it from here. When installing via the Visual Studio installer, you’ll need to add the parts we’ll need for .NET Core development and Node.js which are listed below (note the blue ticked selections):-

There’s also a really useful Visual Studio extension that comes in handy when developing Angular apps, the ‘open command line‘ extension. You can find it here if you want to add it to Visual Studio. This is another great extension by Mads Kristensen, who has a large number of other Visual Studio extensions to his name. Be sure to check them out when you’ve got a chance. It basically allows you to open a command prompt by right clicking anywhere in your solution explorer.

Installing Angular 7 with Angular Material

Right, next part is to get Angular 7 installed. There’s a complete guide to this on the official Angular website here so I won’t bother repeating it here – just come back here when you’ve got it installed.

However, before we install Angular Material we need to create our Visual Studio project first. Open Visual Studio and create a new project, when the ‘New Project‘ dialog pops up, select the ‘ASP.NET Core Web Application‘ (see image below). In this example we’re going to be using C#:-

You’ll then be presented with another dialog asking you which project template to use (see image below). For the purposes of our tutorial we’re going to choose the ‘API‘ template – ignore the ‘Angular’ template as this is currently only at version 6 of Angular at the time of writing.

The latest stable version of the .NET Core framework is version 2.2, which you’ll notice is selected in one of the drop downs at the top of the dialog. You should also see a button at the bottom right of the dialog which can be used to ‘Change Authentication’, but for our purposes we are not going to use any authentication. At least not for this first tutorial…

OK, you should eventually end up with a .NET Core 2.2 API project with files and folders listed in your ‘Solution Explorer’ window in Visual Studio. Something a bit like this:-

Adding Angular

Now, we’re going to add an Angular app to the project. To do this, we need to open a command prompt and navigate to the location of our project folder. If you installed the ‘open command prompt‘ extension mentioned earlier then just right click on the project name and go to the ‘Open Command Line’ option and select ‘Default (cmd)’ from the menu. Otherwise just open a command prompt like normal and change directory to your project folder.

Assuming that your command prompt is now open at the location of your project, all we need to do is use the Angular CLI (which if you followed the install instructions on the Angular site, should be installed) to create an app for us, in this case we’ll call the app ‘Angular7‘, so type the following into the command prompt and press enter:-

ng new Angular7

You should then be asked some questions, we’ll need routing so choose ‘Y’ for routing. Almost any app will end up needing that. We’re also going to use SASS for styles, so choose ‘SASS (.SCSS)‘ when it asks you to choose styles. If you’ve never heard of, or never used SASS before don’t worry, we’ll get to that later…

Now we’ve got an Angular app we can add Angular Material to it. If you’ve never heard of this before it’s a collection of components that follow Google’s Material Design specification and they’re built specifically for use with Angular. This is what we’ll use to build our UI (user interface) here in the particular app. In previous app’s I’ve built I used Bootstrap, but once I began experimenting and using Angular Material I just fell in love with the whole idea, look and feel of it. It’s personal preference of course and since this is my blog, we’ll use it here 🙂

To add Angular Material to an Angular app is very easy now. In the command prompt type the following and press enter (this will change the directory to the Angular7 folder that was just created):-

cd Angular7

Now we should be inside our Angular app folder with the command prompt. Let’s type the following into the command prompt and press enter:-

ng add @angular/material

Hopefully you should then see it doing stuff and eventually it will ask you to choose a prebuilt them from a list, for our tutorial we’ll just choose the first in the list, so just press enter. You’ll then be asked if you want to add ‘HammerJS’ for gesture recognition, we don’t really need this for our tutorial but so you can choose Y or N. You’ll then be asked if you want browser animations, we’ll choose Y for this one. Now it goes off an installs and configures everything you need to get going. Previously you had to do most of the configuration manually but now that’s it.

Wiring Angular up to the Visual Studio project

Now we’ve got our basic Angular app, we need to tie wire it up to work with Visual Studio. Most of this configuration comes from the standard Angular template in Visual Studio but there’s a bit of extra configuration that’s usually needed.

To open the project configuration file, just right click on the project name in Visual Studio and choose ‘Edit **** .csproj’ where the **** is the name of your project, see below:-

You should end up with something a bit like this below, see here for more information on what you can do:-

Delete what’s in there for now and copy and paste the code below. I’ve put comments above each part to explain what is going on. Note that some parts are taken straight from the standard Visual Studio Angular template, others are changes or additions I’ve made:-

<Project Sdk="Microsoft.NET.Sdk.Web">
  
  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>

    <!--
    Currently there is a bug with 'InProcess' so for 
    now just use 'OutOfProcess' until its fixed
    
    See: https://github.com/aspnet/AspNetCore/issues/4206
    -->
    <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>

    <!-- 
    Set this to the folder name (relative to the project) 
    where your active Angular app is
    -->
    <SpaRoot>Angular7\</SpaRoot>

    <!-- 
    Use this to set the 'base href' in Angular's 'index.html' file, so for example
    if you're using a virtual directory then it would be set to '/myvirtualdirectory'
    or if its at the site root then just '/'
    -->
    <AngularBaseHref>/</AngularBaseHref>

    <!-- 
    This is needed to stop TypeScript compiling and IDE error highlighting, the
    TSCONFIG.JSON settings alone *DO NOT* (or did not) work! This maybe fixed in a 
    future version of Visual Studio as it seems to come and go with updates, so
    this code below could potentially be removed in the future
    
    N.B. the 'TypeScriptBaseUrl' value should be the same as the 'SpaRoot' that
    was set previously above!!!
    -->
    <TypeScriptCompileBlocked>True</TypeScriptCompileBlocked>
    <TypeScriptToolsVersion>3.1</TypeScriptToolsVersion>
    <TypeScriptBaseUrl>Angular7\</TypeScriptBaseUrl>
    <TypeScriptExperimentalDecorators>True</TypeScriptExperimentalDecorators>
    <TypeScriptEmitDecoratorMetadata>True</TypeScriptEmitDecoratorMetadata>

    <!--
    Default is true for IsPackable, so we're going to have to turn it off
    -->
    <IsPackable>false</IsPackable>
    
    <!--
    Exclude various folders
    -->
    <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
  </PropertyGroup>

  <!-- 
  In addition, because there is no TSCONFIG.JSON in the 'root' of the 
  Visual Studio project, Visual Studio ignores above settings sometimes, 
  so here we must put some stuff to stop it compiling .TS into .JS files! 
  Again, this seems to come and go with updates to Visual Studio, I leave 
  it here just in case. 
  
  N.B. If some of the fundamental configuration of Angular changes 
  though, you may need to update some of these settings!
  -->
  <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
    <TypeScriptTarget>ES5</TypeScriptTarget>
    <TypeScriptJSXEmit>None</TypeScriptJSXEmit>
    <TypeScriptModuleKind />
    <TypeScriptCompileOnSaveEnabled>False</TypeScriptCompileOnSaveEnabled>
    <TypeScriptNoImplicitAny>False</TypeScriptNoImplicitAny>
    <TypeScriptRemoveComments>False</TypeScriptRemoveComments>
    <TypeScriptOutFile />
    <TypeScriptOutDir />
    <TypeScriptGeneratesDeclarations>False</TypeScriptGeneratesDeclarations>
    <TypeScriptNoEmitOnError>True</TypeScriptNoEmitOnError>
    <TypeScriptSourceMap>True</TypeScriptSourceMap>
    <TypeScriptMapRoot />
    <TypeScriptSourceRoot />
  </PropertyGroup>

  <ItemGroup>
    <!-- 
    Don't publish the SPA source files, but do show 
    them in the project files list 
    -->
    <Content Remove="$(SpaRoot)**" />    
    <None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
  </ItemGroup>  

  <ItemGroup>
    <!--
    This includes the basic .NET Core NuGet packages we'll need
    -->
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
    <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.2.0" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.1" />
  </ItemGroup>

  <ItemGroup>
    <!--
    If you're using web.config files on IIS then this is a 
    tool which can transform web.config files depending on
    the project configuration (e.g. Debug, Release etc...)
    
    See these links for more information:-
    https://github.com/nil4/dotnet-transform-xdt#msbuild
    https://msdn.microsoft.com/en-us/library/dd465326.aspx
    
    .NET Core XML Document Transformation usage: 
      dotnet transform-xdt [options]    
    -->
    <DotNetCliToolReference Include="Microsoft.DotNet.Xdt.Tools" Version="2.0.0" />
  </ItemGroup>
  
  <!--
  This code below is taken straight from the standard template for Angular projects
  in Visual Studio. I've modified it a little to pass our 'AngularBaseHref' value
  to the npm build process
  -->
  <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
    <!-- 
    Ensure Node.js is installed, as its required to run and build the client side
    stuff!
    -->
    <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="PublishRun" AfterTargets="ComputeFilesToPublish">
    <!-- 
    As part of publishing, ensure the JS resources are freshly built in production mode. Note
    the $(AngularBaseHref) which is passing our build variable value to the NPM script!
    -->
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod --base-href=$(AngularBaseHref)" />

    <!-- 
    Include the newly-built files in the publish output 
    -->
    <ItemGroup>
      <DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
      <DistFiles Include="$(SpaRoot)node_modules\**" Condition="'$(BuildServerSideRenderer)' == 'true'" />
      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>%(DistFiles.Identity)</RelativePath>
        <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
      </ResolvedFileToPublish>
    </ItemGroup>
  </Target>

  <!--
  Use the web.config transformation tool as detailed previously above...
  
  See these links for more information:-
  https://github.com/nil4/dotnet-transform-xdt#msbuild
  https://msdn.microsoft.com/en-us/library/dd465326.aspx
    
  .NET Core XML Document Transformation usage: 
    dotnet transform-xdt [options]
  -->
  <Target Name="ApplyXdtConfigTransform" BeforeTargets="_TransformWebConfig">
    <PropertyGroup>
      <_SourceWebConfig>$(MSBuildThisFileDirectory)Web.config</_SourceWebConfig>
      <_XdtTransform>$(MSBuildThisFileDirectory)Web.$(Configuration).config</_XdtTransform>
      <_TargetWebConfig>$(PublishDir)Web.config</_TargetWebConfig>
    </PropertyGroup>
    <Exec Command="dotnet transform-xdt --xml "$(_SourceWebConfig)" --transform "$(_XdtTransform)" --output "$(_TargetWebConfig)"" Condition="Exists('$(_XdtTransform)')" />
  </Target>

</Project>

The main ones to note are the ‘SpaRoot‘ – which is the relative path to from the Visual Studio project folder to the Angular app folder. Then there’s ‘AngularBaseHref‘ – which is something I’ve added as we had a server with several apps each under a virtual directory like:-

OK, that’s enough of that. Let’s move onto the code in our .NET Core API… Open up the ‘Startup.cs’ file in the root of the project. We’ll need to add some code here to fully wire up our Angular project to the rest of the project:-

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace VisualStudio2017WithAngular7
{
    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);

            // We need to specify where the files that Angular has built 
            // are located when the production build is being done
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "Angular7/dist";
            });
        }

        // 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();

            // We'll need static files and the SPA static files!
            app.UseStaticFiles();
            app.UseSpaStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller}/{action=Index}/{id?}");
            });

            app.UseSpa(spa =>
            {
                // During development this is the folder where the Angular app is located
                spa.Options.SourcePath = "Angular7";

                if (env.IsDevelopment())
                {
                    // You can use either 'start', or if you've configured HMR for
                    // your Angular app then use 'hmr'. Make sure there's a 'hmr' entry
                    // in your 'package.json' file though!
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });
        }
    }
}

Note the last part ‘spa.UseAngularCliServer(npmScript: “hmr”);‘ – the parameter value of ‘hmr’ is usually replaced with ‘start’ in most apps, but in our tutorial we’re going to use HMR (Hot Module Replacement). This is a cool feature of webpack that lets us change code in our modules and have them swapped out live. In other words, make a change to your code in Visual Studio and the browser gets updated automatically with the new code!

Luckily for us the complex configuration of webpack is handled behind the scenes in Angular 7 apps so we don’t need to worry about how all that works. Be glad, its not for the faint hearted! Note that this feature is only used for development, it does not get included or configured when the production code is finally built!

One final thing to change then we should be able to run our app and see something. Under the properties in solution explorer, there’s a file called ‘launchSettings.json’, we need to remove a line from this file otherwise when we run the app we’ll just get some results spat back to us from the .NET Core API example ‘Controller’:-

Open the file and remove the lines that say:-

“launchUrl”: “api/values”

There are two entries we need to remove, one is highlighted below then further down there’s one more. Just delete the whole line and save the file:-

OK, I think we’re ready to go, if you start debugging with Visual Studio the Angular app should get built and eventually (give it a while) you should see the standard Angular template app page show up in whichever browser Visual Studio has been configured to use like this:-

If you’ve got here then you’ve now successfully got a Visual Studio 2017 project running with Angular 7 and .NET Core 2.2 together. Or sort of… Neither Angular or .NET Core is doing much here and we’re not using our .NET Core API yet either. The browser is only showing results from our Angular code really…

OK, that’s our basic setup done (more or less), we’ll move on to using Angular Material and some API functionality in the next part…

Leave a Reply

%d