Dynamically Loading Assemblies for Dependency Injection in .Net Core

We want to get all our assemblies registered for Dependency Injection in a .Net Core 3 application by scanning the bin folder and registering all the classes which implement a specific interface. Bit of a mouthful so a simple (and classic) example is

public class Foo: IFoo
{
}

public interface IFoo : ILifecycle
{
}
public class Bar: IBar
{
}

public interface IBar: ILifecycle
{
}
public class Bar: IBar
{
}

public interface IBar: ILifecycle
{
}

We could register each object by its own interface i.e.

services.AddTransient<IFoo, Foo>();
services.AddTransient<IBar, Bar>();

That’s fine for 2 but for hundreds it will be a pain. We want to register the assemblies based on an interface that they all inherit – in this case ILifecycle. Also, we want to register all the assemblies in a given folder, typically the bin folder. This is what didn’t work in .Net Core for me and hence the post – no answer on the internet (that I could find) so I’m filling the internet gap.

Implementation

We will use Scrutor as our DI framework. It’s an extension of the native .Net DI framework with extensions for scanning and registering assemblies en mass.

Incorrect Implementation – LoadFromFile

Using an MVC application and within Startup

public void ConfigureServices(IServiceCollection services)
{
//..lots of other code

foreach (string assemblyPath in Directory.GetFiles(System.AppDomain.CurrentDomain.BaseDirectory, "*.dll", SearchOption.AllDirectories))
{
  var assembly = Assembly.LoadFile(assemblyPath);
  assemblies.Add(assembly);
}

//.. register
services.Scan(scan => scan
   .FromAssemblies(assemblies)
   .AddClasses(classes => classes.AssignableTo<ILifecycle>(), publicOnly: false)
   .AsImplementedInterfaces()
   .WithTransientLifetime());

//.. test
var provider = services.BuildServiceProvider();
var foo = provider.GetService<IFoo>(); //.. returns null
var bar = provider.GetService<IBar>(); //.. return null
}

Frustratingly this doesn’t work and it’s not obvious why. The test returns null Foo and Bar objects even though we have registered them in the correct way i.e. by scanning for ILifecycle and registering the object as their matching interface. I we debug and look at the loaded assemblies everything looks fine. The assemblies have loaded and I can use reflection to poke into them further and satisfy myself that they are indeed the correct assemblies. Except they aren’t

Correct Implementation – AssemblyLoadContext

public void ConfigureServices(IServiceCollection services)
{
//..lots of other code

foreach (string assemblyPath in Directory.GetFiles(System.AppDomain.CurrentDomain.BaseDirectory, "*.dll", SearchOption.AllDirectories))
{
var assembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
assemblies.Add(assembly);
}

//.. register
services.Scan(scan => scan
.FromAssemblies(assemblies)
.AddClasses(classes => classes.AssignableTo<ILifecycle>(), publicOnly: false)
.AsImplementedInterfaces()
.WithTransientLifetime());

//.. test
var provider = services.BuildServiceProvider();
var foo = provider.GetService<IFoo>(); //.. returns null
var bar = provider.GetService<IBar>(); //.. return null
}

Very similar except we have swapped

Assembly.LoadFile(assemblyPath);

for

System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);

Now it works and the DI framework can provide us with the correct objects based on their matching interface. All is good.

Explanation

I don’t really have one so if anyone can post a comment explain this then that would be very interesting. I do know that .Net Core handles its dependencies differently to .net framework i.e. it’s all NuGet packages so it makes sense that we need another way to correctly load the assemblies with their dependencies. What’s puzzling is that Assembly.LoadFromFile is still there and appears to work – except it doesn’t for DI.

Other DI Frameworks

I wasn’t exhaustive but I tried the with StructureMap and AutoFac and got the same issue. So, it’s not limited to Scrutor. You’d face these problems with other frameworks as well.

Useful Links

Stack Overflow question on How to load assemblies located in a folder in .net core console app. It’s where I found the proper way to load assemblies

Git Hub for Scutor. Works well (when you get over the assembly loading issue).

Converting .Net Standard Libraries to .Net Core

I was looking for a quick answer to this on the internet and couldn’t find it. So here it is

Open your .Net Standard csproj file in notepad or similar text editor. You’ll see this structure

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Framework\AnotherLibrary.csproj" />
</ItemGroup>
</Project>

