IdentityServer 4 + asp.net core 2 = Take 2

For the last year, I have been trying (off and on) to get up and running with an identity solution.  Since the main server technology I use is asp.net core, Identity Server is a natural choice.  Since I don’t want to write my own Identity/Claims management/storage solution, asp.net core Identity is also a natural partner to Identity Server.  There is even a demo project from the Identity Server folks, to get up and running with Identity Server with asp.net core Identity.  To prep this round, I went back and worked through all the tutorials on the Identity Server site again, since it had been some time since I mounted a full attack to get this working.

The goal is to have one login/token provider (Identity Server) with its own persistence for all my projects as a single sign on.  The current project I am working on, uses an angular 4 SPA and a asp.net core api, as well as a backend asp.net core MVC application for data administration.  The asp.net core MVC, API and angular app are nearly complete – except for login – which is the  critical piece.

Last year, when I tried this, I developed everything offline as a group (Identity Server, api, mvc, angular).  But those are quite a few moving parts to deploy (and actually work when deployed).  This year, instead, I have decided to get Identity Server deployed and working well for login, and then bring the other apps online.  I can call my server to access identity server from my apps that I am developing on my local machine.   After getting Identity Server deployed, then deploy the MVC admin and API and finally the Angular app.

As I mentioned, Identity Server and Asp Net Core Identity appears to be a common pattern, and works on development machines with demo projects.  From the demo projects, I did learn (and relearn) a process to run this apps more easily as described on the Identity Server website:

  • In Visual Studio, set  Solution Properties => Startup Project to “Current Selection”.  Run the currently selected project with Ctrl-F5.
  • Set Project Properties => Debug: Profile to the Project Name (not IIS Express) with a specified Port.  In program.cs, main, set Console.Title=”project name here”.   Then on running the project, it will run in a Console window (with the title you specify) and all the app errors will appear in the console.
  • On the server, you set the app to run within IIS (with its own app pool set to “No Managed Code”).   To test on the server,  navigate to the website directory and open a powershell window (or command prompt) and type “dotnet my.dll” and this will run the console app on the server.   The command line can be used to also pass extra config parameters, such as “dotnet my.dll key=value”.  In asp.net core 2, these values are available with configuration[key].  The browser can also be made to show  errors, if in the Startup Configure method, place (remove this in production) :app.UseDeveloperExceptionPage(); and app.UseDatabaseErrorPage();
  • Much of the Entity Framework and DotNet machinery for migrating databases is less accessible on the server.  Include  dbContext.Database.Migrate(); in the Startup Configure Method.

