0

0

详细介绍ZKEACMS for .Net Core

零下一度

零下一度

发布时间:2017-05-26 13:34:48

|

3123人浏览过

|

来源于php中文网

原创

zkeacms.core 是基于 .net core mvc 开发的开源cms,这篇文章主要为大家深度解析了zkeacms for .net core,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

ZKEACMS 简介
ZKEACMS.Core 是基于 .Net Core MVC 开发的开源CMS。ZKEACMS可以让用户自由规划页面布局,使用可视化编辑设计“所见即所得”,直接在页面上进行拖放添加内容。

ZKEACMS使用插件式设计,模块分离,通过横向扩展来丰富CMS的功能。

响应式设计

ZKEACMS使用Bootstrap3的栅格系统来实现响应式设计,从而实现在不同的设备上都可以正常访问。同时站在Bootstrap巨人的肩膀上,有丰富的主题资源可以使用。

简单演示

接下来看看程序设计及原理

项目结构

  • EasyFrameWork  底层框架

  • ZKEACMS   CMS核心

  • ZKEACMS.Article   文章插件

  • ZKEACMS.Product  产品插件

  • ZKEACMS.SectionWidget  模板组件插件

  • ZKEACMS.WebHost 

原理 - 访问请求流程

路由在ZKEACMS里面起到了关键性的作用,通过路由的优先级来决定访问的流程走向,如果找到匹配的路由,则优先走该路由对应的 Controller -> Action -> View,如果没有匹配的路由,则走路由优先权最低的“全捕捉”路由来处理用户的请求,最后返回响应。

优先级最低的“全捕捉”路由是用来处理用户自行创建的页面的。当请求进来时,先去数据库中查找是否存在该页面,不存在则返回404。找到页面之后,再找出这个页面所有的组件、内容,然后统一调用各个组件的“Display"方法来来得到对应的“ViewModel"和视图"View",最后按照页面的布局来显示。

ZKEACMS 请求流程图

驱动页面组件:

widgetService.GetAllByPage(filterContext.HttpContext.RequestServices, page).Each(widget =>
{
  if (widget != null)
  {
    IWidgetPartDriver partDriver = widget.CreateServiceInstance(filterContext.HttpContext.RequestServices);
    WidgetViewModelPart part = partDriver.Display(widget, filterContext);
    lock (layout.ZoneWidgets)
    {
      if (layout.ZoneWidgets.ContainsKey(part.Widget.ZoneID))
      {
        layout.ZoneWidgets[part.Widget.ZoneID].TryAdd(part);
      }
      else
      {
        layout.ZoneWidgets.Add(part.Widget.ZoneID, new WidgetCollection { part });
      }
    }
    partDriver.Dispose();
  }
});

页面呈现:

foreach (var widgetPart in Model.ZoneWidgets[zoneId].OrderBy(m => m.Widget.Position).ThenBy(m => m.Widget.WidgetName))
{
  

@if (widgetPart.Widget.Title.IsNotNullAndWhiteSpace()) {

@widgetPart.Widget.Title

@Html.DisPlayWidget(widgetPart)

} else { @Html.DisPlayWidget(widgetPart) }

}

插件“最关键”的类 PluginBase

每一个插件/模块都必需要一个类继承PluginBase,作为插件初始化的入口,程序在启动的时候,会加载这些类并作一些关键的初始化工作。

public abstract class PluginBase : ResourceManager, IRouteRegister, IPluginStartup
{
  public abstract IEnumerable RegistRoute(); //注册该插件所需要的路由 可返回空
  public abstract IEnumerable AdminMenu(); //插件在后端提供的菜单 可返回空
  public abstract IEnumerable RegistPermission(); //注册插件的权限
  public abstract IEnumerable WidgetServiceTypes(); //返回该插件中提供的所有组件的类型
  public abstract void ConfigureServices(IServiceCollection serviceCollection); //IOC 注册对应的接口与实现
  public virtual void InitPlug(); //初始化插件,在程序启动时调用该方法
}

具体实现可以参考“文章”插件 ArticlePlug.cs 或者“产品”插件 ProductPlug.cs 

加载插件 Startup.cs

public void ConfigureServices(IServiceCollection services)
{
  services.UseEasyFrameWork(Configuration).LoadEnablePlugins(plugin =>
  {
    var cmsPlugin = plugin as PluginBase;
    if (cmsPlugin != null)
    {
      cmsPlugin.InitPlug();
    }
  }, null);      
}

组件构成

一个页面,由许多的组件构成,每个组件都可以包含不同的内容(Content),像文字,图片,视频等,内容由组件决定,呈现方式由组件的模板(View)决定。

关系与呈现方式大致如下图所示:

实体 Enity

每个组件都会对应一个实体,用于存储与该组件相关的一些信息。实体必需继承于 BasicWidget 类。

例如HTML组件的实体类:

[ViewConfigure(typeof(HtmlWidgetMetaData)), Table("HtmlWidget")]
public class HtmlWidget : BasicWidget
{
  public string HTML { get; set; }
}
class HtmlWidgetMetaData : WidgetMetaData
{
  protected override void ViewConfigure()
  {
    base.ViewConfigure();
    ViewConfig(m => m.HTML).AsTextArea().AddClass("html").Order(NextOrder());
  }
}