Change the target framework to the desired version of core

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Framework\AnotherLibrary.csproj" />
</ItemGroup>
</Project>

Save it
Reload the project in visual studio or other IDE
Done

(I know there will be all kinds of other complexities to this but I’ve just got a bunch of standard libraries that need to reference a core project and can’t. So, they all need a rapid upgrade to .Net Core – like so).

70-480 Programming in HTML5 with JavaScript and CSS3 – Study Notes

I recently took MS exam 70-480 (and passed and was surprisingly delighted). So before the good feelings dissolve away I thought I would publish a few notes and useful links. I’m not going to be comprehensive but I’m just going to highlight areas that came up for me that I needed deeper reading on.

Generally

The exam does feel old hat especially the JavaScript section. It is frustrating to have to remember Microsoft specific syntax (AddEventHandler!!!). But I’ve seen worse and there is stuff that is still interesting and relevant in there. The good thing is that there are techniques and syntax that crops up over and over and can really help you winnow the answers down on the exam.

Basic stuff to know

The book

I’m old school and still prefer to start with the written word on bits of paper. The standard book is this …

People are really negative about exam ref books generally and this one gets the obligatory poor reviews (and some goods ones in fairness). But do you know what – it’s fine. It’s not that readable, it’s got a lot of gaps and some of it is out of date now (and maybe was never correct in the first place). But it highlights all the syllabus areas for you then it is up to you to go on and read more. I think people get upset because the book alone isn’t enough to pass the exam. So long as you appreciate that then it’s fine.

Syllabus

https://www.microsoft.com/en-us/learning/exam-70-480.aspx

The key thing is to go through it all with a fine tooth comb (or hair care implement of choice). So biting our lips and going through each section ….

Section 1: Implement and Manipulate Document Structures and Objects

JavaScript

Important bits here is understanding the JavaScript this keyword (notoriously confusion) and a tight tight grasp of JavaScript scope. Other things are

HTML5

  • Semantic elements. If I’m honest, some of the questions have a ‘guess what I’m thinking’ quality to them. Get to grips with the Microsoft party line on when these should be used. Just suck it up.
  • Geolocation API
  • App Cache
  • Canvas appears a lot but there is a lot of stuff out there for instance here and here among lots of other places.
  • SVG. It’s good to know when to use SVG and when to use the canvas elements. For instance SVG scales inherently.

Section 2: Implement Program Flow

JavaScript Arrays

Good grasp of javascript control structures is vital so
array iteration (more detail here) also associative arrays and understand why they iterate differently.

Web sockets

Very high level only. How to call and pass events backwards I forwards. I read this and as interesting as it was it is way too much. Spend less time than I did on this.

Ajax

Conversely Ajax comes up a lot in detail

Web Workers

Web workers also comes up. Specific points I found were

Section 3: Access and Secure data

Reg Ex

Regular Expressions crops up here and and how to call from JavaScript Which methods belong to the regex pattern and which methods belong to the string class are useful to know here.

JQuery Forms

JQuery forms API. Pay attention to differences between serialise and serialiseArray methods and be secure in your knowledge of how to submit forms through JQuery.

JavaScript Encoding

JavaScript encoding and decoding of Uris and query string . Comes up bizzarely often so one to really know. Know which method gives which output and which one to use to ensure that the query string is encoded.

Html5 input types

Html 5 input types. Really useful to memorise them all and know all the possible attributes i.e.

  • step
  • min
  • max
  • title
  • pattern etc…

particular know the attributes that can be used to limit the data input format e.g. type=”number”.

Section 4: Use CSS3 in Applications

I wanted to do this exam primarily to improve my CSS which is my weakest web dev side so I spent a bit of time of this. I’m sure you will need less.

Basics

The cascade

Layout

Layout comes up a lot so

Text

Fancy stuff

Generally with the animation /transitions side of things I found it most useful to look at worked examples of some standard (though clever to me) forms of animations. Card flips and loading spinners are typical stuff.

Never saw

I never saw anything on the drag and drop api.  It had a decent sized section in the Microsoft exam ref book but I didn’t see this on the exam or the revision questions. Don’t blame me if you get 7 questions about it though.

Good luck

And of course best of luck for the exam. As painful as it can be, it does feel good to pass a Microsoft exam. Take it from someone who has passed onto the other side.

