在构建交互式Web应用时,如果需要管理Web应用的内容,通常的选择是使用无头CMS服务。但对于小型Web应用来说,这可能过于复杂,并且不允许轻松预览内容变更。Lynicon CMS为ASP.NET Core提供了单页应用(SPA)的内容管理与预览功能,与常见的无头CMS设置不同,它允许立即查看内容变更的效果。它轻量级且设置快速,允许内容存储在文件而非数据库中。
本文将演示如何在Visual Studio 2017中将Lynicon CMS内容管理添加到ASP.NET Core/Angular模板。
打开Visual Studio,选择“文件”/“新建项目”。在左侧选择“Visual C#/.NET Core”,在右侧选择“ASP.NET Core Web应用程序”。
然后选择Angular模板。接下来按照以下指南操作: 从“Install Lynicon”小标题开始,因为已经创建了项目。按照可选步骤安装Storeless模块,并继续到最后。这仅仅是安装几个Nuget包并运行3个命令的问题。
现在项目中已经安装了CMS,但它还没有做任何事情。Lynicon使用C#类来定义内容类型,所以第一步是创建一个内容类来保存在首页上看到的内容。
在项目根目录下创建一个名为Models
的文件夹,并在其中创建一个名为HomeContent.cs
的文件。将以下代码粘贴到该文件中:
using Lynicon.Attributes;
using Lynicon.Models;
public class HomeContent : PageContent
{
[Summary]
public string Title { get; set; }
public MedHtml Body { get; set; } = new MedHtml();
}
在Startup.cs
的ConfigureServices
方法中,修改对services.AddLynicon
的调用,如下所示,添加SetDiverter
调用:
services.AddLynicon(options => options.UseConfiguration(Configuration.GetSection("Lynicon:Core"))
.UseModule<CoreModule>()
.UseModule<Storeless>(Configuration.GetSection("Lynicon:Storeless:Cache"))
).AddLyniconIdentity().SetDiverter(new SpaDataDiverter());
这改变了CMS路由内容请求的方式,使其能够正确地与SPA路由一起工作。
再次在Startup.cs
中,添加带有MapDataRoute<HomeContent>
的行,如下所示:
routes.MapLyniconRoutes();
routes.MapDataRoute<HomeContent>("home", "");
这在/ url上创建了一个内容管理路由。这意味着,如果以内容编辑者的身份登录并访问这个url,Lynicon将向展示页面内容的编辑器以及页面本身。如果使用带有‘Accept: application/json’
头部的请求访问这个页面,它将以JSON格式提供该页面的内容数据。
这就是在服务器端设置内容管理所需的全部,现在需要关注前端!
下载文件lyniconcontent.zip
,解压其中的lynicon-content.ts
并将其放入ClientApp/src/app
文件夹。这包含一些可以使用的类,以便将Angular应用程序转换为与Lynicon CMS一起工作。
首先,需要更新SPA路由,以便在更改路由到内容管理路由时拉取内容数据。
首先,创建一个与服务器端HomeContent
类相对应的类。在包含首页组件的home/
文件夹中创建一个home.content.ts
文件。
export class HomeContent {
title: string;
body: string;
}
这很简单,但请注意在前端使用JS驼峰命名:ASP.NET Core内置的JSON格式化程序会自动将属性名称更改为以小写字母开头。
在Angular中声明路由的地方,按如下方式编辑/路由:
RouterModule.forRoot([
{ path: '', component: HomeComponent, pathMatch: 'full',
resolve: { content: ContentResolver },
data: { contentType: HomeContent } },
// ...其他路由...
])
在这里添加了两个额外的属性:resolve告诉路由在导航到它时要运行ContentResolver。这个类从后端获取内容。data.contentType属性用于指定内容类型,以便ContentResolver在当前路由没有内容时返回一个空类型实例。
现在进入HomeComponent
,使其能够接收内容。
export class HomeComponent implements IContentAwareComponent {
@FromContent() content: HomeContent;
constructor(public injector: Injector) { }
}
通过将Injector依赖项引入一个自动public属性来使类实现IContentAwareComponent。然后添加了一个带有类型HomeContent的属性。在这个属性上有一个装饰器:@FromContent()
,它安排属性用路由期间获取的内容数据进行初始化。
在标记文件home.component.html
中,现在可以将内容插入到渲染的组件中:
<h1>{{content.title}}</h1>
<div [innerHtml]="content.body"></div>
现在添加一个额外的调整,使得在预览页面中的导航能够工作,以便可以看到移动到的url的适当内容编辑器。
在路由位置,这样做:
RouterModule.forRoot([
{ path: '', canActivateChild: [ BypassActivate ], children: [
{ path: '', component: HomeComponent, pathMatch: 'full',
resolve: { content: ContentResolver },
data: { contentType: HomeContent } },
// ...其他路由...
]}
])
将所有路由作为父路由的子路由包装起来,将canActivateChild属性设置为BypassActivate。这个路由守卫检查正在导航的路由是否应该显示编辑器,如果是的话,它跳出Angular路由并执行正常的浏览器导航到所需路由。这返回到服务器以获取内容编辑器以及在适当URL处重新加载前端。如果没有这个,路由将在预览页面内全部发生,而无法更改内容编辑器。
现在已经设置了SPA从后端读取首页的内容,但目前没有内容记录。如果运行站点,首页组件不会在右侧区域渲染任何内容。