But deployment has quite a few gotchas, that despite doing my share of app deployments, still catch me up.  And there are significant holes in MS development that make the process harder:

  • The IIS AppPool typically needs permissions on the database, yet adding this as a database user can be tricky (It won’t show up as  windows users and even typing its fully qualified name will result in an error).  Until this is fixed, the app startup cryptically fails.
  • Setting up SMTP servers is tricky, not because this is hard, but rather because documentation is sparse to none, and Microsoft has recommended use of commercial (paid) providers to do this, instead of using the built-in functionality.  SMTP is used for email confirmation of passwords.
  • Self signed certificates (used for generating tokens) are not intuitive.  The MakeCert app is difficult to find.  After creating a certificate and putting it into the store, getting it via thumbprint is tricky.  The thumbprint for a certificate can be found in the certificate snapin for MMC – in the properties dialog.  This thumbprint is supposed to be usable after removing the spaces, capitalizing the chars, eliminating any preceding space).   This matches the thumbprint from powershell: Get-ChildItem -path cert:\LocalMachine\My.   However, I was not able to match on that thumbprint.  Instead,  when I looped through the unfiltered collection in my asp.net core code:X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
    foreach (X509Certificate2 x509 in collection) {
    Console.WriteLine(“Thumbprint: {0}{1}”, x509.Thumbprint, Environment.NewLine);
    I received a completely different set of thumbprints than in the details and from powershell – and using this value, it worked.
  • Despite having an SSL certificate on my server, HTTPS includes only one prefix.  I spent more than an hour trying to reach https://www.mywebsite/identityserver  and kept getting a 404 error.  When I tried, https://mywebsite/identityserver,  it worked.
  • If you rename a asp.net core project in Visual Studio, you need to manually update the dll filename call inside of web.config

What I could really use, is a reasonable tutorial, for developing production ready applications with Identity.  Identity Server has excellent tutorials, documentation and samples.  However, everything I’ve seen so far is either for getting started or for deep dives into functionality.  I could count at numerous courses on Pluralsight, as well as other free video sources that get you only part way to a deployable identity provider.   Scott Allen, Shawn Wildermuth who have typically had start to finish app development that would get me close to production, have not tackled full production ready identity.  John Papa and Dan Wahlin, who often walk through completed apps (I prefer the built from scratch), have not tackled identity fully.  I was hopeful, when Mosh Hamedani, who did an excellent 3 part series on MVC, developed an asp.net core with Angular course on Udemy;  unfortunately, he deferred Identity to Auth0.   Scott Hanselman and Brock Allen put together a Microsoft Virtual Academy course on Identity Server – so close (what a lecture duo!) – but just an intro.

The closest I’ve seen to getting a production ready Identity Server instance is with Roland Guijit and Kevin Dockx  in their individual courses on Pluralsight.  What is it with the Scandanavians and security? Roland’s course (Understanding ASP.NET security) is more on security as a whole, with individual examples of how to secure production apps.   Kevin’s course (Securing ASP.NET Core with Oauth2 and OpenID) tackles building from scratch a near production ready identity server instance.  I would have preferred if he had customized out-of-the box functionality from asp.net core identity.

But the greatest absentee is Microsoft.  After developing a surprisingly readable and practical guide to asp.net core, production-ready identity advice is lacking.  Where is the template – a starter pack in Visual Studio that combines Identity Server with asp.net core identity with best practices.

Identity is both important and hard.  I do not need a customized, legacy-compliant solution.  I’m looking to the experts in the area to help us get closer to production-ready Identity Server solutions.

Advertisements
Posted in Uncategorized | Leave a comment

Crosswords for Coders

When coding, I typically have a purpose – usually a project surrounding my Fpnotebook site.  But projects with a purpose often drag on, hit frustrating road blocks and often lack a firm endpoint.  As much as I like writing code, side projects can become just one more task on the burner.

I do not do crosswords or Sudoko, but I can understand the passion for conquering a finite puzzle; short coding tasks and exercises are my Crossword.  This past year I completed a Data Science certification from Microsoft (more on this in a forth coming post), and that involved quite a string of exercises and puzzles over the 9 course curriculum.  Even this though, was coding for a purpose (certification) and I was glad to be done with it.  At times, I’ve done coding puzzles on Project Euler or Hacker Rank,  but the problems are often generic.

So I was glad to recently find Rosalind, coding puzzles specific to bioinformatics.  The problems start simply (e.g. calculating a count of DNA nucleotides) and quickly advance to more complex problems (e.g. calculating population growth using variants of the Fibonacci sequence to take into account clutch size).  I had no idea Fibonacci had more use than a cliche coding problem; one of its original 1100 AD uses was to calculate Rabbit colony population growth.

You are given a description for each coding puzzle and sample data with associated sample solutions.  You can use this to create a coding solution.  When you are ready for the test data, click a button and a text file is downloaded;  five minutes is all you have to submit the solution from that point.  I exceeded this a few times for some of the problems, since some non-optimized solutions take far more than 5 minutes to complete. For example, I had to memoize my Fibonacci sequence generator to get a result in time.

One problem I found challenging (factoring in population growth along with a death rate after a given life span), required subtracting a Fibonacci sequence (offset by a given life span) from the population count.

I use Python in Anaconda Jupyter Notebooks to code the problems.  This makes set-up completely painless for more simple problem.  However, for more complex problems, I want intellisense, and use Visual Code and Visual Studio.

If you are a Bio-geek who likes to code, Rosalind is one more way to procrastinate on your other tasks with a purpose.

 

Posted in Uncategorized

Asp.Net Core + Angular 2/4: Saga Continues

Dedicated time to code is limited.  Each month, I try to find blocks of programming time between emergency shifts, and after completing fpnotebook.com content updates. This past year I was also distracted by the Microsoft Data Science curriculum.

Coding projects generally center around medical apps for the site.  Small, self-limited projects that can be completed in a couple of weeks are ideal.  However, most projects require months to complete and it can be difficult to frequently leave and return to these projects, each time spending time to reacquaint myself with the code.  In the meantime, frameworks update, at times with breaking changes.

This month I returned to one of my most challenging projects of recent time: Integrating an angular 2/4 application into asp.net core.  Pluralsight, Lynda.com and Udemy have covered most topics I need, related to angular and asp.net core (including their combination).  In addition, Angular and Asp.net Core both have excellent online documentation.   Microsoft has even created combined SPA project templates for angular within asp.net core projects (Javascript Services).

But these lessons and documentation do not cover my approach well, which I describe in this post.  I think Javascript Services, which embeds the angular app within asp.net core MVC is not the right approach (at least for me), as they do not preserve the angular cli tool chain nor allow for testing angular in isolation of asp.net core.

So the last 2 days, I had time to reacquaint myself with this project and experience frustrations that brought any chance of productivity to a screeching halt.   Day 1 was  spent on deployment to IIS with sql database (one db on development machine, one db on server) – which is not covered well in any video series I have seen.  Many demo videos use Auth0 for authorization and Firebase for database.  But authorization and database are some of the key reasons I use the asp.net core framework.  Why defer that functionality?

Elsewhere, I cover deployment and database.  Despite keeping these blogs for my own reference, it still takes hours to get the whole publish process working.  That is when I found IIS related errors despite my angular + asp.net core working when built on my development machine or on the production server when using local host.  The problem I have had previously, and had again, was the issue with angular base href statement in the index.cshtml file.  My key finding was that the base href works fine as long as it remains “~/” and not a subdirectory (e.g. angular_dist).  Previously, my angular cli project would build its files and send them to a subdirectory of wwwroot.  I did this to prevent overwriting the other assets in the main directory not related to angular.  However, the cli build command has options allowing to not delete files in the destination directory and to not hash file names.

Now I am using the following command line to build angular destination files directly into the asp.net core wwwroot directory:

ng build --prod --extract-css=false --output-hashing=none
     --delete-output-path=false 
     --output-path="../backend/wwwroot/"

 

Posted in Uncategorized

Cryptic Errors in Angular + Asp.Net Core

This is more a note to self, but might help others.

My current application set-up is:

  1. asp.net core backend with web api
  2. angular cli frontend
  3. Build the frontend (ng build) generates output into the wwwroot folder of the backend/asp.net project.

With angular-cli development build, the frontend calls a fake a api based on finding the environment variable set to development.

With the angular-cli production build, the frontend calls the real api (from the wwwroot directory inside the asp.net core project, it is just “/api”.

I spent the better part of a day, trying to get the angular cli production build to work inside the asp.net core wwwroot directory.  First, I could not get the environ variable to change from development to production.  Then I realized the browser was caching the page (this happens so often to me – yet I still forget to clear the cache).  Then I realized the production build worked without error but I kept seeing multiple console errors Uncaught SyntaxError: Unexpected token <  and the angular app refused to load.

The error was cryptic.  I assumed since this worked in development build, that something in the production file processing was awry (e.g. uglify) or a disallowed character had been inserted (e.g. BOM).  I searched online and of course Stack Overflow, which lead to updating Node and Angular-cli, but of course this did not fix the problem.

I snacked. I napped.  Stared at screen.  Answered emails.  rebuilt again – just in case.  stared at screen.

Then I noticed the filenames in the angular-cli destination directory.  In angular development build, the files are called  for example, “inline.bundle.js”, but in the default production build, there is cache busting enabled – so the files are named “inline.ajdsfk2374sf.bundle.js”.   In addition, the development build outputs the css to a js file, but in production build the css is output to a css file.

This is not a problem if you use the generated index.html file, but I have a asp.net mvc default view – Index.cshtml file:

 

<app-root>Loading...</app-root>

@section scripts {
 http://~/angular_dist/inline.bundle.js
 http://~/angular_dist/scripts.bundle.js




http://~/angular_dist/styles.bundle.js

http://~/angular_dist/vendor.bundle.js
 http://~/angular_dist/main.bundle.js

}

 

Why was the error Uncaught SyntaxError: Unexpected token <“?

In any event, the solution is fairly simple:

ng build --prod --ec=false --oh=media
which keeps the script files and css file the same as in development.
Had the original error read – “file not found”, you would not be reading this.  Cryptic errors and a day distracted.
Posted in Uncategorized

Asp.Net Core Testing Repositories and Mocking EF

I wasted the better part of the day implementing simple tests.   Even the most mundane, basic steps that have typically taken no time, were prolonged.  I remember an automated tool inside Visual Studio in 2010 or so, when you could right click on a project or class (context menu) in solution explorer, and select “Create Unit Tests”, and not only would it create a test project with the associated project references and accessors for private objects/methods, but would also offer a dialog to select which methods to create unit test coverage for.   That is not my current experience, which is mostly DIY.

First creating a new test project, did not seem to appear correctly in the solution explorer, under solution items; I had to recreate it several times.  Then I could not get my asp.net core to load inside the test project (which I suspect was being saved as a standard project, despite choosing core).  Then I could not get Moq to load.  I could not find the correct EntityFramework core reference for the test project.  I tried both xunit and mstest projects.  I tried CLI and from inside VS.

Finally, I it is working, and I am not certain if I could repeat my successful steps without some repeat mis-steps again.  In solution explorer, right-click the project => add new project => dotnet core => xunit project.

My resulting .csproj file looks like this:

 

<Project Sdk="Microsoft.NET.Sdk">

 <PropertyGroup> 
 <TargetFramework>netcoreapp1.1</TargetFramework>
 </PropertyGroup>

 <ItemGroup>
 <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="1.1.2" />
 <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
 <PackageReference Include="Moq" Version="4.7.10" />
 <PackageReference Include="xunit" Version="2.2.0" />
 <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
 </ItemGroup>

 <ItemGroup>
 <ProjectReference Include="..\backend\backend.csproj" />
 </ItemGroup>

</Project>

 

The next step was to implement repository testing.  This was an even better exercise in frustration; I nearly gave up a half dozen times.   Ultimately, this link on Microsoft Documentation site is the overall approach:  Entity Framework Testing with a Mocking Framework (EF6 onwards), but this will not work fully as written for asp.net core (esp. for async).  I was able to modify the MS documentation with this Stack Overflow answer.  Finally, I found Armen Shimoon’s Mocking DbSet Helpers which really cleaned up the code.

I put these pieces together as follows, starting with Armen’s piece, but adding async functionality :

 /// <summary>
 /// From http://dotnetliberty.com/index.php/2016/02/22/moq-on-net-core/
 /// </summary>
 /// 
 public static class DbSetMock
 {
 public static Mock<DbSet<T>> Create<T>(params T[] elements) where T : class
 {
 return new List<T>(elements).AsDbSetMock();
 }
 }

 public static class ListExtensions
 {
 public static Mock<DbSet<T>> AsDbSetMock<T>(this List<T> list) where T : class
 {
 IQueryable<T> queryableList = list.AsQueryable();
 Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
 dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider);
 dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression);
 dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType);
 dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(queryableList.GetEnumerator());


 dbSetMock.As<IAsyncEnumerable<T>>()
 .Setup(m => m.GetEnumerator())
 .Returns(new TestAsyncEnumerator<T>(queryableList.GetEnumerator()));

 dbSetMock.As<IQueryable<T>>()
 .Setup(m => m.Provider)
 .Returns(new TestAsyncQueryProvider<T>(queryableList.Provider));


 return dbSetMock;
 }


 }