Extending TypeScript to serialise Map objects to JSON

The collection objects offered by ES6 such as Map and Set are indeed a marvel. One notable downside to them though is that they don’t serialise to JSON. For example

JSON.stringify(MyMapObject);

Results in

{}

Always – irrespective of what is in the map collection. Not great and a pain when we want to stash the map object in a cookie or local storage to be used later. It just doesn’t do it out of the box. Here I’m going to extend TypeScript to do this so I will never need to think about it again.

Serialising the Map object.

There are a number of different ways to get the Map object to serialise and deserialise in and out of JSON. This one relies on the contents of the Map object being serialisable. If they are then we can do the following

Serialise Map into JSON
function toJson(map) {
return JSON.stringify(Array.from(map.entries()));
}
Deserialise JSON into Map
function fromJson(jsonStr) {
return new Map(JSON.parse(jsonStr));
}

This works in JavaScript (ES6) and TypeScript – which after all is a superset of JavaScript.

Serialise the Map Object

It feels a bit clunky to have these methods hanging around in some utility library. What I want to do is extend the TypeScript Map class to have these. To do this go to a TypeScript definition file (*.d.ts) and enter the following

interface Map<K, V> {
toJson(): string;
}

This will extend our map object to have a toJson method. In a suitable library file place the implementation and associate with the prototype object of the Map object

Map.prototype.toJson = function toJson() {
return JSON.stringify(Array.from(this.entries()));
}

It’s not hugely intuitive why we need to extend the prototype object at this point. From the mozilla documention

All Map instances inherit from Map.prototype.

So if we want our new method on an instance of the Map object we need to extend the prototype object –  because Map instances all inherit from this.

This is then called thus

let jsonString = myMap.toJson();

Which can then be stashed away in local storage or the like.

Deserialise a JSON string into a Map object

We are going to do similar to implement the deserialisation part. It’s not quite the same though. If we are serialising a Map object it makes sense to have the toJson method associated with an instance of a Map object. If we are deserialising into a new Map object we want the method associated with the class- like a static method in C#. The following illustrates the difference

let myMap: Map<string, string> = new Map<string, string>();
myMap.set("key1", "value1")
myMap.set("key2", "value2")
myMap.set("key2", "value2")

//.. serialise method associated with the instance of the class
let jsonString = myMap.toJson();

//.. deserialise method associated with the class
let restoredMap: Map<string, string> = Map.fromJson(jsonString);

Again go to a TypeScript definition file (*.d.ts) and enter the following

interface MapConstructor {
fromJson(jsonStr: string);
}

Note – this time I am extending the MapConstructor object rather than the Map<K,V> object. In TypeScript the MapConstructor object returns a reference to the Map function that created the object. So by extending the MapConstructor Typescript object I am associating the method with the object that created the instance of the map object. I am associating the new method with the class and not the instance.

Now associate our implementation directly with the Map object which itself implements MapConstructor

Map.jsonToMap = function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}

Which we call thus

let restoredMap: Map<string, string> = Map.jsonToMap(jsonString);

That’s it – the Map object now has toJson and fromJson methods which handle our JSON conversion. The Set object suffers from the same limitations and can be extended in the same way.

Useful Links

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
Map and Set objects are part of the ES6 standard. TypeScript offers a strongly typed version of these collections

https://codepunk.io/extending-strings-and-other-data-types-in-typescript/
More detail about extending built in types in TypeScript

https://stackoverflow.com/
The initial code to serialise and deserialise the Map object came from a stack overflow question i.e.

function toJson(map) {
return JSON.stringify(Array.from(map.entries()));
}

function fromJson(jsonStr) {
return new Map(JSON.parse(jsonStr));
}

but I’ve forgotten which one – if I find it I will pop the reference here in the interest of full disclosure and not ripping off someone else’s work and claiming it for my own.

Not as irreplaceable as I thought

Like all software developers, I like to think of myself as being irreplaceable. Clearly no-one on the entire planet combines my depth of technical knowledge, my amazing familiarly with the business domain and my legendary humility. I am truly a unique gift to any and all employers.

So I was particularly disappointed this week when I was replaced my this play-mobile figure at the family dinner table . I was out that evening so the daughter placed this unkempt looking plastic figure in my chair . She felt it was an adequate or even superior replacement. It’s uncertain whether my wife noticed the difference. Certainly the level of conversation was improved that evening.

