Introduction
ASP.NET Core combined with Angular is becoming an increasingly popular tech stack for building interactive web apps. However, if you want to manage the content of such a web app, your only choice has been to use a headless CMS service. This can be overkill especially for smaller web apps and doesn’t allow for easy previewing of content changes. Lynicon CMS provides SPA content management with preview for ASP.NET Core, which unlike the more usual headless CMS setup allows you to immediately view the effects of your content changes. It is lightweight and quick to set up, and allows for content to be stored in a file rather than a database.
This article demonstrates how to add Lynicon CMS content management to the ASP.NET Core / Angular template in Visual Studio 2017.
Back End
Open Visual Studio and choose File/New Project. Select Visual C#/.NET Core on the left and ASP.NET Core Web Application on the right.
Then choose the Angular template.
Now follow the instructions here: https://lynicon.atlassian.net/wiki/spaces/LAC/pages/50036737/Installing+to+a+New+Project+-+VS2017+.Net+4.6.1+.Net+Standard+2.0+Core+2.0
to set up Lynicon CMS. Start at the subheading ‘Install Lynicon’ as you have already created the project. Follow the optional step to install the Storeless module, and continue to the end. It’s just a matter of installing a couple of Nuget packages and running 3 commands.
Now you have a CMS installed in your project, but it isn’t yet doing anything. Lynicon uses C# classes to define content types, so your first step is to create a content class to hold the content you’re seeing on the home page.
Create a folder in the project root called Models and create a file within it called HomeContent.cs. Cut and paste the following into that file:
using Lynicon.Attributes;
using Lynicon.Models;
public class HomeContent : PageContent
{
[Summary]
public string Title { get; set; }
public MedHtml Body { get; set; } = new MedHtml();
}
In Startup.cs, in the ConfigureServices
method, amend the call to services.AddLynicon
as below, adding the SetDiverter
call:
services.AddLynicon(options => options.UseConfiguration(Configuration.GetSection("Lynicon:Core"))
.UseModule<CoreModule>()
.UseModule<Storeless>(Configuration.GetSection("Lynicon:Storeless:Cache"))
).AddLyniconIdentity()
.SetDiverter(new SpaDataDiverter());
This changes how the CMS routes content requests so that it works properly with SPA routing.
Then again in Startup.cs, add the line with MapDataRoute<HomeContent>()
as below:
routes.MapLyniconRoutes();
routes.MapDataRoute<HomeContent>("home", "");
This creates a content-managed route on the / url. This means if you go to this url while logged in as a content editor, Lynicon will show you an editor for the page content alongside the page itself. If you go to this page using a request with the ‘Accept: application/json’
header, it will give you the content data for that page in JSON format.
That’s all we need to do server side to set up content management, now we need to pay some attention to the front-end!
Download the file lyniconcontent.zip, unzip lynicon-content.ts from it and put it in your ClientApp/src/app folder. This contains some classes we can use to convert our Angular application to work with Lynicon CMS.
Angular Routing
First, we need to update our SPA routing so that it pulls in content data when changing route to a content-managed route.
First, we create a class mirroring the HomeContent
class on the server side. We create this in a home.content.ts file in the home/ folder which contains the home page component.
export class HomeContent {
title: string;
body: string;
}
This is nice and simple but note we use JS camel casing on the front end side: the built-in JSON formatter in ASP.NET Core automatically changes property names to start with a lower-case letter.
Where routing is declared in Angular, we edit the / route as follows:
{ path: '', component: HomeComponent, pathMatch: 'full',
resolve: { content: ContentResolver }, data: { contentType: HomeContent } },
We have added two extra properties here: resolve
tells the route to run the ContentResolver
when it is navigated to. This class fetches the content from the back end. The data.contentType
property is used to specify our content type so the ContentResolver
can return an empty type instance if there is currently no content at the route.
We go into the HomeComponent
now to enable it to receive the content.
export class HomeComponent implements IContentAwareComponent {
@FromContent()
content: HomeContent;
constructor(public injector: Injector) {
}
}
We’ve made the class implement IContentAwareComponent
by pulling in the Injector dependency into an automatic public
property. Then we have added a property with type HomeContent
. On this is a decorator: @FromContent()
which arranges for the property to be initialised with the content data fetched while routing.
In the markup file, home.component.html, we can now plug the content into the rendered component:
<h1>{{content.title}}</h1>
<div [innerHtml]="content.body"></div>
Now we add an extra tweak which makes navigation within the preview page work so that we are shown the appropriate content editor for the url we have moved to.
In the routing location, do this:
RouterModule.forRoot([
{ path: '', canActivateChild: [ BypassActivate ], children: [
{ path: '', component: HomeComponent, pathMatch: 'full',
resolve: { content: ContentResolver }, data: { contentType: HomeContent } },
... other routes ...
]}
])
We wrap all our routes up as children of a parent route with the canActivateChild
property set to BypassActivate
. This route guard checks whether the route we are navigating to should show an editor, and if so, it jumps out of Angular routing and does a normal browser navigation to the required route. This goes back to the server to get the content editor together with a reload of the front end at the appropriate URL. If it were not for this, routing would all happen within the preview page without it being able to change the content editor.
Adding Content
Now we’ve set up our SPA to read in content from the back end for the home page, however we’ve currently got no content record. If we run the site, the home page component doesn’t render anything in the space on the right.
To create a home page content item, go to /lynicon/login to log in to the CMS. When setting up Lynicon, you will have provided an admin password, use this and the user name administrator
. Now go to /lynicon/items. This page lists all the content items in the CMS, however there are currently none, so if you go to the bar marked Home and click the expander arrow on the left, nothing will appear. To create the content item, click the plus sign on the Home bar. You don’t need to enter any URL information in the bar which then appears, so click the page icon to the right, and you will be taken to the home page again with a content editor. If you enter some text into the Title
and Body
fields and click SAVE (button is on the bottom right), the page will be created, and you will see your entered text displaying in the HomeComponent
area.
Conclusion
This only scratches the surface of what is possible with Angular and Lynicon CMS on .NET Core. My next article will describe how to use a template in Angular to show multiple pages with different content and manage those pages in Lynicon. The complete test site with content control of the home page and multiple template pages can be found at https://github.com/jamesej/lynicon-angular. The main site for Lynicon is at http://www.lynicon.com.