Then here is the async functionality code:

 /// <summary>
 /// From https://stackoverflow.com/questions/40476233/how-to-mock-an-async-repository-with-entity-framework-core#answer-40491640
 /// </summary>
 /// <typeparam name="TEntity"></typeparam>
 internal class TestAsyncQueryProvider<TEntity> : IAsyncQueryProvider
 {
 private readonly IQueryProvider _inner;

 internal TestAsyncQueryProvider(IQueryProvider inner)
 {
 _inner = inner;
 }

 public IQueryable CreateQuery(Expression expression)
 {
 return new TestAsyncEnumerable<TEntity>(expression);
 }

 public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
 {
 return new TestAsyncEnumerable<TElement>(expression);
 }

 public object Execute(Expression expression)
 {
 return _inner.Execute(expression);
 }

 public TResult Execute<TResult>(Expression expression)
 {
 return _inner.Execute<TResult>(expression);
 }

 public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
 {
 return new TestAsyncEnumerable<TResult>(expression);
 }

 public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
 {
 return Task.FromResult(Execute<TResult>(expression));
 }
 }

 internal class TestAsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>
 {
 public TestAsyncEnumerable(IEnumerable<T> enumerable)
 : base(enumerable)
 { }

 public TestAsyncEnumerable(Expression expression)
 : base(expression)
 { }

 public IAsyncEnumerator<T> GetEnumerator()
 {
 return new TestAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
 }

 IQueryProvider IQueryable.Provider
 {
 get { return new TestAsyncQueryProvider<T>(this); }
 }
 }

 internal class TestAsyncEnumerator<T> : IAsyncEnumerator<T>
 {
 private readonly IEnumerator<T> _inner;

 public TestAsyncEnumerator(IEnumerator<T> inner)
 {
 _inner = inner;
 }

 public void Dispose()
 {
 _inner.Dispose();
 }

 public T Current
 {
 get
 {
 return _inner.Current;
 }
 }

 public Task<bool> MoveNext(CancellationToken cancellationToken)
 {
 return Task.FromResult(_inner.MoveNext());
 }
 }

 

