緊接着上面的內容,咱們繼續看下動態模型頁面交互實現方式,內容以下:html
1,如何實現動態表單數據庫
2,如何接收表單數據並綁定到動態模型上json
1、如何實現動態表單mvc
因爲模型信息都是後臺自定義配置的,並非固定不變的結構,因此沒有辦法直接在頁面上寫出對應的表單數據,而須要經過解析模型的結構,動態的生成對應的表單。在說具體實現方法前,咱們先來看下咱們想要達到的效果。ide
Html.Raw(FormGenerator.Generate(Model,Properties))ui
FormGenerator.Generate包含兩個參數,一個動態模型對象,一個須要呈現的屬性列表,方法返回最終生成的form表單html,而後經過Html.Raw呈現到頁面上。orm
下面介紹一下實現過程,首先定義一個IDynamicFormGenerator接口,代碼以下:htm
public interface IDynamicFormGenerator { string Generate(object obj, IEnumerable<RuntimeModelMeta.ModelPropertyMeta> properties); }
接口中只包含一個方法,就是咱們上面實例代碼用到的方法。接口實現邏輯上很簡單,只須要循環每個屬性,根據屬性的特色生成一個表單,並把對象數據綁定到表單上,好比屬性若是是bool類型,咱們能夠生成一個checkbox,而後根據obj對應的屬性值是true仍是false,進而設置checkbox的選中狀態。具體實現代碼:對象
public class DynamicFormGenerator : IDynamicFormGenerator { public string Generate(object obj, IEnumerable<RuntimeModelMeta.ModelPropertyMeta> properties) { StringBuilder builder = new StringBuilder(); //循環屬性集合 foreach (var item in properties) { //TODO:根據屬性信息生成表單並綁定數據 string fieldhtml=""; //把生成的html加入到stringbulder中 builder.Append(fieldhtml); } //返回最終的html結果 return builder.ToString(); } }
這個方法裏最主要的部分就是如何根據屬性的類型生成對應的表單,就是如何獲得上面的fieldhtml?咱們再來看下前面定義的RuntimeModelMetablog
public class RuntimeModelMeta { public int ModelId { get; set; } public string ModelName { get; set; }//模型名稱 public string ClassName { get; set; }//類名稱 public string Properties{get;set;}//屬性集合json序列化結果 public class ModelPropertyMeta { public string Name { get; set; }//對應的中文名稱 public string PropertyName { get; set; } //類屬性名稱 public int Length { get; set; }//數據長度,主要用於string類型 public bool IsRequired { get; set; }//是否必須輸入,用於數據驗證 public string ValueType { get; set; }//數據類型,能夠是字符串,日期,bool等 } }
ModelPropertyMeta裏包含了一個ValueType信息,就是當前屬性的數據類型,那咱們是否能夠根據這個來肯定生成的表單形式?答案是否認的,由於即便是同一種類型也會呈現不一樣的表單,好比都是字符串,可能有的要求呈現下拉框,有的要求呈現複選框,因此只依靠ValueType還不夠,咱們能夠給RuntimeModelMeta增長一個屬性,專門用於設置表單形式的,改造後代碼以下:
public class RuntimeModelMeta { public int ModelId { get; set; } public string ModelName { get; set; }//模型名稱 public string ClassName { get; set; }//類名稱 public string Properties{get;set;}//屬性集合json序列化結果 public class ModelPropertyMeta { public string Name { get; set; }//對應的中文名稱 public string PropertyName { get; set; } //類屬性名稱 public int Length { get; set; }//數據長度,主要用於string類型 public bool IsRequired { get; set; }//是否必須輸入,用於數據驗證 public string ValueType { get; set; }//數據類型,能夠是字符串,日期,bool等 public string ShowType { get; set; }//表單形式 } }
有了ShowType,咱們就能夠根據設置的類型來生成對應的表單。首先先定義個表單生成器接口,代碼以下:
public interface IDynamicFormFieldGenerator { //根據傳遞的屬性及對象,生成表單 string Generate(object obj, RuntimeModelMeta.ModelPropertyMeta meta,bool onlyform=false); //這個表示當前的實現是針對哪種ShowType的 string ForType { get; } }
而後針對每一種ShowType實現一個生成器,好比針對checkbox類型的ShowType,咱們實現一個生成器,代碼以下:
public class CheckboxFieldGenerator : IDynamicFormFieldGenerator { public string ForType { get { return "checkbox"; } } public string Generate(object obj, RuntimeModelMeta.ModelPropertyMeta meta,bool onlyform=false) { //把動態對象轉換成一個DynamicEntity,爲的是後面獲取數據方便,由於DynamicEntity支持經過索引獲取屬性數據 DynamicEntity entity = obj as DynamicEntity; if (obj == null) { throw new NullReferenceException("DynamicEntity"); } //經過entity[meta.PropertyName]獲取到屬性數據 return string.Format("<input id='{1}' name='{1}' type='checkbox' value='{0}'/>", entity[meta.PropertyName]?.ToString(), meta.PropertyName); } }
其餘ShowType類型,能夠根據本身系統的須要,直接實現便可,這裏再也不一一列舉了。
有了表單構造器,咱們再回頭完善下DynamicFormGenerator,在DynamicFormGenerator中,咱們須要根據屬性的ShowType信息獲取到IDynamicFormFieldGenerator,咱們能夠定義一個DynamicFormFieldGeneratorProvider,方便咱們獲得咱們所須要的IDynamicFormFieldGenerator,具體實現代碼:
//提供者接口定義 public interface IDynamicFormFieldGeneratorProvider { IDynamicFormFieldGenerator Get(string type); }
public class DynamicFormFieldGeneratorProvider: IDynamicFormFieldGeneratorProvider { private readonly IHttpContextAccessor _httpContextAccessor; private IEnumerable<IDynamicFormFieldGenerator> _generators; public DynamicFormFieldGeneratorProvider(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public IDynamicFormFieldGenerator Get(string type) { //經過依賴注入,獲取到構造器實現集合,因此咱們須要把全部的構造器實現都註冊到ServiceCollection中 if (_generators==null) { _generators= _httpContextAccessor.HttpContext.RequestServices.GetServices<IDynamicFormFieldGenerator>(); } if (_generators==null) { throw new NotSupportedException("IDynamicFormFieldGenerator"); } //根據type找到第一個符合條件的構造器,並返回 IDynamicFormFieldGenerator g = _generators.FirstOrDefault(m => m.ForType == type); if (g==null) { throw new NotSupportedException("not supproted for " + type + "'s form field generator"); } return g; } }
條件都準備好了,直接完善DynamicFormGenerator,最終代碼以下:
public class DynamicFormGenerator : IDynamicFormGenerator { private readonly IDynamicFormFieldGeneratorProvider _fieldGeneratorProvider; public DynamicFormGenerator(IDynamicFormFieldGeneratorProvider provider) { _fieldGeneratorProvider = provider; } public string Generate(object obj, IEnumerable<RuntimeModelMeta.ModelPropertyMeta> properties) { StringBuilder builder = new StringBuilder(); foreach (var item in properties) { //根據showtype獲取表單構造器 IDynamicFormFieldGenerator fieldGenerator = _fieldGeneratorProvider.Get(item.ShowType); builder.Append(fieldGenerator.Generate(obj,item)); } return builder.ToString(); } }
到此表單就能夠呈現到界面上了。
2、如何接收表單數據並綁定到動態模型上
在mvc中提供了數據綁定機制,能夠快速的把表單數據綁定到對象上,可是如今咱們的對象是動態的,那又該如何應對?
在表單操做中,當前對應的模型咱們確定知道,因此能夠藉助前面介紹的內容,咱們先獲得一個動態模型對象,具體操做以下:
//根據模型id獲取到type Type modelType = _runtimeModelProvider.GetType(modelid); //實例化 object obj = Activator.CreateInstance(modelType);
咱們如今須要解決的是,如何把動態表單提交的數據綁定到obj的屬性上。方法也很簡單,在mvc中給咱們提供了很好的支持,方法就是TryUpdateModelAsync,藉助這個方法,就能夠很方便的把數據綁定到obj上,具體調用實例
TryUpdateModelAsync(obj, modelType, "")
obj就是上面實例化的對象,modelType就是動態模型對應的Type信息,有了數據後,後面就是經過ef完成數據庫同步的事了,好比增長
ShopDbContext.Add(obj); ShopDbContext.SaveChanges();
全部代碼仍是須要你們本身完善補充,若是有不足之處,歡迎你們可以批評指正。