So not as irreplaceable as I thought. I once replaced a colleague with a blow up sheep and sent him the photo. I thought it was very funny at the time – I realise now that it wasn’t as funny as I thought. I really hope my employer doesn’t realise how easily I can be replaced by a cheap child’s toy.

Selecting from a column with possible NULLs in T-SQL

I write blog posts for different reasons. Sometimes it’s because things aren’t well documented elsewhere, sometimes it’s new and interesting and sometimes it’s purely for my own amusement. Occasionally I write things as I kind of penance – things I should know about but bizarrely forgot or misunderstood. This is one of those. It’s how to select from a column with possible NULLs and not omit expected rows from the results set. This has been documented at length elsewhere but that’s not the point of penance.

Test Cases – equals operator

Working through some examples when comparing NULLs with the equals operator.

NULL is equal to ‘test’

SELECT CASE WHEN NULL = 'test' THEN 'true' ELSE 'false' END

False: as expected

NULL is not equal ‘test’

SELECT CASE WHEN NULL <> 'test' THEN 'true' ELSE 'false' END

False:  less expected

NULL is not equal to NULL

SELECT CASE WHEN NULL <> NULL THEN 'true' ELSE 'false' END

False: more expected

NULL is equal to NULL

SELECT CASE WHEN NULL = NULL THEN 'true' ELSE 'false' END

False: odd again

NULL isn’t equal to anything including itself when using the equals operator. I know this really and we see the same kind of thing in JavaScript.

Test cases – IS NULL

Of course it well known that equals doesn’t do the job with NULLS. The IS NULL operator is correct

Null is null

SELECT CASE WHEN NULL IS NULL THEN 'true' ELSE 'false' END

True.

Null is not null

SELECT CASE WHEN NULL IS NOT NULL THEN 'true' ELSE 'false' END

False.

All as expected.

Test case -selecting from a column with possible NULLs

So this is what tripped me up – when you have a column that is nullable and trying to filter as a string.

DECLARE @TestTable TABLE (Id INT NOT NULL, Comment VARCHAR(100))
INSERT INTO @TestTable (Id, Comment) VALUES (1, 'Test')
INSERT INTO @TestTable (Id, Comment) VALUES (2, 'Other Value')
INSERT INTO @TestTable (Id, Comment) VALUES (3,  NULL)

SELECT * FROM @TestTable WHERE Comment <> 'Test'

I naively thought that there are 2 rows that aren’t ‘Test’ so we will get those. But since NULL is not equal to ‘Test’ and not not equal to ‘Test’ then actually we get one less row than we expected

The correct select is

DECLARE @TestTable TABLE (Id INT NOT NULL, Comment VARCHAR(100))
INSERT INTO @TestTable (Id, Comment) VALUES (1, 'Test')
INSERT INTO @TestTable (Id, Comment) VALUES (2, 'Other Value')
INSERT INTO @TestTable (Id, Comment) VALUES (3,  NULL)

SELECT * FROM @TestTable WHERE COALESCE(Comment, '') <> 'Test'

Which converts the NULL to an empty string so then works

SELECT * FROM @TestTable WHERE ISNULL(Comment, '') <> 'Test'

Also works and is the same. Penitential blog post over.

Useful Links

https://stackoverflow.com/questions/18828641/sql-difference-between-coalesce-and-isnull
Comparison of ISNULL and COALESCE

http://adripofjavascript.com/blog/drips/equals-equals-null-in-javascript.html
It’s not just T-SQL. Special handling around NULLs in JavaScript

SQL Server restore fails if backups taken in rapid succession

How I (unfairly) think of SQL Server

I don’t spend an awful lot of time thinking about SQL Server. To me it’s a workhorse which I think is a compliment. * It’s steady, reliable and gets the job done. It’s not glamorous though and people don’t talk about it at dinner parties.

I did have cause to give the old SQL Server workhorse a bit more thought recently. I’m having to do a bit of database work and I’m taking lots of backups in rapid succession and restoring them. For some reason the backups didn’t restore the most recent version of the database. The restored DB was weirdly out of date. I got round this by going to options on the backup dialog and selecting ‘Overwrite existing backup sets’