Finally, here were the repository tests:

 static DbContextOptions<ApiFpn2DbContext> _options = new DbContextOptionsBuilder<ApiFpn2DbContext>()
.UseInMemoryDatabase(databaseName: "ApiFpn2DbContext_testDatabase")
.Options;

 [Fact]
 public async void AddAsyncTest()
 {
 var mockSet = new Mock<DbSet<UserProfile>>();

 var mockContext = new Mock<ApiFpn2DbContext>(_options);
 mockContext.Setup(m => m.UserProfiles).Returns(mockSet.Object);

 var service = new UserProfileRepository(mockContext.Object);
 var result = await service.AddAsync(new UserProfile {
 Id="1",
 Username="user1"
 });
 mockContext.Object.SaveChanges();

 mockSet.Verify(m => m.AddAsync(It.IsAny<UserProfile>(), new CancellationToken()), Times.Once());
 mockContext.Verify(m => m.SaveChanges(), Times.Once());
 }

 [Fact]
 public async Task GetAllUserProfilesAsync()
 {
 var userProfiles = new UserProfile[] { new UserProfile { Id = "user1", Username = "user1" } };
 Mock<DbSet<UserProfile>> userDbSetMock = DbSetMock.Create(userProfiles);

 var mockContext = new Mock<ApiFpn2DbContext>(_options);
 mockContext.Setup(c => c.UserProfiles).Returns(userDbSetMock.Object);

 var service = new UserProfileRepository(mockContext.Object);

 var results = await service.GetAsync();
 var data = results.Data;
 Assert.NotNull(data);
 Assert.Equal(1, data?.Count);
 Assert.True(results.Success);
 Assert.Equal(userProfiles[0].Username, data[0].Username);
 }

 }

 

