GaoXinLibrary.ElasticSearch 1.0.1

dotnet add package GaoXinLibrary.ElasticSearch --version 1.0.1
                    
NuGet\Install-Package GaoXinLibrary.ElasticSearch -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GaoXinLibrary.ElasticSearch" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GaoXinLibrary.ElasticSearch" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="GaoXinLibrary.ElasticSearch" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GaoXinLibrary.ElasticSearch --version 1.0.1
                    
#r "nuget: GaoXinLibrary.ElasticSearch, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GaoXinLibrary.ElasticSearch@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GaoXinLibrary.ElasticSearch&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=GaoXinLibrary.ElasticSearch&version=1.0.1
                    
Install as a Cake Tool

GaoXinLibrary.ElasticSearch

Elasticsearch 9.x 简化封装库,基于 Elastic.Clients.Elasticsearch 9.x,支持 .NET 8/9/10。

安装

dotnet add package GaoXinLibrary.ElasticSearch

特性

  • 简化 CRUD — 一行代码完成文档的增删改查
  • 搜索构建器BuildSearch<T>() 流式构建 Bool 查询 + 排序 + 过滤 + 高亮 + 分页
  • 统一字段映射[ElasticField] 特性统一配置字段类型、分析器、忽略、Completion
  • 多种分析器 — 内置 Standard / Simple / Whitespace / IK / CJK 等分析器支持
  • IK 分词 — 开箱即用的 ik_smart / ik_max_word 分词支持
  • Suggest 自动补全 — Completion Suggester,支持单字段/多字段、模糊匹配、通配符回退
  • 高亮搜索 — 内置高亮标签封装,搜索结果自动携带 Highlights 字典
  • 通配符/前缀搜索WildcardSearchAsync / PrefixSearchAsync,支持不区分大小写
  • 表达式局部更新UpdateFieldsAsync 通过表达式选择字段进行局部更新
  • 索引映射更新UpdateIndexMappingAsync 在线更新索引映射(新增字段)
  • 索引设置更新UpdateIndexSettingsAsync 动态修改副本数、刷新间隔、结果窗口等
  • 索引生命周期 — 刷新、Reindex、关闭/打开、别名管理
  • 批量操作BulkIndexAsync / BulkUpdateAsync / BulkDeleteAsync
  • 滚动搜索ScrollAllAsync 适合大数据量全量导出
  • 滚动批量更新ScrollUpdateAsync 按查询条件滚动批量更新
  • 分页搜索 — 内置分页封装,返回总页数、是否有上/下页
  • 聚合查询 — 简化的 Terms 聚合接口
  • 索引管理 — 根据特性自动创建索引 + 字段映射 + 设置更新 + 别名
  • DI 注入AddElasticsearch() 一行注册所有服务
  • 底层客户端 — 随时通过 Client 属性访问底层 ElasticsearchClient

快速开始

1. 注册服务

builder.Services.AddElasticsearch(options =>
{
    options.Urls = ["http://localhost:9200"];
    options.DefaultIndex = "my-app";
    options.Username = "elastic";
    options.Password = "changeme";
    options.DefaultAnalyzer = AnalyzerType.IkSmart;
});

2. 定义文档

[ElasticsearchIndex("products")]
public class Product
{
    public string Id { get; set; } = "";

    [ElasticField(FieldType = ElasticFieldType.Text, Analyzer = AnalyzerType.IkMaxWord, SearchAnalyzer = AnalyzerType.IkSmart,
        EnableKeywordSubField = true)]
    [ElasticCompletion(Analyzer = AnalyzerType.IkMaxWord)]
    public string Name { get; set; } = "";

    [ElasticField(FieldType = ElasticFieldType.Text, Analyzer = AnalyzerType.IkSmart)]
    public string Description { get; set; } = "";

    [ElasticField(FieldType = ElasticFieldType.Keyword)]
    [ElasticCompletion]
    public string SupplierNo { get; set; } = "";

    [ElasticField(FieldType = ElasticFieldType.Completion, Analyzer = AnalyzerType.IkMaxWord)]
    public string Suggest { get; set; } = "";

