欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ZKEACMS for .Net Core深度解析

 更新時(shí)間:2017年05月24日 12:40:55   作者:ZKEASOFT  
ZKEACMS.Core 是基于 .Net Core MVC 開發(fā)的開源CMS,這篇文章主要為大家深度解析了ZKEACMS for .Net Core,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

ZKEACMS 簡介
ZKEACMS.Core 是基于 .Net Core MVC 開發(fā)的開源CMS。ZKEACMS可以讓用戶自由規(guī)劃頁面布局,使用可視化編輯設(shè)計(jì)“所見即所得”,直接在頁面上進(jìn)行拖放添加內(nèi)容。

ZKEACMS使用插件式設(shè)計(jì),模塊分離,通過橫向擴(kuò)展來豐富CMS的功能。

響應(yīng)式設(shè)計(jì)

ZKEACMS使用Bootstrap3的柵格系統(tǒng)來實(shí)現(xiàn)響應(yīng)式設(shè)計(jì),從而實(shí)現(xiàn)在不同的設(shè)備上都可以正常訪問。同時(shí)站在Bootstrap巨人的肩膀上,有豐富的主題資源可以使用。

簡單演示

接下來看看程序設(shè)計(jì)及原理

項(xiàng)目結(jié)構(gòu)

  • EasyFrameWork  底層框架
  • ZKEACMS   CMS核心
  • ZKEACMS.Article   文章插件
  • ZKEACMS.Product  產(chǎn)品插件
  • ZKEACMS.SectionWidget  模板組件插件
  • ZKEACMS.WebHost 

原理 - 訪問請(qǐng)求流程

路由在ZKEACMS里面起到了關(guān)鍵性的作用,通過路由的優(yōu)先級(jí)來決定訪問的流程走向,如果找到匹配的路由,則優(yōu)先走該路由對(duì)應(yīng)的 Controller -> Action -> View,如果沒有匹配的路由,則走路由優(yōu)先權(quán)最低的“全捕捉”路由來處理用戶的請(qǐng)求,最后返回響應(yīng)。

優(yōu)先級(jí)最低的“全捕捉”路由是用來處理用戶自行創(chuàng)建的頁面的。當(dāng)請(qǐng)求進(jìn)來時(shí),先去數(shù)據(jù)庫中查找是否存在該頁面,不存在則返回404。找到頁面之后,再找出這個(gè)頁面所有的組件、內(nèi)容,然后統(tǒng)一調(diào)用各個(gè)組件的“Display"方法來來得到對(duì)應(yīng)的“ViewModel"和視圖"View",最后按照頁面的布局來顯示。

ZKEACMS 請(qǐng)求流程圖

驅(qū)動(dòng)頁面組件:

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();
  }
});

頁面呈現(xiàn):

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>
}

插件“最關(guān)鍵”的類 PluginBase

每一個(gè)插件/模塊都必需要一個(gè)類繼承PluginBase,作為插件初始化的入口,程序在啟動(dòng)的時(shí)候,會(huì)加載這些類并作一些關(guān)鍵的初始化工作。

public abstract class PluginBase : ResourceManager, IRouteRegister, IPluginStartup
{
  public abstract IEnumerable<RouteDescriptor> RegistRoute(); //注冊(cè)該插件所需要的路由 可返回空
  public abstract IEnumerable<AdminMenu> AdminMenu(); //插件在后端提供的菜單 可返回空
  public abstract IEnumerable<PermissionDescriptor> RegistPermission(); //注冊(cè)插件的權(quán)限
  public abstract IEnumerable<Type> WidgetServiceTypes(); //返回該插件中提供的所有組件的類型
  public abstract void ConfigureServices(IServiceCollection serviceCollection); //IOC 注冊(cè)對(duì)應(yīng)的接口與實(shí)現(xiàn)
  public virtual void InitPlug(); //初始化插件,在程序啟動(dòng)時(shí)調(diào)用該方法
}

具體實(shí)現(xiàn)可以參考“文章”插件 ArticlePlug.cs 或者“產(chǎn)品”插件 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);      
}

