In-depth analysis of ZKEACMS for. Net Core, zkeacmscore

Source: Internet
Author: User

In-depth analysis of ZKEACMS for. Net Core, zkeacmscore

Introduction to ZKEACMS
ZKEACMS. Core is an open-source CMS developed Based on. Net Core MVC. ZKEACMS allows you to freely plan the page layout, use visual editing to design what you see is what you get, and drag and drop the page to add content.

ZKEACMS uses plug-in design and module separation to enrich CMS functions through horizontal scaling.

Responsive Design

ZKEACMS uses the Bootstrap3 raster system to implement responsive design, so as to achieve normal access on different devices. At the same time, we stand on the shoulders of the Bootstrap giant and have a wealth of theme resources to use.

Simple demonstration

Next let's take a look at the program design and principles

Project Structure

  • EasyFrameWork underlying framework
  • Zkeacms cms Core
  • ZKEACMS. Article plugin
  • ZKEACMS. Product plugin
  • ZKEACMS. SectionWidget template component plugin
  • ZKEACMS. WebHost

Principle-access request process

RoutingIt plays a key role in ZKEACMS. The access process is determined by the routing priority. If a matched route is found, the Controller-> Action-> View corresponding to the route is prioritized. If no matching route exists, the "full capture" route with the lowest priority is used to process users' requests, finally, a response is returned.

The "Full capture" route with the lowest priority is used to process pages created by users. When a request comes in, go to the database to check whether the page exists. If the page does not exist, 404 is returned. Find all the components and content on the page, and call the "Display" method of each component to obtain the corresponding "ViewModel" and "View ", the page layout is displayed.

ZKEACMS request Flowchart

Driver 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].OrderBy(m => m.Widget.Position).ThenBy(m => m.Widget.WidgetName)){  <div style="@widgetPart.Widget.CustomStyle">    <div class="widget @widgetPart.Widget.CustomClass">      @if (widgetPart.Widget.Title.IsNotNullAndWhiteSpace())      {        <div class="panel panel-default">          <div class="panel-heading">            @widgetPart.Widget.Title          </div>          <div class="panel-body">            @Html.DisPlayWidget(widgetPart)          </div>        </div>      }      else      {        @Html.DisPlayWidget(widgetPart)      }    </div>  </div>}

Plug-in "most critical" class PluginBase

Each plug-in/module must have a class inherited from PluginBase, which serves as the entry to plug-in Initialization. during startup, the program will load these classes and perform some key initialization work.

Public abstract class PluginBase: ResourceManager, IRouteRegister, IPluginStartup {public abstract IEnumerable <RouteDescriptor> RegistRoute (); // enter public abstract IEnumerable <AdminMenu> AdminMenu () for the route required to register the plug-in (); // The Menu provided by the plug-in on the backend can return an empty public abstract IEnumerable <PermissionDescriptor> RegistPermission (); // you can register the permission of the plug-in public abstract IEnumerable <Type> WidgetServiceTypes (); // return the public abstract void ConfigureServices (IServiceCollection serviceCollection) of all components provided in the plug-in; // IOC registers the corresponding interface and implements public virtual void InitPlug (); // initialize the plug-in and call this method when the program starts}

For specific implementation, refer to Article plug-in ArticlePlug. cs or product plug-in ProductPlug. cs.

Load plug-in 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 consists of many components. Each component can contain different Content, such as text, images, and videos. The Content is determined by the component, the rendering method is determined by the component template (View.

Shows the relationship and rendering method:

Entity Enity

Each component corresponds to an entity used to store information related to the component. The object must inherit from the BasicWidget class.

For example, the entity class of HTML components:

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

The object class uses the metadata configuration [ViewConfigure (typeof (HtmlWidgetMetaData)], and controls the display of form pages and list pages through simple settings. If it is set to text or drop-down box; required, verification of length, etc.

The implementation method here is to add a new ModelMetadataDetailsProviderProvider to MVC. The role of this Provider is to capture the configuration information of these metadata and submit it to MVC.

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

Service

WidgetService is a bridge between data and templates. It captures data and sends it to the page template through the Service. The Service must inherit from WidgetService <WidgetBase, CMSDbContext>. If the business is complex, override the corresponding methods of the base class.

For example, the Service of the HTML component:

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

View object ViewModel

ViewModel is not required. When an object (Entity) is uploaded to a view as a ViewModel, you can create a new ViewModel and pass the ViewModel over. This will require rewriting of the Display method.

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

View/template Widget. cshtml

A Template is used to display the content. The Service collects the "Model" required by the template, and the template displays them.

Dynamically compile distributed templates

Plug-in resources are all under their respective folders. The default view engine cannot find these views and compile them. MVC4 ZKEACMS is implemented by rewriting ViewEngine .. Net core mvc can be more convenient to implement, implement your own ConfigureOptions <RazorViewEngineOptions>, and then use dependency injection.

public class PluginRazorViewEngineOptionsSetup : ConfigureOptions<RazorViewEngineOptions>{  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);  }}

You may wonder why the above Code should be divided into development environments. This is because the folder directory structure is different during ZKEACMS release and development. In order to facilitate development, special handling is added to the development environment. Next, inject this Configuration:

Services. TryAddEnumerable (ServiceDescriptor. Transient <IConfigureOptions <RazorViewEngineOptions>, PluginRazorViewEngineOptionsSetup> ());

EntityFrameWork

ZKEACMS for. net core uses EntityFrameWork for database access. Database-related configuration EntityFrameWorkConfigure

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

The Entity configuration can still be directly written in 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);  }}

Topic

ZKEACMS uses Bootstrap3 as the basis and uses LESS to determine many variables, such as margins, colors, and backgrounds, you can simply modify the variables to "compile" a topic.

Alternatively, you can directly use the existing Bootstrap3 topic as the basis, and then quickly create a topic.

Last

There are many other things about ZKEACMS. If you are interested, please join us.

ZKEACMS for. net core is to make website creation easier and faster. The modification and revision of the page also become easier and more convenient.

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.