    [ElasticField(FieldType = ElasticFieldType.Keyword)]
    public string Category { get; set; } = "";

    [ElasticField(FieldType = ElasticFieldType.Double)]
    public decimal Price { get; set; }

    [ElasticField(FieldType = ElasticFieldType.Date, DateFormat = "yyyy-MM-dd HH:mm:ss||epoch_millis")]
    public DateTime CreatedAt { get; set; }

    [ElasticField(Ignore = true)]
    public string InternalCode { get; set; } = "";

    // ── Object / Nested 嵌套类型 ──
    [ElasticField(FieldType = ElasticFieldType.Object)]
    public ProductCategory? ProductCategory { get; set; }

    [ElasticField(FieldType = ElasticFieldType.Nested)]
    public List<ProductTag>? Tags { get; set; }
}

/// <summary>Object 子类型,属性同样使用 [ElasticField] 标注</summary>
public class ProductCategory
{
    [ElasticField(FieldType = ElasticFieldType.Keyword)]
    public string Value { get; set; } = "";

    [ElasticField(FieldType = ElasticFieldType.Integer)]
    public int CategoryId { get; set; }
}

/// <summary>Nested 子类型,支持嵌套查询</summary>
public class ProductTag
{
    [ElasticField(FieldType = ElasticFieldType.Keyword)]
    public string Name { get; set; } = "";

    [ElasticField(FieldType = ElasticFieldType.Double)]
    public double Score { get; set; }
}

Object / Nested 说明:FieldType 设置为 ObjectNested 时,库会自动递归读取子类型的 [ElasticField] 特性,生成嵌套映射。支持直接类型(ProductCategory)和集合类型(List<ProductTag>ProductTag[] 等)。

3. 使用服务

public class ProductService
{
    private readonly IElasticsearchService _es;

    public ProductService(IElasticsearchService es) => _es = es;