組件構(gòu)成

一個(gè)頁面,由許多的組件構(gòu)成,每個(gè)組件都可以包含不同的內(nèi)容(Content),像文字,圖片,視頻等,內(nèi)容由組件決定,呈現(xiàn)方式由組件的模板(View)決定。

關(guān)系與呈現(xiàn)方式大致如下圖所示:

實(shí)體 Enity

每個(gè)組件都會(huì)對(duì)應(yīng)一個(gè)實(shí)體,用于存儲(chǔ)與該組件相關(guān)的一些信息。實(shí)體必需繼承于 BasicWidget 類。

例如HTML組件的實(shí)體類:

[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());
  }
}

實(shí)體類里面使用到了元數(shù)據(jù)配置[ViewConfigure(typeof(HtmlWidgetMetaData))],通過簡單的設(shè)置來控制表單頁面、列表頁面的顯示。假如設(shè)置為文本或下拉框;必填,長度等的驗(yàn)證。

這里實(shí)現(xiàn)方式是向MVC里面添加一個(gè)新的ModelMetadataDetailsProviderProvider,這個(gè)Provider的作用就是抓取這些元數(shù)據(jù)的配置信息并提交給MVC。

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

服務(wù) Service

WidgetService 是數(shù)據(jù)與模板的橋梁,通過Service抓取數(shù)據(jù)并送給頁面模板。 Service 必需繼承自 WidgetService<WidgetBase, CMSDbContext>。如果業(yè)務(wù)復(fù)雜,則重寫(override)基類的對(duì)應(yīng)方法來實(shí)現(xiàn)。

例如HTML組件的Service:

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

視圖實(shí)體 ViewModel

ViewModel 不是必需的,當(dāng)實(shí)體(Entity)作為ViewModel傳到視圖不足以滿足要求時(shí),可以新建一個(gè)ViewModel,并將這個(gè)ViewModel傳過去,這將要求重寫 Display 方法

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

視圖 / 模板 Widget.cshtml

模板 (Template) 用于顯示內(nèi)容。通過了Service收集到了模板所要的“Model”,最后模板把它們顯示出來。

動(dòng)態(tài)編譯分散的模板

插件的資源都在各自的文件夾下面,默認(rèn)的視圖引擎(ViewEngine)并不能找到這些視圖并進(jìn)行編譯。MVC4版本的ZKEACMS是通過重寫了ViewEngine來得以實(shí)現(xiàn)。.net core mvc 可以更方便實(shí)現(xiàn)了,實(shí)現(xiàn)自己的 ConfigureOptions<RazorViewEngineOptions> ,然后通過依賴注入就行。

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);
  }
}

看上面代碼您可能會(huì)產(chǎn)生疑惑,為什么要分開發(fā)環(huán)境。這是因?yàn)閆KEACMS發(fā)布和開發(fā)的時(shí)候的文件夾目錄結(jié)構(gòu)不同造成的。為了方便開發(fā),所以加入了開發(fā)環(huán)境的特別處理。接下來就是注入這個(gè)配置:

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

EntityFrameWork

ZKEACMS for .net core 使用EntityFrameWork作為數(shù)據(jù)庫訪問。數(shù)據(jù)庫相關(guān)配置 EntityFrameWorkConfigure

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

對(duì)Entity的配置依然可以直接寫在對(duì)應(yīng)的類或?qū)傩陨?。如果想使?Entity Framework Fluent API,那么請(qǐng)創(chuàng)建一個(gè)類,并繼承自 IOnModelCreating

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

主題

ZKEACMS 使用Bootstrap3作為基礎(chǔ),使用LESS,定議了許多的變量,像邊距,顏色,背景等等,可以通過簡單的修改變量就能“編譯”出一個(gè)自己的主題。

或者也可以直接使用已經(jīng)有的Bootstrap3的主題作為基礎(chǔ),然后快速創(chuàng)建主題。

最后

關(guān)于ZKEACMS還有很多,如果您也感興趣,歡迎加入我們。