实体类里面使用到了元数据配置[ViewConfigure(typeof(HtmlWidgetMetaData))],通过简单的设置来控制表单页面、列表页面的显示。假如设置为文本或下拉框;必填,长度等的验证。

良精.Net企业网站管理系统5.7
良精.Net企业网站管理系统5.7

良精.Net企业网站管理系统是一款以.net为开发语言的企业网站系统。后台主要功能如下:1) 系统管理:管理员管理,网站配置,上传文件管理,QQ-MSN 在线客服设置,文件浏览,模版的编辑,样式表的编辑。2) 企业信息:后台自由添加修改企业的各类信息及介绍。3) 产品管理:产品类别新增修改管理,产品添加修改以及产品的审核。4) 订单管理:查看订单的详细信息及订单处理。5) 会员管理:查看修改删除会

下载

这里实现方式是向MVC里面添加一个新的ModelMetadataDetailsProviderProvider,这个Provider的作用就是抓取这些元数据的配置信息并提交给MVC。

services.AddMvc(option =>
  {
    option.ModelMetadataDetailsProviders.Add(new DataAnnotationsMetadataProvider());
  })

服务 Service

WidgetService 是数据与模板的桥梁,通过Service抓取数据并送给页面模板。 Service 必需继承自 WidgetService。如果业务复杂,则重写(override)基类的对应方法来实现。

例如HTML组件的Service:

public class HtmlWidgetService : WidgetService
{
  public HtmlWidgetService(IWidgetBasePartService widgetService, IApplicationContext applicationContext)
    : base(widgetService, applicationContext)
  {
  }
 
  public override DbSet CurrentDbSet
  {
    get
    {
      return DbContext.HtmlWidget;
    }
  }
}

视图实体 ViewModel

ViewModel 不是必需的,当实体(Entity)作为ViewModel传到视图不足以满足要求时,可以新建一个ViewModel,并将这个ViewModel传过去,这将要求重写 Display 方法

public override WidgetViewModelPart Display(WidgetBase widget, ActionContext actionContext)
{
  //do some thing
  return widget.ToWidgetViewModelPart(new ViewModel());
}

视图 / 模板 Widget.cshtml

模板 (Template) 用于显示内容。通过了Service收集到了模板所要的“Model”,最后模板把它们显示出来。

动态编译分散的模板

插件的资源都在各自的文件夹下面,默认的视图引擎(ViewEngine)并不能找到这些视图并进行编译。MVC4版本的ZKEACMS是通过重写了ViewEngine来得以实现。.net core mvc 可以更方便实现了,实现自己的 ConfigureOptionsRazorViewEngineOptions> ,然后通过依赖注入就行。

public class PluginRazorViewEngineOptionsSetup : ConfigureOptions
{
  public PluginRazorViewEngineOptionsSetup(IHostingEnvironment hostingEnvironment, IPluginLoader loader) :
    base(options => ConfigureRazor(options, hostingEnvironment, loader))
  {
 
  }
  private static void ConfigureRazor(RazorViewEngineOptions options, IHostingEnvironment hostingEnvironment, IPluginLoader loader)
  {
    if (hostingEnvironment.IsDevelopment())
    {
      options.FileProviders.Add(new DeveloperViewFileProvider());
    }
    loader.GetPluginAssemblies().Each(assembly =>
    {
      var reference = MetadataReference.CreateFromFile(assembly.Location);
      options.AdditionalCompilationReferences.Add(reference);        
    });
    loader.GetPlugins().Where(m => m.Enable && m.ID.IsNotNullAndWhiteSpace()).Each(m =>
    {
      var directory = new DirectoryInfo(m.RelativePath);
      if (hostingEnvironment.IsDevelopment())
      {
        options.ViewLocationFormats.Add($"/Porject.RootPath/{directory.Name}" + "/Views/{1}/{0}" + RazorViewEngine.ViewExtension);
        options.ViewLocationFormats.Add($"/Porject.RootPath/{directory.Name}" + "/Views/Shared/{0}" + RazorViewEngine.ViewExtension);
        options.ViewLocationFormats.Add($"/Porject.RootPath/{directory.Name}" + "/Views/{0}" + RazorViewEngine.ViewExtension);
      }
      else
      {
        options.ViewLocationFormats.Add($"/{Loader.PluginFolder}/{directory.Name}" + "/Views/{1}/{0}" + RazorViewEngine.ViewExtension);
        options.ViewLocationFormats.Add($"/{Loader.PluginFolder}/{directory.Name}" + "/Views/Shared/{0}" + RazorViewEngine.ViewExtension);
        options.ViewLocationFormats.Add($"/{Loader.PluginFolder}/{directory.Name}" + "/Views/{0}" + RazorViewEngine.ViewExtension);
      }
    });
    options.ViewLocationFormats.Add("/Views/{0}" + RazorViewEngine.ViewExtension);
  }
}