    public async Task Demo()
    {
        // ── 确保索引存在(自动创建 + 字段映射) ──
        await _es.EnsureIndexAsync<Product>();

        // ── 索引文档 ──
        await _es.IndexAsync(new Product
        {
            Id = "1",
            Name = "华为 Mate 60 Pro",
            Description = "搭载麒麟芯片的旗舰手机",
            Suggest = "华为 Mate 60 Pro",
            Category = "手机",
            Price = 6999
        }, id: "1");

        // ── 获取文档 ──
        var product = await _es.GetAsync<Product>("1");

        // ── 批量获取 ──
        var products = await _es.MultiGetAsync<Product>(["1", "2", "3"]);

        // ── 更新文档 ──
        await _es.UpdateAsync<Product>("1", new { Price = 5999 });

        // ── 表达式局部更新(推荐) ──
        await _es.UpdateFieldsAsync<Product>("1", ct: default,
            (x => x.Price, 5999m),
            (x => x.Name, "华为 Mate 70 Pro"));

        // ── 全文搜索(字符串字段名) ──
        var results = await _es.FullTextSearchAsync<Product>(
            "华为手机", ["name", "description"],
            analyzerType: AnalyzerType.IkSmart);

        // ── 全文搜索(表达式选择字段,自动解析 [ElasticField] 字段名,推荐) ──
        var results2 = await _es.FullTextSearchAsync<Product>(
            "华为手机", [x => x.Name, x => x.Description],
            analyzerType: AnalyzerType.IkSmart);

        // ── 分页搜索 ──
        var paged = await _es.SearchPagedAsync<Product>(
            "手机", [x => x.Name], page: 1, pageSize: 10);
        Console.WriteLine($"共 {paged.Total} 条,第 {paged.Page}/{paged.TotalPages} 页");

        // ── 高亮搜索 ──
        var highlighted = await _es.HighlightSearchAsync<Product>(
            "华为", [x => x.Name, x => x.Description],
            preTags: "<mark>", postTags: "</mark>");

        // ── 自动补全 ──
        var suggestions = await _es.SuggestAsync<Product>(
            "华为", x => x.Suggest, size: 5, fuzzy: true);
        foreach (var s in suggestions.Suggestions)
            Console.WriteLine($"建议: {s}");

        // ── 通配符搜索 ──
        var wildcardResults = await _es.WildcardSearchAsync<Product>(
            x => x.Name, "华为*", size: 10);

        // ── 前缀搜索 ──
        var prefixResults = await _es.PrefixSearchAsync<Product>(
            x => x.Category, "手", size: 10);

        // ── 精确匹配 ──
        var exact = await _es.TermSearchAsync<Product>(x => x.Category, "手机");

        // ── 批量索引 ──
        var batch = Enumerable.Range(1, 100).Select(i => new Product
        {
            Id = i.ToString(),
            Name = $"商品{i}",
            Category = "测试",
            Price = i * 10
        });
        await _es.BulkIndexAsync(batch);

        // ── 批量更新 ──
        await _es.BulkUpdateAsync<Product>(new Dictionary<string, object>
        {
            ["1"] = new { Price = 4999 },
            ["2"] = new { Price = 3999 }
        });

        // ── 聚合 ──
        var agg = await _es.TermsAggregationAsync<Product>(x => x.Category, size: 5);

        // ── 计数 ──
        var count = await _es.CountAsync<Product>();

        // ── 多字段自动补全(带通配符回退) ──
        var multiSuggest = await _es.SuggestMultiFieldAsync<Product>(
            "华为", [x => x.Name, x => x.Suggest],
            size: 10, fuzzy: true, wildcardFallback: true);

        // ── 高亮搜索结果中提取高亮 ──
        var hlResult = await _es.HighlightSearchAsync<Product>(
            "华为", [x => x.Name, x => x.Description],
            preTags: "<mark>", postTags: "</mark>");
        for (int i = 0; i < hlResult.Documents.Count; i++)
        {
            if (hlResult.Highlights.TryGetValue(i, out var fields))
            {
                if (fields.TryGetValue("name", out var nameHl))
                    Console.WriteLine($"高亮名称: {string.Join("", nameHl)}");
            }
        }

        // ── 滚动搜索(大数据量导出) ──
        var allProducts = await _es.ScrollAllAsync<Product>(batchSize: 500);

        // ── 滚动批量更新(按条件批量更新所有文档) ──
        var updated = await _es.ScrollUpdateAsync<Product>(
            q => q.Query(qq => qq.Term(t => t.Field("category").Value("手机"))),
            new { Price = 4999 },
            batchSize: 5000);
        Console.WriteLine($"共更新 {updated} 个文档");

        // ── 更新索引映射(新增字段时使用) ──
        await _es.UpdateIndexMappingAsync<Product>();

        // ── 更新索引设置(动态设置,立即生效) ──
        await _es.UpdateIndexSettingsAsync("products", settings => settings
            .NumberOfReplicas(2)
            .RefreshInterval("30s")
            .MaxResultWindow(50000));

        // ── 根据 [ElasticsearchIndex] 特性更新索引设置 ──
        await _es.UpdateIndexSettingsAsync<Product>();

        // ── 刷新索引(使最近写入对搜索可见) ──
        await _es.RefreshIndexAsync<Product>();

        // ── Reindex(索引迁移 / 字段类型变更) ──
        var reindexed = await _es.ReindexAsync("products", "products_v2");
        Console.WriteLine($"共迁移 {reindexed} 个文档");

        // ── 关闭 / 打开索引(修改静态设置时使用) ──
        await _es.CloseIndexAsync("products");
        // ... 修改静态设置 ...
        await _es.OpenIndexAsync("products");

        // ── 索引别名管理 ──
        await _es.AddAliasAsync("products_v2", "products_alias");
        var aliases = await _es.GetAliasesAsync("products_v2");
        Console.WriteLine($"别名: {string.Join(", ", aliases)}");
        await _es.RemoveAliasAsync("products_v2", "products_alias");

        // ── 删除文档 ──
        await _es.DeleteAsync<Product>("1");

        // ── 按条件删除 ──
        await _es.DeleteByQueryAsync<Product>(d => d
            .Query(q => q.Term(t => t.Field("category").Value("测试"))));

        // ── 删除索引 ──
        await _es.DeleteIndexAsync("products");
    }
}