ZKEACMS for .net core 就是要讓建網(wǎng)站變得更簡單,快速。頁面的修改與改版也變得更輕松,便捷。

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • asp.net通過消息隊(duì)列處理高并發(fā)請(qǐng)求(以搶小米手機(jī)為例)

    asp.net通過消息隊(duì)列處理高并發(fā)請(qǐng)求(以搶小米手機(jī)為例)

    這篇文章主要介紹了asp.net通過消息隊(duì)列處理高并發(fā)請(qǐng)求(以搶小米手機(jī)為例),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • 測(cè)試控制臺(tái)使用方法

    測(cè)試控制臺(tái)使用方法

    如何使用測(cè)試控制臺(tái),需要的朋友可以參考下。
    2009-11-11
  • 淺談.Net Core 認(rèn)證系統(tǒng)源碼解析

    淺談.Net Core 認(rèn)證系統(tǒng)源碼解析

    這篇文章主要介紹了淺談.Net Core 認(rèn)證系統(tǒng)源碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • asp.net實(shí)現(xiàn)訪問局域網(wǎng)共享目錄下文件的解決方法

    asp.net實(shí)現(xiàn)訪問局域網(wǎng)共享目錄下文件的解決方法

    這篇文章主要介紹了asp.net實(shí)現(xiàn)訪問局域網(wǎng)共享目錄下文件的解決方法,需要的朋友可以參考下
    2014-07-07
  • asp.net Context.Handler 頁面間傳值方法

    asp.net Context.Handler 頁面間傳值方法

    很有用的頁面間傳值方法(Context.Handler),使用說明
    2008-08-08
  • .Net Core WebApi的簡單創(chuàng)建以及使用方法

    .Net Core WebApi的簡單創(chuàng)建以及使用方法

    這篇文章主要給大家介紹了關(guān)于.Net Core WebApi的簡單創(chuàng)建以及使用方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用.Net Core WebApi具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • .Net?7.0實(shí)現(xiàn)支付寶退款和結(jié)果查詢接口

    .Net?7.0實(shí)現(xiàn)支付寶退款和結(jié)果查詢接口

    支付寶對(duì) .Net 的支持還是比較充分的,在每個(gè)接口文檔中都有關(guān)于 C# 語言的示例,這樣就大大降低了對(duì)接的難度,很容易上手,這篇文章主要介紹了支付寶退款和結(jié)果查詢接口簡單實(shí)現(xiàn)(.Net?7.0),需要的朋友可以參考下
    2024-07-07
  • ASP.NET實(shí)現(xiàn)圖形驗(yàn)證碼功能

    ASP.NET實(shí)現(xiàn)圖形驗(yàn)證碼功能

    ASP.NET 實(shí)現(xiàn)圖形驗(yàn)證碼能夠增強(qiáng)網(wǎng)站安全性,防止機(jī)器人攻擊,本文介紹了如何使用 C# 和 ASP.NET 創(chuàng)建一個(gè)簡單而有效的圖形驗(yàn)證碼系統(tǒng),包括生成隨機(jī)驗(yàn)證碼、繪制驗(yàn)證碼圖像以及將圖像輸出到客戶端等步驟,感興趣的朋友一起看看吧
    2024-03-03
  • asp.net BackgroundWorker之在后臺(tái)下載文件

    asp.net BackgroundWorker之在后臺(tái)下載文件

    下載文件是常見任務(wù),通常情況下,最好以單獨(dú)的線程來運(yùn)行這項(xiàng)可能很耗時(shí)的操作。使用 BackgroundWorker 組件可以用非常少的代碼完成此任務(wù)
    2011-12-12
  • asp.net結(jié)合aspnetpager使用SQL2005的存儲(chǔ)過程分頁

    asp.net結(jié)合aspnetpager使用SQL2005的存儲(chǔ)過程分頁

    項(xiàng)目中用到了,同事阿春寫了例子,并在實(shí)際項(xiàng)目中使用了,記錄下。感謝春哥的無私奉獻(xiàn)。
    2009-07-07

最新評(píng)論