看上面代码您可能会产生疑惑,为什么要分开发环境。这是因为ZKEACMS发布和开发的时候的文件夹目录结构不同造成的。为了方便开发,所以加入了开发环境的特别处理。接下来就是注入这个配置:

services.TryAddEnumerable(ServiceDescriptor.Transient, PluginRazorViewEngineOptionsSetup>());            

EntityFrameWork

ZKEACMS for .net core 使用EntityFrameWork作为数据库访问。数据库相关配置 EntityFrameWorkConfigure

public class EntityFrameWorkConfigure : IOnConfiguring
{
  public void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  {
    optionsBuilder.UseSqlServer(Easy.Builder.Configuration.GetSection("ConnectionStrings")["DefaultConnection"]);
  }
}

对Entity的配置依然可以直接写在对应的类或属性上。如果想使用 Entity Framework Fluent API,那么请创建一个类,并继承自 IOnModelCreating

class EntityFrameWorkModelCreating : IOnModelCreating
{
  public void OnModelCreating(ModelBuilder modelBuilder)
  {
    modelBuilder.Entity().Ignore(m => m.Description).Ignore(m => m.Status).Ignore(m => m.Title);
  }
}

主题

ZKEACMS 使用Bootstrap3作为基础,使用LESS,定议了许多的变量,像边距,颜色,背景等等,可以通过简单的修改变量就能“编译”出一个自己的主题。

或者也可以直接使用已经有的Bootstrap3的主题作为基础,然后快速创建主题。

最后

关于ZKEACMS还有很多,如果您也感兴趣,欢迎加入我们。

ZKEACMS for .net core 就是要让建网站变得更简单,快速。页面的修改与改版也变得更轻松,便捷。

【相关推荐】

1. .Net Core 之 图形验证码

2. .NET Core配置文件加载与DI注入配置数据

3. .NET Core CLI工具文档dotnet-publish

4. Bootstrap0

5. Bootstrap1

6. Bootstrap2

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
抖音网页版入口与视频观看指南 抖音官网视频在线访问
抖音网页版入口与视频观看指南 抖音官网视频在线访问

本专题汇总了抖音网页版的入口链接、官方登录页面以及视频观看入口,帮助用户快速访问抖音网页版,提供免登录访问方式和直接进入视频播放页面的方法,确保顺利浏览和观看抖音视频。

0

2026.02.04

学习通网页版入口与在线学习指南 学习通官网登录与使用方法
学习通网页版入口与在线学习指南 学习通官网登录与使用方法

本专题详细汇总了学习通网页版入口与登录方法,提供学习通官方网页端入口、学生登录平台、网页版使用指南等内容,帮助用户快速稳定地登录学习通官网,顺利进入学习平台,提升学习效率和体验。

1

2026.02.04

Python Web 框架 Django 深度开发
Python Web 框架 Django 深度开发

本专题系统讲解 Python Django 框架的核心功能与进阶开发技巧,包括 Django 项目结构、数据库模型与迁移、视图与模板渲染、表单与认证管理、RESTful API 开发、Django 中间件与缓存优化、部署与性能调优。通过实战案例,帮助学习者掌握 使用 Django 快速构建功能全面的 Web 应用与全栈开发能力。

0

2026.02.04

Java 流式处理与 Apache Kafka 实战
Java 流式处理与 Apache Kafka 实战

本专题专注讲解 Java 在流式数据处理与消息队列系统中的应用,系统讲解 Apache Kafka 的基础概念、生产者与消费者模型、Kafka Streams 与 KSQL 流式处理框架、实时数据分析与监控,结合实际业务场景,帮助开发者构建 高吞吐量、低延迟的实时数据流管道,实现高效的数据流转与处理。

0

2026.02.04

Golang 容器化与 Docker 实战
Golang 容器化与 Docker 实战

本专题深入讲解 Golang 应用的容器化与 Docker 部署,涵盖 Docker 基础概念、容器构建与镜像管理、Go 应用的 Dockerfile 编写、跨平台容器部署与优化、Docker Compose 和 Kubernetes 部署工具。通过实际案例,帮助学习者掌握 如何将 Golang 应用容器化并实现高效部署与管理,提升系统的可扩展性与运维效率。

1

2026.02.04

全国统一发票查询平台入口合集
全国统一发票查询平台入口合集

本专题整合了全国统一发票查询入口地址合集,阅读专题下面的文章了解更多详细入口。

57

2026.02.03

短剧入口地址汇总
短剧入口地址汇总

本专题整合了短剧app推荐平台,阅读专题下面的文章了解更多详细入口。

104

2026.02.03

植物大战僵尸版本入口地址汇总
植物大战僵尸版本入口地址汇总

本专题整合了植物大战僵尸版本入口地址汇总,前往文章中寻找想要的答案。

49

2026.02.03

c语言中/相关合集
c语言中/相关合集

本专题整合了c语言中/的用法、含义解释。阅读专题下面的文章了解更多详细内容。

9

2026.02.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 8.5万人学习

python编程入门系列图文教程
python编程入门系列图文教程

共65课时 | 24.7万人学习

vscode其实很简单
vscode其实很简单

共72课时 | 29.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号