紧接着上面的内容,咱们继续看下动态模型页面交互实现方式,内容以下: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();
全部代码仍是须要你们本身完善补充,若是有不足之处,欢迎你们可以批评指正。