Once I’d blatted out the existing sets then it worked fine. I don’t know why it wouldn’t work if I appended to backup sets and clearly this is a development environment workaround. I’m not advocating people merrily wiping out backup sets on production sets. A better workaround might have been to start using snapshots but once the workhorse was lashed back to the plough then I was happy. That said, I’d be very interested to know why it was doing that if anyone knows.

* On reflection, I wouldn’t like it if called me a workhorse so perhaps it’s not as much of a compliment as I imagine.

LINQ FirstOrDefault implementation in TypeScript

Proust looking of of the window thinking about LINQ operators

Confession: when working in JavaScript languages I kind of miss some C# things such as LINQ. A substantial part of my C# coding seemed to be chaining LINQ operators together. So rather than staring wistfully out of the window  in remembrance of things past – I thought I would just try to write one of my own. I’ve picked FirstOrDefault for this honour.

FirstOrDefault

For the uninitiated FirstOrDefault is a LINQ operator in C# that takes a function which resolves to a boolean – a predicate. It has the following characteristics

  1. Returns the first object in a collection that matches the predicate
  2. If it can’t find one then it will return null
  3. It won’t throw an exception if it can’t make the match – in contrast to it’s harsher sibling SingleOrDefault that will

TypeScript

I’m writing this In TypeScript – simply because that’s what I’m using at the moment. It would actually be easier to do this in plain JavaScript – the prototype will be the same and they would be no steps to hook it into the TypeScript interface. But we will do it in TypeScript

Implementation

Step 1: Extending Array Type

In C#, the LINQ operators are an extension of IEnumerable<T>. In TypeScript we will extend the Array object which is a similar principle. In Typescript type definitions go in .d.ts files. I’m working in Angular and there is handily a definition file already present – typings.d.ts. In that file put the following

interface Array<T> {
   firstOrDefault(predicate: Function): T;
}

This adds a firstOrDefault defintion to the Array type. It takes a function just like the C# first or default method. As we are using TypeScript we can specify a type of function for the parameter so we will get compile errors if we try to supply anything else to this method. Of course there is no implementation yet ….

Step 2: Implementing the LINQ operator

Create a file e.g. Linq.ts and enter the following

export module Linq {

Array.prototype.firstOrDefault = function(predicate: Function){
  return this.reduce( (accumulator, currentValue) => {

      if(!accumulator && predicate(currentValue)) 
        accumulator = currentValue;
      
      return accumulator;
    }, null);
  }
}

This method is going to do the work – it’s the meat and potatoes. We are leveraging the reduce operator. Reduce flattens a collection into a single value – a simple example would be totalling all the numeric values in an array i.e.

let total = this.reduce( (accumulator, currentValue) => accumulator + currentValue);

For us flattening the array means returning the first value that matches the predicate. So we iterate through until predicate(currentValue) evaluates to true then we stash the value in the accumulator object and once there we never write over it.

An interesting quirk to this is what happens on the first loop – if we call it like this

return this.reduce( (accumulator, currentValue) => {

  if(!accumulator && predicate(currentValue)) 
    accumulator = currentValue;
  return accumulator;
});

i.e. reduce with a single argument. In the first iteration the accumulator has the value of the first object in the array; the currentValue has the second. The first item is already stashed in the accumulator and the predicate is never checked – the first item is always returned no matter what the filter is. This is exactly what we don’t want. We need to supply a second argument to reduce …..

return this.reduce( (accumulator, currentValue) => {

  if(!accumulator && predicate(currentValue)) 
    accumulator = currentValue;
  return accumulator;
}, null);

By supplying a second argument we specify what the initial value of the accumulator is. We want a initial value of null so our LINQ operator will attempt the match each time until it succeeds.

As a side note – I’m aware that there are any number of ways to achieve this but I’ve a theory that all of the LINQ operators can be done with JavaScript reduce, map or filter methods so this is my first step to prove that theory out. It can be done and it will be done (if I get the time).

Step 3. Consuming the LINQ operator

Import the linq prototype and use thus

import('../utilities/linq');

let results = arrayUnderTest.firstOrDefault(x => x.Id === 1);

This returns the first object in the array with an Id of 1. This compares quite nicely with the C# FirstOrDefault method which is

var results = collectionUnderTest.FirstOrDefault(x => x.Id == 1);

Which looks pretty similar to me and works in the same way. It doesn’t do a great job with type checking though and since we are using TypeScript we can do a bit better.

