CmfDBCommon 1.0.0
dotnet add package CmfDBCommon --version 1.0.0
NuGet\Install-Package CmfDBCommon -Version 1.0.0
<PackageReference Include="CmfDBCommon" Version="1.0.0" />
<PackageVersion Include="CmfDBCommon" Version="1.0.0" />
<PackageReference Include="CmfDBCommon" />
paket add CmfDBCommon --version 1.0.0
#r "nuget: CmfDBCommon, 1.0.0"
#addin nuget:?package=CmfDBCommon&version=1.0.0
#tool nuget:?package=CmfDBCommon&version=1.0.0
DBCommon 数据库通用组件
基于SqlSugar ORM的数据库通用访问组件,支持多种数据库,包括MySQL、SQL Server、Oracle、PostgreSQL和达梦数据库。
特点
- 支持多种数据库类型
- 基于工厂模式的设计
- 完整的ORM操作支持
- 灵活的配置管理
- 支持事务处理
- 支持原生SQL执行
- 支持存储过程和函数调用
- DBFirst实体生成器
- 支持日志记录和自定义日志接口
- 支持Microsoft日志系统集成
- 完善的资源释放机制
- 多线程环境下线程安全
- 新增 - 分页查询支持
- 新增 - 内存缓存支持
- 新增 - 流式API查询构造器
- 新增 - 高性能批量操作
安装
通过NuGet包管理器安装:
dotnet add package DBCommon
配置文件
默认配置文件为dbconfig.xml
,位于程序根目录下。配置文件格式如下:
<?xml version="1.0" encoding="utf-8"?>
<DbConfig>
<Connections>
<Connection>
<Name>default</Name>
<DbType>MySql</DbType>
<ConnectionString>server=localhost;database=testdb;uid=root;pwd=123456;charset=utf8;</ConnectionString>
<IsMaster>true</IsMaster>
<Enabled>true</Enabled>
</Connection>
<Connection>
<Name>sqlserver</Name>
<DbType>SqlServer</DbType>
<ConnectionString>Server=.;Database=testdb;Trusted_Connection=True;</ConnectionString>
<IsMaster>false</IsMaster>
<Enabled>true</Enabled>
</Connection>
</Connections>
</DbConfig>
基本用法
初始化
// 使用默认配置和默认日志
var client = new DbCommonClient();
// 或指定配置文件路径
var client = new DbCommonClient("path/to/dbconfig.xml");
// 或指定配置文件路径和自定义日志
var logger = DbCommonClient.CreateDefaultLogger(
minLevel: DefaultLogger.LogLevel.Debug,
logFilePath: "logs/dbcommon.log",
consoleOutput: true);
var client = new DbCommonClient("path/to/dbconfig.xml", logger);
// 或使用Microsoft日志系统
var msLogger = loggerFactory.CreateLogger<DbCommonClient>();
var client = new DbCommonClient("path/to/dbconfig.xml", msLogger);
// 或使用Microsoft日志工厂
var client = new DbCommonClient("path/to/dbconfig.xml", loggerFactory, "DBCommon.Client");
获取数据库上下文
// 获取默认数据库上下文
var db = client.GetDbContext();
// 获取指定名称的数据库上下文
var db = client.GetDbContext("sqlserver");
基本CRUD操作
// 插入
var entity = new User { Name = "张三", Age = 25 };
int insertId = await db.InsertAsync(entity);
// 查询 - 获取单个实体
var user = await db.GetByIdAsync<User>(1);
// 查询 - 获取列表
var list = await db.GetListAsync<User>(it => it.Age > 20);
// 查询 - 分页
var pageList = await db.GetPageListAsync<User>(it => it.Age > 20, 1, 10);
// 更新
user.Name = "李四";
await db.UpdateAsync(user);
// 删除
await db.DeleteAsync<User>(1);
事务处理
// 开始事务
db.BeginTran();
try
{
var user = new User { Name = "王五", Age = 30 };
int userId = await db.InsertAsync(user);
var log = new Log { UserId = userId, Content = "新用户注册" };
await db.InsertAsync(log);
// 提交事务
db.CommitTran();
}
catch (Exception ex)
{
// 回滚事务
db.RollbackTran();
throw;
}
原生SQL执行
// 执行SQL查询
var users = await db.SqlQueryAsync<User>("SELECT * FROM Users WHERE Age > @Age", new { Age = 25 });
// 执行SQL命令
int affectedRows = await db.ExecuteCommandAsync("UPDATE Users SET Status = 1 WHERE Id = @Id", new { Id = 1 });
配置管理功能
// 获取所有配置
var configs = client.GetAllConfigs();
// 获取特定配置
var config = client.GetConfig("default");
// 保存单个配置
var newConfig = new DbConnectionConfig
{
Name = "oracle",
DbType = Enums.DbType.Oracle,
ConnectionString = "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL)));User Id=system;Password=oracle;",
IsMaster = false,
Enabled = true
};
client.SaveConfig(newConfig);
// 保存多个配置
var configList = new List<DbConnectionConfig>
{
new DbConnectionConfig
{
Name = "pg",
DbType = Enums.DbType.PostgreSQL,
ConnectionString = "Host=localhost;Port=5432;Database=testdb;Username=postgres;Password=postgres",
IsMaster = false,
Enabled = true
},
new DbConnectionConfig
{
Name = "dameng",
DbType = Enums.DbType.Dameng,
ConnectionString = "Server=localhost;Port=5236;User=SYSDBA;Password=SYSDBA;Database=DAMENG",
IsMaster = false,
Enabled = true
}
};
client.SaveConfigs(configList);
// 删除配置
client.DeleteConfig("dameng");
// 确保配置存在(如果不存在则创建默认配置)
client.EnsureConfigExists();
日志功能
// 创建并设置默认日志(控制台输出 + 文件输出)
var logger = DbCommonClient.CreateDefaultLogger(
minLevel: DefaultLogger.LogLevel.Debug,
logFilePath: "logs/dbcommon.log",
consoleOutput: true);
DbCommonClient.SetDefaultLogger(logger);
// 创建指定名称的日志实例
var sqlLogger = DbCommonClient.CreateDefaultLogger(
minLevel: DefaultLogger.LogLevel.Info,
logFilePath: "logs/sql.log");
DbCommonClient.RegisterLogger("SQL", sqlLogger);
// 获取指定名称的日志实例
var logger = DbCommonClient.GetLogger("SQL");
logger.Info("执行SQL查询");
// 创建空日志(不输出任何日志)
var nullLogger = DbCommonClient.CreateNullLogger();
// 使用自定义日志实现
// 首先实现ILogger接口
public class MyCustomLogger : ILogger
{
public void Debug(string message, params object[] args) { /* 自定义实现 */ }
public void Info(string message, params object[] args) { /* 自定义实现 */ }
public void Warning(string message, params object[] args) { /* 自定义实现 */ }
public void Error(string message, params object[] args) { /* 自定义实现 */ }
public void Error(Exception exception, string message, params object[] args) { /* 自定义实现 */ }
public void Fatal(string message, params object[] args) { /* 自定义实现 */ }
public void Fatal(Exception exception, string message, params object[] args) { /* 自定义实现 */ }
}
// 然后注册并使用
var myLogger = new MyCustomLogger();
DbCommonClient.SetDefaultLogger(myLogger);
// 或者在创建客户端时直接使用
var client = new DbCommonClient(logger: myLogger);
Microsoft日志系统集成
// 在ASP.NET Core或使用Microsoft.Extensions.Logging的项目中集成
// 依赖注入方式
// 在Startup.cs或Program.cs中
services.AddLogging(builder =>
{
builder.AddConsole();
builder.AddDebug();
});
// 在控制器或服务中注入
public class MyService
{
private readonly DbCommonClient _dbClient;
public MyService(ILoggerFactory loggerFactory)
{
// 方法1:使用Microsoft ILogger创建DbCommonClient
var logger = loggerFactory.CreateLogger<MyService>();
_dbClient = new DbCommonClient("path/to/dbconfig.xml", logger);
// 方法2:使用Microsoft ILoggerFactory创建DbCommonClient
_dbClient = new DbCommonClient("path/to/dbconfig.xml", loggerFactory, "DBCommon");
// 方法3:将Microsoft ILoggerFactory设置为全局默认日志工厂
DbCommonClient.UseMicrosoftLoggerFactory(loggerFactory);
_dbClient = new DbCommonClient("path/to/dbconfig.xml");
}
}
// 直接使用方式
using Microsoft.Extensions.Logging;
// 创建LoggerFactory
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
builder.AddDebug();
});
// 使用Microsoft ILogger
var logger = loggerFactory.CreateLogger("DBCommon");
var dbClient = new DbCommonClient("path/to/dbconfig.xml", logger);
// 使用Microsoft ILoggerFactory
var dbClient2 = new DbCommonClient("path/to/dbconfig.xml", loggerFactory);
// 创建适配器
var loggerAdapter = DbCommonClient.CreateMicrosoftLoggerAdapter(logger);
var factoryAdapter = DbCommonClient.CreateMicrosoftLoggerFactoryAdapter(loggerFactory);
// 设置为默认日志
DbCommonClient.SetDefaultLogger(logger);
// 注册指定名称的日志
DbCommonClient.RegisterLogger("SQLLogger", logger);
// 将Microsoft ILoggerFactory设置为全局默认日志工厂
DbCommonClient.UseMicrosoftLoggerFactory(loggerFactory);
实体生成
// 生成所有表的实体类
var generator = new EntityGenerator(client.GetDbContext());
generator.GenerateEntities("Output/Entities");
// 生成指定表的实体类
generator.GenerateEntity("Output/Entities", "User");
高级用法
Lambda表达式查询
// 复杂条件查询
var users = await db.GetListAsync<User>(it =>
it.Age > 20 &&
it.Status == 1 &&
it.Name.Contains("张")
);
// 排序
var orderedUsers = await db.GetListAsync<User>(
it => it.Status == 1,
it => it.Age,
OrderByType.Desc
);
// 指定返回字段
var partialUsers = await db.GetListAsync<User>(
it => it.Status == 1,
it => new { it.Id, it.Name }
);
多表查询
// 多表连接查询
var query = await db.Queryable<User>()
.LeftJoin<UserRole>((u, ur) => u.Id == ur.UserId)
.LeftJoin<Role>((u, ur, r) => ur.RoleId == r.Id)
.Where((u, ur, r) => u.Status == 1)
.Select((u, ur, r) => new
{
UserId = u.Id,
UserName = u.Name,
RoleId = r.Id,
RoleName = r.Name
})
.ToListAsync();
新增功能
分页查询
分页查询可以轻松实现分页功能,支持多种方式:
// 基本分页查询(所有记录)
var page1 = await db.GetPagedListAsync<User>(1, 10); // 第1页,每页10条
// 条件分页查询
var page2 = await db.GetPagedListAsync<User>(u => u.Age > 20, 1, 10);
// 条件排序分页查询
var page3 = await db.GetPagedListAsync<User>(
u => u.Age > 20,
u => u.CreateTime,
OrderByType.Desc,
1, 10);
// 分页结果包含丰富的信息
Console.WriteLine($"当前页:{page1.PageIndex}");
Console.WriteLine($"每页记录数:{page1.PageSize}");
Console.WriteLine($"总记录数:{page1.TotalCount}");
Console.WriteLine($"总页数:{page1.TotalPages}");
Console.WriteLine($"是否有上一页:{page1.HasPreviousPage}");
Console.WriteLine($"是否有下一页:{page1.HasNextPage}");
// 结果遍历
foreach (var item in page1.Items)
{
Console.WriteLine($"用户ID:{item.Id},姓名:{item.Name}");
}
缓存查询
缓存查询可以提高查询性能,减少数据库访问:
// 从缓存中获取单个实体,如果缓存中不存在则从数据库获取并缓存
var user = db.GetByIdFromCache<User>(1);
// 指定缓存键和过期时间(30分钟)
var user2 = db.GetByIdFromCache<User>(2, "user:2", TimeSpan.FromMinutes(30));
// 从缓存中获取列表
var users = db.GetListFromCache<User>(u => u.Status == 1);
// 从缓存中获取分页数据
var page = db.GetPagedListFromCache<User>(1, 10);
// 移除指定键的缓存
db.RemoveCache("user:2");
// 移除指定前缀的所有缓存
int count = db.RemoveCacheByPrefix("user:");
查询构造器
DBCommon提供了灵活的查询构造器,用于构建复杂的查询条件和操作。
// 创建查询构造器
var query = dbClient.Query<User>()
.Where(u => u.Age > 18)
.OrderBy(u => u.CreateTime, OrderByType.Desc)
.Skip(10)
.Take(20)
.UseCache("users_cache", TimeSpan.FromMinutes(10));
// 获取结果
var users = query.ToList();
// 异步获取结果
var usersAsync = await query.ToListAsync();
// 获取分页结果
var pagedUsers = query.ToPagedList(1, 20);
// 获取第一条记录
var firstUser = query.First();
// 统计记录数
var count = query.Count();
// 判断是否存在符合条件的记录
var exists = query.Any();
// 表连接查询
var query = dbClient.Query<User>()
.LeftJoin<UserAddress>((u, a) => u.Id == a.UserId)
.Where(u => u.Status == 1);
查询构造器扩展方法
QueryBuilderExtensions提供了更多高级查询和转换功能。
// 将查询结果转换为指定类型
var userDtos = dbClient.Query<User>()
.Where(u => u.Status == 1)
.ToListAs<User, UserDto>();
// 将查询结果分页并转换为指定类型
var pagedUserDtos = dbClient.Query<User>()
.Where(u => u.Status == 1)
.ToPagedListAs<User, UserDto>(1, 20);
// 按条件进行分组统计
var userCountByStatus = dbClient.Query<User>()
.GroupCount(u => u.Status);
// 执行自定义SQL查询
var customResults = dbClient.Query<User>()
.SqlQuery<User, CustomResult>("SELECT id, name FROM user WHERE age > @age",
new SugarParameter("@age", 18));
// 将查询结果转换为字典
var userDict = dbClient.Query<User>()
.ToDictionary(u => u.Id);
批量操作
批量操作提供更高的性能,特别适合大量数据处理:
// 批量插入
var users = new List<User>();
for (int i = 0; i < 1000; i++)
{
users.Add(new User { Name = $"用户{i}", Age = 20 + i % 50, Status = 1 });
}
int count = await db.BulkInsertAsync(users);
// 批量更新
users.ForEach(u => u.Status = 2);
await db.BulkUpdateAsync(users);
// 批量更新指定字段
await db.BulkUpdateAsync(users, u => new { u.Status });
// 批量删除
await db.BulkDeleteAsync(users);
// 根据条件批量删除
await db.BulkDeleteAsync<User>(u => u.Status == 0);
// 使用DataTable进行SQL批量复制
DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Age", typeof(int));
dt.Columns.Add("Status", typeof(int));
for (int i = 0; i < 1000; i++)
{
dt.Rows.Add($"用户{i}", 20 + i % 50, 1);
}
await db.SqlBulkCopyAsync<User>(dt);
高级特性
仓储模式
DBCommon提供了仓储模式的支持,可以更加方便地对数据进行操作。
// 创建仓储
var userRepository = dbClient.GetRepository<User>();
// 查询数据
var user = userRepository.GetById(1);
var users = userRepository.GetAll();
var activeUsers = userRepository.GetList(u => u.Status == 1);
// 分页查询
var pagedResult = userRepository.GetPagedList(1, 10);
var pagedActiveUsers = userRepository.GetPagedList(u => u.Status == 1, 1, 10);
var pagedSortedUsers = userRepository.GetPagedList(u => u.Status == 1, u => u.CreateTime, OrderByType.Desc, 1, 10);
// 新增数据
var newUser = new User { Name = "张三", Age = 25 };
userRepository.Insert(newUser);
// 更新数据
user.Age = 26;
userRepository.Update(user);
// 删除数据
userRepository.Delete(user);
userRepository.DeleteById(2);
userRepository.DeleteByCondition(u => u.Status == 0);
// 批量操作
var users = new List<User>();
for (int i = 0; i < 1000; i++)
{
users.Add(new User { Name = $"用户{i}", Age = 20 + i % 10 });
}
userRepository.BulkInsert(users);
仓储扩展方法
DBCommon提供了丰富的仓储扩展方法,进一步简化数据操作。
// 获取仓储
var userRepository = dbClient.GetRepository<User>();
// 使用SQL查询
var users = userRepository.FromSql("SELECT * FROM users WHERE age > @age", new SugarParameter("@age", 18));
// 执行SQL命令
int rows = userRepository.ExecuteSql("UPDATE users SET status = @status WHERE age < @age",
new SugarParameter("@status", 0),
new SugarParameter("@age", 18));
// 获取指定范围的记录
var users = userRepository.GetRange(10, 20); // 跳过10条,获取20条
// 根据条件更新
userRepository.UpdateWhere(
u => new User { Status = 1, UpdateTime = DateTime.Now },
u => u.Age > 18 && u.Status == 0
);
// 检查记录是否存在
bool exists = userRepository.Exists(u => u.UserName == "admin");
// 查询并映射到DTO
var userDtos = userRepository.GetListAs<User, UserDto>(u => u.Status == 1);
// 分页查询并映射到DTO
var pagedResult = userRepository.GetPagedListAs<User, UserDto>(1, 10, u => u.Status == 1);
工作单元模式
工作单元模式可以更好地管理数据库操作和事务。
// 创建工作单元
using (var unitOfWork = dbClient.CreateUnitOfWork())
{
// 获取仓储
var userRepository = unitOfWork.GetRepository<User>();
var orderRepository = unitOfWork.GetRepository<Order>();
// 开始事务
unitOfWork.BeginTransaction();
try
{
// 执行操作
var user = userRepository.GetById(1);
user.Balance -= 100;
userRepository.Update(user);
var order = new Order
{
UserId = user.Id,
Amount = 100,
Status = 1
};
orderRepository.Insert(order);
// 提交事务
unitOfWork.CommitTransaction();
}
catch
{
// 回滚事务
unitOfWork.RollbackTransaction();
throw;
}
}
// 使用更简便的方式执行事务
dbClient.UseTransaction(unitOfWork =>
{
var userRepository = unitOfWork.GetRepository<User>();
var orderRepository = unitOfWork.GetRepository<Order>();
var user = userRepository.GetById(1);
user.Balance -= 100;
userRepository.Update(user);
var order = new Order
{
UserId = user.Id,
Amount = 100,
Status = 1
};
orderRepository.Insert(order);
});
// 异步方式执行事务
await dbClient.UseTransactionAsync(async unitOfWork =>
{
var userRepository = unitOfWork.GetRepository<User>();
var orderRepository = unitOfWork.GetRepository<Order>();
var user = await userRepository.GetByIdAsync(1);
user.Balance -= 100;
await userRepository.UpdateAsync(user);
var order = new Order
{
UserId = user.Id,
Amount = 100,
Status = 1
};
await orderRepository.InsertAsync(order);
});
工作单元扩展方法
通过工作单元扩展方法,可以更灵活地进行数据库操作和事务管理。
// 创建工作单元
using (var unitOfWork = dbClient.CreateUnitOfWork())
{
// 使用WithTransaction方法自动管理事务
unitOfWork.WithTransaction(() =>
{
// 获取仓储
var userRepository = unitOfWork.GetRepository<User>();
var orderRepository = unitOfWork.GetRepository<Order>();
// 执行业务逻辑
var user = userRepository.GetById(1);
user.Balance -= 100;
userRepository.Update(user);
var order = new Order
{
UserId = user.Id,
Amount = 100,
Status = 1
};
orderRepository.Insert(order);
});
// 执行SQL查询
var users = unitOfWork.SqlQuery<User>("SELECT * FROM users WHERE balance > @balance",
new SugarParameter("@balance", 1000));
// 检查表是否存在
bool tableExists = unitOfWork.TableExists<User>();
// 创建表
unitOfWork.CreateTable<User>();
// 获取数据库时间
DateTime dbTime = unitOfWork.GetDate();
}
// 异步使用工作单元和事务
await dbClient.UseTransactionAsync(async unitOfWork =>
{
var userRepository = unitOfWork.GetRepository<User>();
await userRepository.UpdateColumnsAsync(user, u => new { u.Status, u.UpdateTime });
// 执行存储过程
var result = await unitOfWork.ExecuteProcedureAsync<ProcResult>("sp_process_order",
new SugarParameter("@orderId", 1001));
});
连接字符串构建器
DBCommon提供了连接字符串构建器,使得创建和管理数据库连接字符串变得更加简单。
// 创建MySQL连接字符串构建器
var builder = dbClient.CreateMySqlConnectionStringBuilder();
// 设置连接参数
builder.WithServer("localhost")
.WithPort(3306)
.WithDatabase("mydb")
.WithUsername("root")
.WithPassword("password")
.WithMaxPoolSize(100)
.WithParameter("AllowUserVariables", "True");
// 构建连接字符串
string connectionString = builder.Build();
// 可以直接创建配置并保存
dbClient.SaveConnectionConfig("MyConnection", builder);
// 或者直接保存连接字符串
dbClient.SaveConnectionConfig("MyConnection", connectionString, DBCommon.Enums.DbType.MySql);
许可证
MIT
资源释放
所有关键对象都实现了IDisposable接口,建议使用using语句确保资源正确释放:
// 使用DbCommonClient
using (var client = new DbCommonClient())
{
// 使用DbContext
using (var db = client.GetDbContext())
{
// 执行数据库操作
var users = db.GetList<User>();
}
}
// 或者在ASP.NET Core中注册为单例,由框架自动管理生命周期
services.AddSingleton<DbCommonClient>();
线程安全
组件内部实现了线程安全机制,可安全地在多线程环境下使用:
// 多线程环境中安全使用
var client = new DbCommonClient();
Parallel.For(0, 10, i =>
{
using (var db = client.GetDbContext())
{
// 线程安全的数据库操作
var user = new User { Name = $"用户{i}", Age = 20 + i };
db.Insert(user);
}
});
// 线程安全的配置管理
Parallel.For(0, 5, i =>
{
var config = new DbConnectionConfig
{
Name = $"db{i}",
DbType = Enums.DbType.MySql,
ConnectionString = $"server=localhost;database=db{i};uid=root;pwd=123456;charset=utf8;",
IsMaster = i == 0,
Enabled = true
};
client.SaveConfig(config);
});
ASP.NET Core 集成
在ASP.NET Core项目中,可以通过依赖注入来使用DBCommon。
// 在Startup.cs中注册服务
public void ConfigureServices(IServiceCollection services)
{
// 注册DBCommon服务
services.AddDBCommon();
// 或者注册DBCommon服务和工作单元
services.AddDBCommonWithUnitOfWork();
// 注册实体仓储
services.AddRepository<User>();
services.AddRepository<Order>();
}
// 在Controller或Service中使用
public class UserService
{
private readonly DbCommonClient _dbClient;
private readonly Repository<User> _userRepository;
private readonly UnitOfWork _unitOfWork;
public UserService(DbCommonClient dbClient, Repository<User> userRepository, UnitOfWork unitOfWork)
{
_dbClient = dbClient;
_userRepository = userRepository;
_unitOfWork = unitOfWork;
}
public async Task<User> GetUserAsync(int id)
{
return await _userRepository.GetByIdAsync(id);
}
public async Task CreateOrderAsync(int userId, decimal amount)
{
await _unitOfWork.ExecuteInTransactionAsync(async () =>
{
var userRepository = _unitOfWork.GetRepository<User>();
var orderRepository = _unitOfWork.GetRepository<Order>();
var user = await userRepository.GetByIdAsync(userId);
user.Balance -= amount;
await userRepository.UpdateAsync(user);
var order = new Order
{
UserId = userId,
Amount = amount,
Status = 1
};
await orderRepository.InsertAsync(order);
});
}
}
Product | Versions 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 was computed. 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. |
-
net8.0
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.Configuration.Xml (>= 8.0.0)
- Microsoft.Extensions.Logging (>= 9.0.3)
- SqlSugarCore (>= 5.1.4.124)
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.0 | 439 | 7 days ago |