4. 搜索构建器(推荐)

通过 BuildSearch<T>() 创建搜索构建器,支持 Bool 查询组合排序过滤高亮分页 等:

// ── 基本搜索 + 过滤 + 排序 ──
var result = await _es.BuildSearch<Product>()
    .Must(q => q.Match(m => m.Field("name").Query("华为手机").Analyzer("ik_smart")))
    .Filter(q => q.Term(t => t.Field("category").Value("手机")))
    .Filter(q => q.Range(r => r.NumberRange(n => n.Field("price").Gte(1000).Lte(5000))))
    .Sort(x => x.Price, SortOrder.Asc)
    .SortByScore()
    .Size(20)
    .ExecuteAsync();

// ── 多条件搜索 + 高亮 + 分页 ──
var paged = await _es.BuildSearch<Product>()
    .Must(q => q.MultiMatch(mm => mm.Query("华为").Fields(["name", "description"]).Analyzer("ik_smart")))
    .Should(q => q.Term(t => t.Field("category").Value("手机")))
    .MustNot(q => q.Term(t => t.Field("category").Value("配件")))
    .Filter(q => q.Range(r => r.NumberRange(n => n.Field("price").Gte(100))))
    .MinimumShouldMatch(0)
    .Sort(x => x.Price, SortOrder.Asc)
    .Highlight(x => x.Name, "<mark>", "</mark>")
    .Highlight(x => x.Description, "<mark>", "</mark>")
    .ExecutePagedAsync(page: 1, pageSize: 10);
Console.WriteLine($"共 {paged.Total} 条,第 {paged.Page}/{paged.TotalPages} 页");

// ── 纯过滤(不需要得分排序,性能最好) ──
var filtered = await _es.BuildSearch<Product>()
    .Filter(q => q.Term(t => t.Field("category").Value("手机")))
    .Filter(q => q.Range(r => r.DateRange(d => d.Field("createdAt").Gte("2024-01-01"))))
    .Sort(x => x.CreatedAt, SortOrder.Desc)
    .Size(50)
    .ExecuteAsync();

// ── Source 过滤(只返回部分字段) ──
var partial = await _es.BuildSearch<Product>()
    .Must(q => q.MatchAll(new MatchAllQuery()))
    .SourceIncludes(x => x.Name, x => x.Price)
    .Size(100)
    .ExecuteAsync();

查询类型说明:

方法 作用 影响得分 典型场景
Must() 必须匹配 ✅ 是 关键词搜索、全文匹配
Should() 可选匹配(提升得分) ✅ 是 相关性提升、多条件可选
Filter() 必须匹配 ❌ 否 价格区间、分类、状态过滤
MustNot() 排除匹配 ❌ 否 排除特定分类、状态

5. 自定义搜索(DSL)

通过 SearchAsync 方法直接使用底层 DSL:

var result = await _es.SearchAsync<Product>(s => s
    .Size(20)
    .Query(q => q
        .Bool(b => b
            .Must(
                m => m.Match(mm => mm.Field("name").Query("手机").Analyzer("ik_smart")),
                m => m.Range(r => r.NumberRange(nr => nr.Field("price").Gte(1000).Lte(5000)))
            )
        )
    )
    .Sort(so => so.Field("price", f => f.Order(SortOrder.Asc)))
);

6. 直接使用底层客户端

var client = _es.Client;
var response = await client.SearchAsync<Product>(s => s.Indices("products").Size(5));

分析器类型

类型 说明
Default 不指定 使用 ES 默认
Standard standard 标准分析器(按 Unicode 规则分词)
Simple simple 简单分析器(按非字母字符拆分)
Whitespace whitespace 空白分析器(按空白字符拆分)
Keyword keyword 不分词(整个字段作为一个 Token)
Pattern pattern 模式分析器(按正则拆分)
Cjk cjk 中日韩分析器
IkSmart ik_smart IK 智能分词(粗粒度,适合搜索)
IkMaxWord ik_max_word IK 最大化分词(细粒度,适合索引)