Implementation with Generics

We can use generics in TypeScript to get type checking in the predicate and get a typed returned value. An improvement I think.

Step 1: Extending Array Type

Go to the d.ts file again and use this

type predicate<T> = (arg: T) => boolean;

Which defines a function that takes type T and returns a boolean – our filtering predicate.

interface Array<T> {
  firstOrDefault<T>(predicate: predicate<T>): T;
}

And a generic array extension which uses the typed predicate instead of the more generic Function type.

Step 2: Implementing the LINQ operator

Change the implementation to this

export module Linq {

  Array.prototype.firstOrDefault = function<T>(predicate: predicate<T>){
    return this.reduce((accumulator: T, currentValue: T) => {

      if(!accumulator && predicate(currentValue)) 
        accumulator = currentValue;
      
     return accumulator;
    }, null);
  }
}

Which uses the generic types throughout.

Step 3. Consuming the LINQ operator

If we were using a collection of persons, the new generic powered firstOrDefault would be called like this

let result: Person = persons.FirstOrDefault<Person>(x => x.Id === 1);

We can now get decent intellisense when filling in the filter conditions and type checking so we don’t compare the wrong types. It’s slightly more verbose than the first example but safer to use. I prefer it, but use whichever floats your TypeScript boat – both work.

Useful Links

https://codepunk.io/extending-strings-and-other-data-types-in-typescript/
More detail about extending built in types in TypeScript

https://danmartensen.svbtle.com/javascripts-map-reduce-and-filter
Nice comparison of the map, filter and reduce methods in JavaScript and guidance about which to use when.

https://www.tutorialspoint.com/linq/linq_query_operators.htm
Overview of LINQ operators. There’s more than you think.

https://stackoverflow.com/questions/7192040/linq-to-entities-vs-linq-to-objects-are-they-the-same
When I’m talking about LINQ I’m really talking about LINQ to objects. There is LINQ to SQL, LINQ to entities, LINQ to XML etc.. This SO question points out the difference.

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq
There are two styles of operators in LINQ – lambda and query syntax. Query syntax is

IEnumerable<int> numQuery1 = from num in numbers 
                             where num % 2 == 0 
                             orderby num s
                             elect num;

And the equivalent lamdba is

numQuery1.Where(num => num % 2 == 0).OrderBy(num => num);

I’m emulating the lamdba syntax here. I never use the query syntax – I think it was easy route to LINQ for people more familiar with SQL. The lamdba is a more functional approach and nearer to what the code is actually doing. Anyway the query operator was only ever a sub set of the lamdba.

Copying static files into build directory with Angular

This is probably obvious for Angular aficionados and aficionadistas but I found how to copy static files into the output directory of an angular application non-obvious.

To do it go to angular-cli.json in your project root and add the static file to the assets collection thus

