日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

ZKEACMS for .Net Core 深度解析

發布時間:2023/12/4 asp.net 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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",最后按照頁面的布局來顯示。

驅動頁面組件:



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)) { ???? <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> }


插件“最關鍵”的類?PluginBase

每一個插件/模塊都必需要一個類繼承PluginBase,作為插件初始化的入口,程序在啟動的時候,會加載這些類并作一些關鍵的初始化工作。



public abstract class PluginBase : ResourceManager, IRouteRegister, IPluginStartup { ???? public abstract IEnumerable<RouteDescriptor> RegistRoute(); //注冊該插件所需要的路由 可返回空 ???? public abstract IEnumerable<AdminMenu> AdminMenu(); //插件在后端提供的菜單 可返回空 ???? public abstract IEnumerable<PermissionDescriptor> RegistPermission(); //注冊插件的權限 ???? public abstract IEnumerable<Type> 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<HtmlWidget> { ???? protected override void ViewConfigure() ???? { ???????? base .ViewConfigure(); ???????? ViewConfig(m => m.HTML).AsTextArea().AddClass( "html" ).Order(NextOrder()); ???? } }


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

這里實現方式是向MVC里面添加一個新的ModelMetadataDetailsProviderProvider,這個Provider的作用就是抓取這些元數據的配置信息并提交給MVC。



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


服務 Service

WidgetService 是數據與模板的橋梁,通過Service抓取數據并送給頁面模板。 Service 必需繼承自?WidgetService<WidgetBase, CMSDbContext>。如果業務復雜,則重寫(override)基類的對應方法來實現。

例如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; ???????? } ???? } }


視圖實體 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 可以更方便實現了,實現自己的?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); ???? } }

看上面代碼您可能會產生疑惑,為什么要分開發環境。這是因為ZKEACMS發布和開發的時候的文件夾目錄結構不同造成的。為了方便開發,所以加入了開發環境的特別處理。接下來就是注入這個配置:


services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, 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<LayoutHtml>().Ignore(m => m.Description).Ignore(m => m.Status).Ignore(m => m.Title); ???? } }

  

主題

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

或者也可以直接使用已經有的Bootstrap3的主題作為基礎,然后快速創建主題。

?

最后

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

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

原文地址:http://www.cnblogs.com/seriawei/p/6540235.html


.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

贊賞

人贊賞

總結

以上是生活随笔為你收集整理的ZKEACMS for .Net Core 深度解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。