Zkeacms. Core is an open-source CMS based on. NET Core MVC, this article is mainly for the deep analysis of zkeacms for. NET core, with a certain reference value, interested in small partners can refer to
ZKEACMS Introduction
Zkeacms. Core is an open source CMS developed based on. Net Core MVC. ZKEACMS allows users to freely plan page layouts, use visual editing to design "WYSIWYG" and drag and drop content directly on the page.
ZKEACMS uses plug-in design, module separation, and scale-out to enrich the functionality of the CMS.
Responsive design
The ZKEACMS uses the BOOTSTRAP3 grid system for responsive design, enabling normal access on different devices. At the same time standing on the shoulders of the bootstrap giants, there are a wealth of theme resources to use.
Simple Demo
Next look at the program design and principles
Project structure
Easyframework Bottom Frame
Zkeacms CMS Core
Zkeacms. Article article Plugin
Zkeacms. Product Plug-in
Zkeacms. Sectionwidget template Component Plug-in
Zkeacms. Webhost
Principle-Access Request flow
routing plays a key role in Zkeacms, which determines the flow of access through the priority of the route, and if a matching route is found, it takes precedence over the Controller-to-Action View for that route, if there are no matching routes , the walk is handled by the lowest-priority "catch-all" route to the user's request, and finally the response is returned.
The lowest-priority "catch-all" route is used to process pages that the user creates themselves. When the request comes in, go to the database first to find out if the page exists, and return 404 if it does not exist. After finding the page, find out all the components and contents of the page, then call the "display" method of each component to get the corresponding "ViewModel" and "View", and then display it according to the layout of the page.
ZKEACMS Request Flowchart
Drive Page Components:
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 (); }});
Page Rendering:
foreach (Var widgetpart in Model.zonewidgets[zoneid]. (M = m.widget.position). ThenBy (M = m.widget.widgetname)) { <p style= "@widgetPart. Widget.customstyle" > <p class= "Widget @widgetPart. Widget.customclass "> @if (WidgetPart.Widget.Title.IsNotNullAndWhiteSpace ()) { <p class= "Panel Panel-default" > <p class= "panel-heading" > @widgetPart. widget.title </p> <p class= "Panel-body" > @Html. Displaywidget (widgetpart) </p> </p> } Else { @Html. Displaywidget (Widgetpart) } </p> </p>}
Plug-in "most critical" class Pluginbase
Each plugin/module will need a class to inherit pluginbase, as the plug-in initialization of the portal, when the program starts, it will load these classes and do some key initialization work.
Public abstract class Pluginbase:resourcemanager, Irouteregister, ipluginstartup{public abstract ienumerable< Routedescriptor> Registroute (); The route required to register the plug-in can return empty public abstract ienumerable<adminmenu> adminmenu ();//plug-in menu provided on backend can return empty public Abstract ienumerable<permissiondescriptor> registpermission (); Permissions to register plug-ins public abstract ienumerable<type> widgetservicetypes ();//Returns the type of all components provided in the plug-in public abstract void Configureservices (Iservicecollection servicecollection); IOC registers the corresponding interface with the implementation public virtual void initplug ();//Initialize the plug-in to invoke the method at program startup}
Specific implementation can refer to the "article" Plugin ArticlePlug.cs or "product" plug-in ProductPlug.cs
Load Plugin Startup.cs
public void Configureservices (iservicecollection services) { services. Useeasyframework (Configuration). Loadenableplugins (Plugin = { var cmsplugin = plugin as pluginbase; if (cmsplugin! = null) { cmsplugin.initplug ();} }, NULL); }
Component composition
A page, consisting of a number of components, each of which can contain different content, such as text, pictures, videos, etc., content is determined by the component, and the presentation is determined by the component's template (View).
The relationship and presentation are roughly as follows:
Entity Enity
Each component corresponds to an entity that stores some information related to that component. The entity must inherit from the Basicwidget class.
For example, an entity class for an HTML component:
[Viewconfigure (typeof (Htmlwidgetmetadata)), Table ("Htmlwidget")]public class htmlwidget:basicwidget{public String HTML {get; set;}} Class htmlwidgetmetadata:widgetmetadata
The entity class uses metadata configuration [Viewconfigure (typeof (Htmlwidgetmetadata))] to control the display of form pages and list pages with simple settings. If set to text or drop-down box, required, length, etc. verification.
The way to do this is to add a new modelmetadatadetailsproviderprovider to MVC, a provider that captures the configuration information of the metadata and submits it to MVC.
Services. ADDMVC (option = { option. Modelmetadatadetailsproviders.add (New Dataannotationsmetadataprovider ()); })
Services Service
Widgetservice is a bridge between data and templates that fetches data through a service and sends it to a page template. Service must inherit from Widgetservice<widgetbase, cmsdbcontext>. If the business is complex, the corresponding method of overriding the (override) base class is implemented.
For example, the service for HTML components:
public class Htmlwidgetservice:widgetservice
View Entity ViewModel
ViewModel is not required, you can create a new ViewModel and pass this ViewModel over if the entity (entities) is not uploaded to the view as ViewModel to meet the requirements, which will require overriding the Display method
public override Widgetviewmodelpart Display (Widgetbase widget, Actioncontext actioncontext) { //do some thing return widget. Towidgetviewmodelpart (New ViewModel ());}
View/Template widget.cshtml
Template is used to display content. The service collects the "Model" required by the template, and the final template displays them.
Dynamic compilation of distributed templates
The plugins ' resources are under their respective folders, and the default view engine (Viewengine) does not find these views and compile them. The MVC4 version of ZKEACMS is implemented by rewriting the viewengine. NET core MVC makes it easier to implement your own configureoptions<razorviewengineoptions>, Then pass the dependency injection on the line.
public class pluginrazorviewengineoptionssetup:configureoptions<razorviewengineoptions>{Public Pluginrazorviewengineoptionssetup (ihostingenvironment hostingenvironment, Ipluginloader loader): base (options = Configurerazor (options, hostingenvironment, loader)) {} private static void Configurerazor (Razorviewengineoptions opt Ions, 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); }}
Look at the code above and you may wonder why you should divide the development environment. This is due to the different structure of the folder directory when the Zkeacms is published and developed. Special handling of the development environment was added to facilitate development. The next step is to inject this configuration:
Services. Tryaddenumerable (SERVICEDESCRIPTOR.TRANSIENT<ICONFIGUREOPTIONS<RAZORVIEWENGINEOPTIONS>, Pluginrazorviewengineoptionssetup> ());
EntityFramework
Zkeacms for. NET core uses EntityFramework as a database access. Database-related configuration entityframeworkconfigure
public class entityframeworkconfigure:ionconfiguring{public void Onconfiguring (Dbcontextoptionsbuilder Optionsbuilder) { optionsbuilder.usesqlserver (Easy.Builder.Configuration.GetSection ("ConnectionStrings ") [" defaultconnection "]);} }
The configuration of the entity can still be written directly on the corresponding class or attribute. If you want to use the Entity Framework Fluent API, create a class and inherit from Ionmodelcreating
Class entityframeworkmodelcreating:ionmodelcreating{public void onmodelcreating (ModelBuilder ModelBuilder) { modelbuilder.entity<layouthtml> (). Ignore (M = m.description). Ignore (M = m.status). Ignore (M = m.title);} }
Theme
Zkeacms uses the BOOTSTRAP3 as the basis, using less, to negotiate a number of variables, such as margin, color, background, etc., can be "compiled" by simply modifying the variable can be a theme.
Or you can use the theme of an already existing Bootstrap3 as a basis and quickly create a theme.
At last
There are a lot more about ZKEACMS, if you are interested, please join us.
Zkeacms for. NET core is about making websites easier and faster. The revision and revision of the page has also become easier and more convenient.
"Recommended"
1.. Net Core Graphics Verification Code
2.. NET core configuration file loading with di injection configuration data
3.. NET Core CLI Tool documentation Dotnet-publish
4. Sharing. NET MVC using forms to validate instance code
5. How do I make HTTP requests under. NET Core?
6. Example tutorials for running zkeacms on CentOS