"apps": [
{
"assets": [
"assets",
"favicon.ico",
"mystaticfile.txt"
],

And it places it nicely into the output folder which is dist by default. I found this useful when using a web.config file to set up some URL rewriting rules in an IIS hosting scenario i.e..

"apps": [
{
"assets": [
"assets",
"favicon.ico",
"web.config"
],
.. rest of app settings
}];

Just though I would break it out of that post and flag up how to do it when I had a spare 10 mins between cleaning the bathroom and taking the daughter to swimming lessons (too much information – sorry).

Hosting Angular in IIS under an existing website

I recently had cause to put an Angular application a IIS sub application under an existing .Net website so effectively they share the same host url. It took me longer than it should have done – I made heavy weather of it. Some issues were just fiddly and took some working out. Some issues I had were the result of my own sub-optimal performance in this technical area (stupidity). It was Saturday afternoon so I’m allowed sub -optimal performance in my own time.

Tutorial

There is already a good tutorial here. So I’m not proposing to go through it step by step, Instead I’ll quickly outline the basic steps then point out where I went wrong. I suffer so you don’t have to.

Motivation

Just briefly – my motivation for doing this was to have Angular running under the same address as the API it was calling.

So

http://demo-api:4200/

Is called by an angular app under a virtual directory at

http://demo-api:4200/Angular

This is to avoid Cross Origin Scripting Issues in my own environment. I know there are other ways to do this – but they either

  1. Never worked
  2. Were too invasive to implement on the API side (for a spare time demo project)
  3. Did work then frustrating stopped working

So I bit the bullet and moved Angular under the API project where it is always going to work for me i.e. they use the same host url so are no longer cross origin.

Create the Sub Application

So very briefly – ceate a sub application under main application to get this configuration

Point virtual directory to Angular app and browse. Boom – It doesn’t work!

Error 1: Using a .Net App pool

First issue is this yellow screen of death

The exact error will vary but essentially the angular application complains that it is missing assemblies, handlers, modules etc… It wants to be a .Net application. It doesn’t need to be.

When setting up the new application the default will be a .Net integrated application pool

To stop it behaving like a .Net app – create a new app pool with .Net CLR version of ‘No Managed Code’

Assign this to the new angular application in IIS and the site is no longer a .Net wannbe. The YSOD is gone.

Error 2: Pointing to the wrong folder

No yellow screen of death, instead the application is entirely blank. This is where I was being particularly sub-optimal. So I pointed it to my angular application at

{MyAngularApplication}\src

This is never going to work. Angular builds into this directory by default

{MyAngularApplication}\dist

Point the sub application here. Why I thought this would magically work I’ve no idea. Although IIS had stopped behaving like a .Net site, I clearly carried on thinking it was one and pointed to the root folder as I would a .Net site. 15 minutes of my life working this out that I am never going to get back. Oh well.

Error 3: Correcting Angular script references

So run the app again and sadly it is still blank. This time if you look at chrome developer toolbar or similar you will see a lot of 404 errors

What’s going on here is that Angular is still behaving as if it is loading all scripts from the root website. To correct this

  1. Use base href element in the root index page i.e.
<head>
<meta charset="utf-8">
<title>Title</title>
<base href="/Angular">
</head>

1. Change the ng build command from

ng build

to

ng build --base-href /Angular --deploy-url /Angular/

This will point Angular to the right direction i.e. looking at the dist folder the script references have changed from

<script type="text/javascript" src="/main.bundle.js"></script>

to

<script type="text/javascript" src="/Angular/main.bundle.js"></script>

Which is correct for our sub application.

As a side note – I always forget these kind of command lines. To avoid the need for additional brain friction use the npm start command to run the ng build command with the extra parameters. So go to packages.json in the root directory of your angular app and change the npm start node under scripts to the build command i.e.

"scripts": {
"ng": "ng",
"start": "ng build --base-href /Angular --deploy-url /Angular/",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},

Now to build the app use

npm start

And the build command runs with the correct params.

Error 4: Refreshing page causes 404

If you are using routing you will find that refreshing a page when on a route (i.e. demo-app/Angular/page1) will give a 404 error, To resolve this one

1. Install Url rewrite

2. Include a web.config page into your src folder with these url rewrite rules

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<directoryBrowse enabled="true" />
<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="/Angular" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

3. Include the web.config file in project assets. Go to .angular-cli.json and add web.config to the asset node like so

"apps": [
{
"assets": [
"assets",
"favicon.ico",
"web.config"
],
"index": "index.html",
"main": "main.ts",

.. rest of app settings

}];

If you omit this step then the web.config won’t be copied over to the dist folder on build. If you add it to the dist folder manually then it will be deleted on build so you won’t be any further forward.

Once all these steps are done, refreshing on a route this will reissue the request up to the base url which will resolve correctly.

Finishing up

Now the angular app runs nicely under a sub application in IIS and my Cors problem is no longer an issue. There are a couple of disadvantages to running it this way

  1. Hot reloading of the application on rebuild doesn’t work
  2. Related to this – the application sometimes caches and a hard refresh of the browser (ctrl, F5) is sometimes needed to kick it back to life.
  3. When refreshing a page it will redirect back to the root so you lose whatever route you are on so
http://demo-app/angular/page1

Refreshed becomes

http://demo-app/angular

Which may or may not be what you want

These are probably resolvable but when I got my development environment to this point, I declared loudly to all with ears to hear – Job done!

Useful Links

https://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/creating-rewrite-rules-for-the-url-rewrite-module
Url Rewriting module in IIS – official microsoft page

https://blogs.msdn.microsoft.com/webdev/2006/06/30/part-1-of-3-creating-sub-projects-in-iis-with-web-application-projects/
Setting in sub applications in IIS – detailed tutorial

https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
Wiki page about CORS which was causing me all the problem in the first place