增量生成器简化Blazor内存中状态容器服务

AutoPageStateContainerGenerator

介绍

Blazor 的组件数据(或者说组件的属性),如果没有做特殊处理的话,在路由切换的时候就会丢失当前页面上的数据,不管是 Server 还是 WebAssembly,官方文档的推荐做法都是将数据抽出来当作一个服务,在页面中注入使用(内存中状态容器服务),而使用生成器,就可以很方便的完成这些功能,自动为 Razor 组件生成相应的数据容器。

使用

dotnet add package AutoPageStateContainerGenerator --version 0.0.5

StateContainerAttribute

在需要生成数据容器的组件上标注。

属性

名称 类型 说明
Lifetime Microsoft.Extensions.DependencyInjection.ServiceLifetime 指定容器服务注入的生命周期
Name string? 设置容器名称(用法)
Implements Type? 设置容器自定义实现类型(用法)

SaveStateAttribute

标注需要保存的字段。

AddStateContainers

注入生成的数据容器

父类中使用

必须使用virtual属性

public partial class CounterParent : ComponentBase
{
    [SaveState]
    public virtual string? Type { get; set; } = "CounterParent";

    public void CheckType()
    {
        Console.WriteLine(Type);
    }
}

在其他地方使用内存数据容器

1. 直接从Ioc容器中获取,生成的类型为类型的全名StateContainer

2. 使用IStateContainerManager

设计目的:如果使用第一种方式,主要问题是类型名称太长,并且产生了依赖,所以就出现了IStateContainerManager

Counter为例

public interface ICounter
{
    // 假如我想在其他地方通过ICounter使用数据容器中的Name1
    string? Name1 { get; set; }
}
[StateContainer(Name = "Counter", Implements = typeof(ICounter))]
public partial class Counter
{
    [SaveState]
    public partial string? Name1 { get; set; }

    [SaveState]
    public partial int Index { get; set; }

    [SaveState(Init = "[]")]
    public partial List<string> Values { get; set; }
}

Home组件中使用Counter组件的数据容器

// 注入IStateContainerManager
[Inject, NotNull] IStateContainerManager? ContainerManager { get; set; }
ICounter? counter;
protected override void OnInitialized()
{
    base.OnInitialized();
    // 从IStateContainerManager中获取ICounter
    counter = ContainerManager.GetStateContainer<ICounter>("Counter");
}

示例

Counter组件,不能直接在razor文件中添加该Attribute。

使用字段

[StateContainer(Name = "Counter", Implements = typeof(ICounter))]
public partial class Counter
{
    [SaveState]
    private string? name1;

    [SaveState]
    private int index;

    [SaveState]
    private List<string> values = [];

    public string? Name2 { get; set; }
}

使用分部属性

[StateContainer(Name = "Counter", Implements = typeof(ICounter))]
public partial class Counter
{
    [SaveState]
    public partial string? Name1 { get; set; }

    [SaveState]
    public partial int Index { get; set; }

    [SaveState(Init = "[]")]
    public partial List<string> Values { get; set; }

    public string? Name2 { get; set; }
}

生成的组件属性(分部属性)

using AutoPageStateContainerGenerator;

// <auto-generated/>
#pragma warning disable
#nullable enable
namespace Blazor.Test.Client.Pages;


/// <inheritdoc/>
partial class Counter 
{
    [global::Microsoft.AspNetCore.Components.InjectAttribute]
    public Blazor_Test_Client_Pages_CounterStateContainer StateContainer { get; set; }


    public override string? Type { get => StateContainer.Type; set => StateContainer.Type = value; }


    public partial string? Name1 { get => StateContainer.Name1; set => StateContainer.Name1 = value; }


    public partial int Index { get => StateContainer.Index; set => StateContainer.Index = value; }


    public partial System.Collections.Generic.List<string> Values { get => StateContainer.Values; set => StateContainer.Values = value; }
}

生成的数据容器

using AutoPageStateContainerGenerator;

// <auto-generated/>
#pragma warning disable
#nullable enable
namespace Blazor.Test.Client.Pages;

[AutoPageStateContainerGenerator.GeneratedStateContainerAttribute(Lifetime = 0, Name = "Counter")]
[global::System.CodeDom.Compiler.GeneratedCode("AutoPageStateContainerGenerator.PageStateContainerGenerator", "0.0.4.0")]
/// <inheritdoc/>
public partial class Blazor_Test_Client_Pages_CounterStateContainer : AutoPageStateContainerGenerator.IGeneratedStateContainer, Blazor.Test.Client.Pages.ICounter
{
    public event Action? OnChange;

    private string? type = "CounterParent";

    public string? Type
    {
        get
        {
            return type;
        }
        set
        {
            type = value;
            NotifyStateChanged(); 
        }
    }

    private string? name1;

    public string? Name1
    {
        get
        {
            return name1;
        }
        set
        {
            name1 = value;
            NotifyStateChanged(); 
        }
    }

    private int index;

    public int Index
    {
        get
        {
            return index;
        }
        set
        {
            index = value;
            NotifyStateChanged(); 
        }
    }

    private System.Collections.Generic.List<string> values = [];

    public System.Collections.Generic.List<string> Values
    {
        get
        {
            return values;
        }
        set
        {
            values = value;
            NotifyStateChanged(); 
        }
    }


    private void NotifyStateChanged()
      => OnChange?.Invoke();
}

⭐ 源码

posted @ 2025-05-29 16:37  yaoqinglin_mtiter  阅读(93)  评论(0)    收藏  举报