After all that, I found this Github Issue Report for Entity Framework: Async MOQ testing with EntityFramework Core.  I was wondering why EF did not have better testing helpers, as the ones above based on Armen Shimoon’s code.  Ultimately, the EF team does not seem to recommend mocking EF.    So, how then do you test Repositories?  They argue that EF uses a repository pattern already, so why add a second one on top?

Julie Lehrman has a Pluralsight video Entity Framework in the Enterprise: Understanding EF Encapsulation and the great Repository Debates,  in which she reviews the architecture patterns, and when to use a Repository.  My understanding from this video series, is that she will still, for certain simple cases, use a classic repository (basic CRUD functionality).  This mapping is often done via generic repository classes.

However, she seems to highlight business use case specific persistence classes/methods (e.g. Read users with associated Notes), instead of writing  simple wrappers around EF CRUD  (1:1  maps of Create, Read, Update and Delete between the repository and EF).   This makes sense – why recreate what EF already does. She makes a similar argument regarding Unit Of Work objects; why recreate logic already contained in the EF data context object.

Finally, as a related concept, Julie Lehrman says she tends to return IEnumerable from her persistence objects instead of IQueryable, in order to lock down functionality and business logic for specific cases.  Instead of broad reuse (all but the kitchen sink), the focus is on solving specific real needs in the software.  When new use cases arise, write new persistence classes/methods.

