ASP.NET CORE 利用 object 类型数据处理 json 格式的数据

这两天遇到一个需求,需要处理动态类型数据,这个数据,既要能在web上传输,页面上展示,又能持久化到数据库。我首先想到的,就是用json字符串来处理,拿到json数据后,再在不同的上下文环境中去解析。

为了简单,我把类型定义为了object,但这种类型不能被EF序列化,所以我们需要做一些额外的转换工作。

思路也很简单,就是利用newtonsoft json来序列化与反序列化。

首先我们看看模型定义

public Class Book
{
    [Key]
    public string Id { get; set }
    
    public string Name { get; set; }
    
    [NotMapped]
    public object Config { get; set; }
}

然后通过 Fluent Api 来实现

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Book>()
                .Property(e => e.Config)
                .HasConversion(
                    v => JsonConvert.SerializeObject(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }),
                    v => JsonConvert.DeserializeObject(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore })
                );
        }

以上,就完成了实体模型中带动态类型数据的持久化。

那么接下来就是如何在页面上显示,以及从页面接收数据了。 

微软提供了一套完整的模型绑定库,可以应对绝大多数数据到模型的绑定,一般来说,我们是不用自己处理的,但是由于object没有对应的处理,所以我们需要自己写一个自定义模型绑定库。

首先,实现IModelBinder接口,处理object类型的绑定工作

    public class MyBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

            var modelName = bindingContext.ModelName;

            // 尝试按名称获取数据
            // 如果在应用 ModelBinder 的时候,指定了 Name ,那么这个地方的 modelName
            // 就是 Name.属性名 这样的形式
            var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

            if (valueProviderResult == ValueProviderResult.None)
            {
                return Task.CompletedTask;
            }

            // 拿到数据后,用 newtonsoft json 处理
            var value = valueProviderResult.FirstValue;
            try
            {
                var result = JsonConvert.DeserializeObject(value);
                bindingContext.Result = ModelBindingResult.Success(result);
            }
            catch
            {
                // 加上这句,可以将错误的json字符串重新展示到页面上
                bindingContext.ModelState.SetModelValue(modelName, result, value);
                bindingContext.ModelState.TryAddModelError(modelName, "无效的json数据");
            }
            return Task.CompletedTask;
        }
    }

接下来定义一个Provider,并将其添加到DI中

    public class MyBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (null == context)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (context.Metadata.ModelType == typeof(object))
            {
                return new BinderTypeModelBinder(typeof(MyBinder));
            }

            return null;
        }
    }

    // 添加到 DI 中
       services.AddControllersWithViews(options =>
       {
           options.ModelBinderProviders.Insert(0, new MyBinderProvider());
       })
       // 替换System.Text.Json
        .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
            });

将定义好的 ModelBinder 应用到对应的属性上

public Class Book
{
    [Key]
    public string Id { get; set }
    
    public string Name { get; set; }
    
    [NotMapped]
    [ModelBinder(BinderType = typeof(MyBinder))]
    public object Config { get; set; }
}

最后就是如何在页面上显示了,方法很简单,就是直接利用newtonsoft json显示字符串,那种按模板自动生成的方法有点难度,我还搞不定^_^。

    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Id)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Name)
                </td>
                <td>
                    @Newtonsoft.Json.JsonConvert.SerializeObject(item.Config)
                </td>
            </tr>
        }
    </tbody>

编辑页面直接用模板生成的话,不用什么特殊处理,已经可以正确显示了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值