天天看點

一個能夠根據對象或者類型自動生成頁面元件的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);
        }
    }
}