字段类型

类型 说明
Auto 自动推断(有分析器时为 Text,否则为 Keyword)
Text 全文本(支持分词)
Keyword 关键词(精确匹配、排序、聚合)
Integer / Long / Float / Double 数值类型
Date 日期类型(支持自定义格式)
Boolean 布尔类型
Completion 自动补全(Suggest)
Nested 嵌套对象
Object 对象类型
GeoPoint 地理位置
Ip IP 地址
Binary 二进制
*Range 范围类型

[ElasticField] 特性选项

选项 默认值 说明
FieldType Auto 字段映射类型
Analyzer Default 索引时分析器
SearchAnalyzer Default 搜索时分析器(默认同 Analyzer)
Ignore false 忽略字段(不添加到索引映射中)
FieldName null 自定义 ES 字段名
MaxInputLength 50 Completion 最大输入长度(仅 FieldType=Completion)
DateFormat null 日期格式
Store false 是否存储原始值
Boost 0 权重提升
EnableKeywordSubField false 添加 .keyword 子字段(仅 Text 类型,用于精确匹配/排序/聚合)

[ElasticCompletion] 特性选项

独立的自动补全子字段特性,可与 [ElasticField] 配合使用,在 Text / Keyword 字段上附加 .suggest 子字段。

选项 默认值 说明
SubFieldName "suggest" 子字段名称(生成 fieldName.suggest
Analyzer Default 自动补全分析器(默认同主字段 Analyzer)
MaxInputLength 50 最大输入长度
// Text 字段 + .keyword 子字段 + .suggest 自动补全
[ElasticField(FieldType = ElasticFieldType.Text, Analyzer = AnalyzerType.IkMaxWord, EnableKeywordSubField = true)]
[ElasticCompletion(Analyzer = AnalyzerType.IkMaxWord)]
public string Name { get; set; } = "";

// Keyword 字段 + .suggest 自动补全
[ElasticField(FieldType = ElasticFieldType.Keyword)]
[ElasticCompletion]
public string SupplierNo { get; set; } = "";

// 独立的 Completion 字段(不是子字段)
[ElasticField(FieldType = ElasticFieldType.Completion, Analyzer = AnalyzerType.IkMaxWord)]
public string Suggest { get; set; } = "";

配置选项

选项 默认值 说明
Urls ["http://localhost:9200"] 节点地址
DefaultIndex "default" 默认索引
Username null 用户名
Password null 密码
ApiKey null API Key 认证
CertificateFingerprint null HTTPS 证书指纹
RequestTimeoutSeconds 30 请求超时
DefaultAnalyzer Standard 默认分析器
DefaultNumberOfShards 1 默认分片数
DefaultNumberOfReplicas 1 默认副本数

表达式字段选择(推荐)

所有接受 string field / string[] fields 参数的搜索方法都提供了 表达式重载,通过 x => x.PropertyName 自动解析 ES 字段名,避免手写字符串出错:

// ❌ 字符串方式(容易拼错、重构不友好)
await _es.FullTextSearchAsync<Product>("手机", ["name", "description"]);
await _es.TermSearchAsync<Product>("category", "手机");
await _es.SuggestAsync<Product>("华为", "suggest");

// ✅ 表达式方式(编译时检查、自动解析 [ElasticField] 特性的 FieldName)
await _es.FullTextSearchAsync<Product>("手机", [x => x.Name, x => x.Description]);
await _es.TermSearchAsync<Product>(x => x.Category, "手机");
await _es.SuggestAsync<Product>("华为", x => x.Suggest);

支持表达式的方法:FullTextSearchAsyncSearchPagedAsyncTermSearchAsyncHighlightSearchAsyncSuggestAsyncSuggestMultiFieldAsyncWildcardSearchAsyncPrefixSearchAsyncUpdateFieldsAsyncTermsAggregationAsync

也可以直接使用 ElasticFieldResolver 手动解析:

var fieldName = ElasticFieldResolver.Resolve<Product>(x => x.Name); // "name" 或 [ElasticField(FieldName = "xxx")] 的值
var fieldNames = ElasticFieldResolver.ResolveMany<Product>(x => x.Name, x => x.Description);

索引管理

方法 说明
IndexExistsAsync 判断索引是否存在
CreateIndexAsync<T> 根据特性自动创建索引 + 字段映射 + 设置
EnsureIndexAsync<T> 索引不存在则自动创建
DeleteIndexAsync 删除索引
UpdateIndexMappingAsync<T> 更新索引映射(仅可新增字段,不可修改已有字段类型)
UpdateIndexSettingsAsync 动态更新索引设置(副本数、刷新间隔、结果窗口等)
UpdateIndexSettingsAsync<T> 根据 [ElasticsearchIndex] 特性更新动态设置
RefreshIndexAsync 强制刷新索引(使写入对搜索可见)
ReindexAsync 将数据从源索引迁移到目标索引
CloseIndexAsync 关闭索引(修改静态设置前需关闭)
OpenIndexAsync 打开索引(恢复读写)
AddAliasAsync 为索引添加别名
RemoveAliasAsync 移除索引别名
GetAliasesAsync 获取索引的所有别名

IndexSettingsBuilder

通过 UpdateIndexSettingsAsync 使用流式构建器更新动态设置:

await _es.UpdateIndexSettingsAsync("products", settings => settings
    .NumberOfReplicas(2)          // 副本数
    .RefreshInterval("30s")       // 刷新间隔("-1" 禁用自动刷新)
    .MaxResultWindow(50000)       // from + size 上限
    .MaxRescoreWindow(10000)      // 最大重评分窗口
    .Set("index.gc_deletes", "60s") // 自定义设置
);

零停机索引迁移(Reindex + Alias)

// 1. 创建新索引(新映射/新设置)
await _es.CreateIndexAsync<ProductV2>("products_v2");

// 2. 迁移数据
var count = await _es.ReindexAsync("products", "products_v2");

// 3. 切换别名(零停机)
await _es.RemoveAliasAsync("products", "products_live");
await _es.AddAliasAsync("products_v2", "products_live");

// 4. 删除旧索引
await _es.DeleteIndexAsync("products");

项目结构

GaoXinLibrary.ElasticSearch/
├── Attributes/                          # 特性标注
│   ├── ElasticCompletionAttribute.cs    # Completion 子字段特性
│   ├── ElasticFieldAttribute.cs         # 字段映射特性
│   └── ElasticsearchIndexAttribute.cs   # 索引配置特性
├── Builders/                            # 构建器
│   ├── ElasticSearchBuilder.cs          # 搜索构建器(Bool 查询 + 排序 + 高亮 + 分页)
│   └── IndexSettingsBuilder.cs          # 索引设置构建器
├── Core/                                # 核心基础设施
│   ├── ElasticsearchClientFactory.cs    # 客户端工厂(内部单例)
│   ├── ElasticsearchOptions.cs          # 连接配置选项
│   └── ElasticFieldResolver.cs          # 表达式字段解析器
├── Enums/                               # 枚举类型
│   ├── AnalyzerType.cs                  # 分析器类型
│   └── ElasticFieldType.cs              # 字段映射类型
├── Extensions/                          # DI 扩展
│   └── ServiceCollectionExtensions.cs   # AddElasticsearch() 注册
├── Models/                              # 返回结果模型
│   ├── PagedSearchResult.cs             # 分页搜索结果
│   ├── SearchResult.cs                  # 搜索结果(含高亮)
│   └── SuggestResult.cs                 # 自动补全结果
└── Services/                            # 服务接口与实现
    ├── IElasticsearchService.cs         # 服务接口
    └── ElasticsearchService.cs          # 服务实现

前提条件

License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 111 3/13/2026
1.0.0-beta.2 68 3/10/2026