I think my repositories have already morphed into business specific logic, rather than simply wrapping EF Crud functionality.  Even if we call these classes something other than Repositories, they are still persistence objects that are not simply EF wrappers and have unique functionality that should be unit tested.  So again, how do you unit test persistence objects, if you do not mock Entity Framework?  I may be misunderstanding the EF team’s response in this Github Issue Report for Entity Framework:, but counter to their argument, I think there is a strong use case for making this testing less cumbersome.

 

Posted in Uncategorized

Angular 2/4 Dynamic Content Woes

I have been working for sometime on an angular version of my fpnotebook.com website. I migrated from an Angular 1 version  to an Angular 2 (late beta) version.  I have been setting up a backend using asp.net core, and thought I would bring the Angular 2 beta version up to the Angular 4 release.  Overall, the upgrade process was starting off fairly smooth with instructions like these. That’s when I noticed the absence of dynamic content tools in Angular 4.

Side note: AngularJs (version 1) is now just called Angular, not Angular 2 or Angular 4 – just Angular.  But try web searching for Angular – finding relevant version specific content has become difficult.  So I am referring to it as Angular 2/4.

My fpnotebook.com content is medical information organized into 31 books (e.g. cardiology), 722 chapters (e.g. blood pressure) and 6407 pages (e.g. hypertension).  Each page is stored in folders using a book/chapter/page hierarchy,  for example: http://www.fpnotebook.com/CV/Htn/Hyprtnsn.htm.

For the angular app, I keep each page in a json file.  Pages are composed of outlines, and each block of the outline (think roman numerals I, II, III) are stored in an array of page blocks, like this:

{
"Heading": "Risk Factors",
"Content": "<ol><li>See <a href='#/library/CV/Prevent/CrdcRsk' class='LinkPage' data-cui='C0580320'>Cardiac Risk Factor</a>s</li></ol>"
},

Each of these blocks is the template for a component, and up until full release version of angular 2, I could dynamically insert this outline html content and have it be JIT (just-in-time) compiled and function as Angular code, including the links as RouterLinks.  Worked great.

And then came the push for smaller Angular distributions and ahead-of-time compilation (AOT), and away went dynamic content and JIT compilation.  The html can still be inserted into a component, but the html is no longer compiled.  The outline still looks like an outline, but it is not integrated with angular.  This means that RouterLinks, custom components, component events and data, do not work.

I thought there must still be a way, surely with all the old directive functionality that I could not previously understand;  surely there must be a way to do this.  And it would seem there are ways to dynamically insert components with the ComponentFactoryResolver, but I could not find a way to insert a template and have it compiled dynamically by Angular.

I then found this blog entry: Forget $compile in Angular 2, in which the component template html is modified as DOM elements. In effect you use query selectors (similar to jquery css selectors) to find html elements and  attach javascript event listeners directly.  This actually works,  but I initially resisted it.  Going outside of Angular to manipulate the DOM directly is not ideal.

So, I looked for various ways to use Angular facilitated approaches to dynamically create the equivalent to RouterLinks.   I tried various alternatives to using ElementRef, such as @ContentChildren(), but these would not work, since I still had uncompiled html.   I was however able to use the Angular Renderer2 service.

So, given the json format above, and a page component with markup like this:

 <app-page-block-html [innerHTML]="block.Content"></app-page-block-html>

