天天看点

一个能够根据对象或者类型自动生成页面组件的Blazor WebAssembly应用

一个能够根据对象或者类型自动生成页面组件的Blazor WebAssembly应用

  • Github ma-hua/blazor-auto
  • 基于Ant.Design-Blazor组件库
  • 需要dotnet-sdk v3.1.6及以上
    一个能够根据对象或者类型自动生成页面组件的Blazor WebAssembly应用
    一个能够根据对象或者类型自动生成页面组件的Blazor WebAssembly应用

需求描述

  • 优惠活动相关业务需求常常变更频繁,基于Sql Server中json存储技术,对公司原先的体系展开重构。将活动规则划分为多个大类,每一类的对象不再以字段对应的方式存储在数据库中,而是以Json的方式存储,这样需要增加或者删除某些字段的时候,只需要修改相应实体,而不必修改数据库设计。
  • 之后也对活动管理系统提出新的要求,即能够根据最新发布的包含活动实体的Nuget包,自动生成规则设置页面。基于html+js的前端技术或许并不能做到这一点,因此提出了使用Blazor技术+C#,来完成这一目标:根据对象或者类型自动生成页面组件,并且完成数据绑定,来完成新增或编辑等操作。

项目介绍

本项目仅用于学习参考,本人才疏学浅,不足之处还请多多指教

  • Blazor.Auto 包含反射与字段描述等相关工具
  • Blazor.Auto.Components 根据字段描述符来自动完成数据绑定的组件库(基于Ant.Design-Blazor)

获取字段主要信息

  • 字段描述符 FieldDescriptor   包含字段名,字段描述,IsRequired,值描述符
  • 值描述符 ValueDescriptor  包含值的类型,值,下拉框列表

字段组件:输入框 日期选择器 开关 列表选择器

  • 根据值类型,输入框分为:字符串输入框,整数输入框,小数输入框
  • 开关分为可控开关和非空开关(bool?和bool两种)
  • 列表选择器以模态框的形式展示,分为单选列表和多选列表

  字段组件均继承自父组件BaseComponent,父组件中包含虚方法ValueChangedCallBack,以链接绑定的方式来完成参数绑定。

列表选择器

一个能够根据对象或者类型自动生成页面组件的Blazor WebAssembly应用

  列表选择器通常对应类型为List<T>的字段,选择器内容的获取较为关键。假如泛型类型是枚举的话,可以直接通过反射技术拿到选择列表。

  但是如果需要通过查询某些接口来获取选择列表的话,需要实现ISelectItemProvider接口。并且为其实现类指定一个Keyword,在字段上使用特性[SelectDescriptionAttribute]标注同样的Keyword。那么在生成组件时,可以通过Keyword从IOC容器中获取SelectItemProvider,并调用实现方法,来获取选择项。

通常需要使用Named的方式注入ISelectItemProvider实现类,在本项目中,我使用的是Autofac容器。

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
//注入ISelectItemProvider实现类
builder.ConfigureContainer(new AutofacServiceProviderFactory(cfg =>
    {
        cfg.RegisterAssemblyTypes(Assembly.GetExecutingAssembly());
        cfg.RegisterType<StoreGroupProvider>().Named<ISelectItemProvider>(StoreGroupProvider.Keyword).SingleInstance();
        cfg.RegisterType<PriceGroupProvider>().Named<ISelectItemProvider>(PriceGroupProvider.Keyword).SingleInstance();
    }));
           

在列表选择器组件中,根据字段的Keyword从IOC容器中获取选择列表项

[Inject]
public IComponentContext ComponentContext { get; set; }

protected override async Task OnParametersSetAsync()
{
    if (!ValueComponentExtension.IsEnumSelect(Descriptor.Value) && !string.IsNullOrWhiteSpace(Keyword))
    {
        try
        {
            Items = await ComponentContext.ResolveNamed<ISelectItemProvider>(Keyword).GetSelectItemAsync();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}