Side Issue: Curiously, Angular removes data elements (e.g. data-cui=”C123456″) as part of its sanitize process of [innerHtml], and this breaks part of my functionality.  I’m not sure why the Angular team chose to black-list data elements.  How can you XSS attack with a data attribute?  However, there is a work around using a pipe here.   Hopefully the Angular team will reconsider – by disallowing innocuous attributes like the data attribute, they force work-arounds (e.g. bypass security methods) that open up larger security holes.

The following component code would load this dynamically with working links:

import { Component, OnInit, Input, Renderer2, ViewChild, ElementRef, ContentChildren, QueryList, Directive } from '@angular/core';
import { Router } from "@angular/router";

@Component({
 selector: 'app-page-block-html',
 templateUrl: './page-block-html.component.html',
 styleUrls: ['./page-block-html.component.less']
})

export class PageBlockHtmlComponent implements OnInit {
 
 private clickListeners: Function[] = [];

 constructor(private router: Router,private el:ElementRef, private renderer: Renderer2) { }

 ngAfterViewInit() { // for searching a components template
 const anchorNodes:NodeList = this.el.nativeElement.querySelectorAll('a[href]:not(.LinkRef)'); //or a.LinkPage

 const anchors:Node[] = Array.from(anchorNodes); //or Array.prototype.slice.call(anchorNodes);

 anchors.forEach(anchor => {
      let listener = this.renderer.listen(anchor,'click',e=>{
           e.preventDefault();
           let href = e.srcElement.getAttribute('href');
           this.router.navigateByUrl(href);
      });
 this.clickListeners.push(listener);

 }

 

So another hurdle circumvented with a process that works well despite my wishing there was a more best-practice way.  All due to the sacrifice of JIT and dynamic content for the speed/footprint of Angular with AOT.

 

Posted in Uncategorized

angular spa, asp.net core and authentication – Part 2, Authenticating with MVC

In Part 1, I discussed my rationale for the following set-up using asp.net core MVC for authentication for an  angular single page application (SPA) frontend and an asp.net core backend.  In this post, I’m going to build on concepts from Michel Dymel’s two project set-up, as well as parts of the MS Javascriptservices SPA template project.  I am setting this up on Windows, so I’ll be using Visual Studio 2017 Community Edition for backend editing, and VS Code for frontend.

Step 1: Asp.Net Core Backend/Server Project

  1. Within Visual Studio 2017, Create a new asp.net core project, inside a new solution
  2. Choose to create an MVC/API application with User Authentication (along with Git)
  3. If adding this to another git repo, then add a .gitignore file manually for VS project
  4. The backend project should remain the default project (bold in solution explorer)
  5. In project properties, under debug tab, note the App URL (http://localhost:port)
    1. The app url is used below in setting the proxy

newMvcApp2017-1

 newMvcApp2017-2

Step 2: Angular-Cli Frontend project

  1. Add a new netCore class library project inside the solution created above
    1. Delete the default class1.cs that is automatically created
  2. Open a powershell window here within this new project directory
  3. Prepare to use node/npm/angular-cli
    1. Install or update node (check version with “node -v”)
    2. Update angular-cli
      1. npm uninstall -g @angular/cli
      2. npm cache clean
      3. npm install -g @angular/cli@latest
  4. Create a new angular project via the command-line interface (CLI)
    1. ng new [projectname] –routing –style scss –prefix [myPrefix]
      1. choose your own projectname (e.g. frontend) and prefix (for components, directives)
      2. for style, select scss or less (css is the default)
      3. If  routing flag is specified, angular will automate routing set-up
    2.  Set a proxy configuration pointing to the asp.net core backend as above
      1. This uses Michal Dymel’s set-up 
      2. This will only be used for development (npm start)
      3. Create a “proxy.conf.json” file in the main frontend directory:
      4. {
          "/api": {
            "target": "http://localhost:61234",
            "secure": false
          }
        }
      5. Edit the start command in “package.json”
        1.   “start”: “ng serve –proxy-config proxy.conf.json”
        2. To use the proxy, run “npm start”, NOT “ng serve”
    3. Set up the production build pipeline for the angular app
      1. On “ng Build”, the angular app distribution is written to wwwroot
      2. In the angular-cli.json file, edit “OutDir”
      3.  “outDir”: “../backend/wwwroot/angular_dist/”
        1. Writing to wwwroot will clear the directory (angular-cli wipes it)
        2. Therefore, better to write to a subdir

Step 3: Other Angular Frontend Customizations

Now, for a compromise.  I want a fast set-up for the server login without much customization.   I typically use Bootstrap with angular, but instead of using jquery, I use ng-bootstrap, and I’ve started using Bootstrap 4, which is still in alpha version as I write this blog entry.

However,  Asp.net uses Bootstrap 3 and JQuery as its default, so I’m going to compromise and use this set-up for my app (Bootstrap 3, jquery).  I will be using the Sass version of Bootstrap.  Finally, the bootstrap css, and script libraries (jquery, bootstrap) should only be loaded once (client or server).  I need to load them either in the angular-cli.json or in the server _layout.cshtml.  Since I will frequently run the angular app in memory, outside of the asp.net app, I will want the scripts to be loaded via the angular-cli.json.  I’ll need to therefore make sure that the layout.cshtml used to hold the angular app does not load these scripts also.

Adding Boostrap V3

  1. npm install –save bootstrap-sass font-awesome jquery
  2. npm install @types/jquery –save-dev
  3. create empty file in “src/: _variables.scss” and add the following:
$icon-font-path: '../node_modules/bootstrap-sass/assets/fonts/bootstrap/';
$fa-font-path:'../node_modules/font-awesome/fonts';
  1. add to styles.scss file:
@import 'variables';
@import '../node_modules/bootstrap-sass/assets/stylesheets/_bootstrap';
@import '../node_modules/font-awesome/scss/font-awesome';

Finally set styles and scripts objects in  the “angular-cli.json file:”

"styles": ["styles.scss"],
"scripts": [
"../node_modules/jquery/dist/jquery.min.js",
 "../node_modules/bootstrap-sass/assets/javascripts/bootstrap.min.js"
],

Step 4: AspNet MVC Index View to show the angular Spa

Change the “Backend\Views\Home\Index.cshtml” to contain the following code:

@{
 ViewData["Title"] = "Angular App";
 Layout = "_Layout_ngEmbed";
}

Loading...

@section scripts {
http://~/angular_dist/inline.bundle.js
http://~/angular_dist/polyfills.bundle.js
http://~/angular_dist/styles.bundle.js
http://~/angular_dist/vendor.bundle.js
http://~/angular_dist/main.bundle.js
}

Notice that the Layout is being set to a new file “Layout_ngEmbed.cshtml ” (instead of using the default _Layout.cshtml).  We need to customize a couple of items in the Layout file, specific for pages that have an embedded angular app:

  1. In the shared folder, copy “_Layout.cshtml” to a new file and name it “_Layout_ngEmbed.cshtml”
  2. Delete script files that will instead be loaded by the angular app
    1. Delete all links to the bootstrap.css
    2. Delete all script tags to bootstrap.js and jquery.js
  3. In the head section, add a base href tag (angular will need this):

Now, to show the frontend angular code embedded inside the backend MVC app:

  1. at the powershell prompt, type “ng build”
  2. In Visual Studio, in the backend app, “Ctrl F5” (run without debug)

To run the angular app alone, in memory, but still access the api:

  1. at the powershell prompt, “npm serve” (this will run “ng serve” with proxy)
  2. Note that the backend needs to be running (Ctrl-F5) for Api to work

Next Steps

That is it for a basic set-up.  The angular app can be run on its own to allow for rapid development and can still call the Api even when not embedded.  When embedded in the MVC app, login is possible and that single asp.net core MVC project (backend) can be deployed to a server.

Some additional to-do items:

  1. Login and call protected Apis either with tokens or cookies
  2. Login and authorize api access via claims or roles
  3. apply user information to app content (e.g. username as author)
  4. Build backend admin pages in MVC
  5. Automate frontend “ng build” as part of backend pre-build of the project
Posted in Uncategorized