diff --git a/README.md b/README.md
index 78d38682..ba862756 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ EasilyNET Packages
- 对 MongoDB 驱动的一些封装,方便使用以及一些常用的默认配置
- 雪花 ID,一些常用的数据类型,枚举,扩展方法等
- 自动模块化注入服务,新增支持 WPF,WinForm 等项目,需使用 IHost 通用主机模式
-- MongoDB 添加 DateOnly 和 TimeOnly 的支持
+- MongoDB 添加 DateOnly 和 TimeOnly 的支持, dynamic 类型支持
- MongoDB GridFS 用法的简单支持(常用用法)和使用案例.
- 在 WebAPI 中集成一些常见的过滤器和中间件
- 对 Swagger 文档添加分组,隐藏 API 和添加部分数据类型默认值显示的支持,方便前端工程师查阅
@@ -54,7 +54,7 @@ EasilyNET Packages
- Some encapsulation of MongoDB driver for easy use and some common default configurations
- Snowflake ID, some common data types, enumerations, extension methods, etc.
- Automatic modular injection services, adding support for WPF, WinForm and other projects, using IHost common host mode
-- Added support for DateOnly and TimeOnly in MongoDB
+- Added support for DateOnly and TimeOnly in MongoDB, dynamic type support
- Simple support for MongoDB GridFS usage (common usage) and usage examples.
- Integration of some common filters and middleware in WebAPI
- Added support for grouping, hiding APIs, and displaying default values for some data types in Swagger documents, making it easier for front-end engineers to refer to
diff --git a/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs b/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs
index 7240d5e0..a9628ae0 100644
--- a/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs
+++ b/sample/WebApi.Test.Unit/Controllers/MongoLockController.cs
@@ -9,8 +9,39 @@ namespace WebApi.Test.Unit.Controllers;
/// MongoDB分布式锁测试
///
[Route("api/[controller]/[action]"), ApiController, ApiGroup("MongoLock", "v1", "基于MongoDB实现的分布式锁测试")]
-public class MongoLockController(IMongoLockFactory lockFactory) : ControllerBase
+public class MongoLockController(IMongoLockFactory lockFactory, DbContext db) : ControllerBase
{
+ ///
+ /// 测试锁
+ ///
+ ///
+ [HttpPost]
+ public async Task BusinessTest()
+ {
+ const string lockId = "64d44afda4473b85a177084d"; // 这里使用一个随机的ID作为锁ID,相当于其他锁中的Key.用来区分不同的业务的锁
+ var mongoLock = lockFactory.GenerateNewLock(ObjectId.Parse(lockId));
+ var acq = await mongoLock.AcquireAsync(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(0));
+ try
+ {
+ if (acq.Acquired)
+ {
+ await db.GetCollection("locks_test").InsertOneAsync(new
+ {
+ AcquiredId = acq.AcquireId
+ });
+ }
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ throw;
+ }
+ finally
+ {
+ await mongoLock.ReleaseAsync(acq);
+ }
+ }
+
///
/// AcquireLock
///
diff --git a/sample/WebApi.Test.Unit/Script.js b/sample/WebApi.Test.Unit/Script.js
index 07d2abfa..ae2d1a85 100644
--- a/sample/WebApi.Test.Unit/Script.js
+++ b/sample/WebApi.Test.Unit/Script.js
@@ -1,15 +1,32 @@
-import { check } from "k6";
+import { check, sleep } from "k6";
import http from "k6/http";
export const options = {
- stages: [
- { duration: "30s", target: 20 },
- { duration: "1m30s", target: 10 },
- { duration: "20s", target: 0 },
- ],
+ stages: [
+ { duration: "60s", target: 100 }, // Ramp-up to 100 users over 30s
+ { duration: "60s", target: 200 }, // Ramp-up to 200 users over 1 minute
+ { duration: "60s", target: 300 }, // Ramp-up to 300 users over 1 minute
+ { duration: "60s", target: 500 }, // Ramp-down to 0 users over 1 minute
+ ],
};
export default function () {
- const res = http.post("http://localhost:5046/api/MongoTest/MongoPost");
- check(res, { "status was 200": (r) => r.status == 200 });
+ const url = 'http://localhost:8848/api/MongoLock/BusinessTest';
+
+ const payload = JSON.stringify({
+ email: 'aaa',
+ password: 'bbb'
+ });
+
+ const params = {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ };
+
+ const res = http.post(url, params);
+ check(res, { "status was 200": (r) => r.status == 200 });
+
+ // Optional: Add a small sleep to simulate real user behavior
+ sleep(1);
}
diff --git a/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs b/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs
index 42d0e28f..b8d067ad 100644
--- a/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs
+++ b/sample/WebApi.Test.Unit/ServiceModules/MongoModule.cs
@@ -92,9 +92,12 @@ public override void ConfigureServices(ConfigureServicesContext context)
// }).Build());
// b.AddSimpleConsole();
//}));
+ cs.MaxConnecting = int.MaxValue;
+ cs.MaxConnectionPoolSize = int.MaxValue;
};
});
context.Services.RegisterSerializer(new DateOnlySerializerAsString());
context.Services.RegisterSerializer(new TimeOnlySerializerAsString());
+ context.Services.RegisterDynamicSerializer();
}
}
\ No newline at end of file
diff --git a/src/EasilyNET.MongoDistributedLock/Acquire.cs b/src/EasilyNET.MongoDistributedLock/Acquire.cs
index 65f85cc7..e3064d0b 100644
--- a/src/EasilyNET.MongoDistributedLock/Acquire.cs
+++ b/src/EasilyNET.MongoDistributedLock/Acquire.cs
@@ -6,14 +6,18 @@ namespace EasilyNET.MongoDistributedLock;
///
internal sealed class Acquire : IAcquire
{
+ private readonly IDistributedLock? _distributedLock;
+
///
/// 构造函数
///
///
- public Acquire(ObjectId acquireId)
+ ///
+ public Acquire(ObjectId acquireId, IDistributedLock distributedLock)
{
Acquired = true;
AcquireId = acquireId;
+ _distributedLock = distributedLock;
}
///
@@ -29,4 +33,12 @@ public Acquire()
///
public ObjectId AcquireId { get; }
+
+ public async ValueTask DisposeAsync()
+ {
+ if (Acquired && _distributedLock is not null)
+ {
+ await _distributedLock.ReleaseAsync(this);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/EasilyNET.MongoDistributedLock/Attributes/IAcquire.cs b/src/EasilyNET.MongoDistributedLock/Attributes/IAcquire.cs
index 8b4bc391..afac22b2 100644
--- a/src/EasilyNET.MongoDistributedLock/Attributes/IAcquire.cs
+++ b/src/EasilyNET.MongoDistributedLock/Attributes/IAcquire.cs
@@ -5,7 +5,7 @@ namespace EasilyNET.MongoDistributedLock.Attributes;
///
/// IAcquire
///
-public interface IAcquire
+public interface IAcquire : IAsyncDisposable
{
///
/// true if lock successfully acquired; otherwise, false
diff --git a/src/EasilyNET.MongoDistributedLock/DistributedLock.cs b/src/EasilyNET.MongoDistributedLock/DistributedLock.cs
index 570f5797..3789c4b7 100644
--- a/src/EasilyNET.MongoDistributedLock/DistributedLock.cs
+++ b/src/EasilyNET.MongoDistributedLock/DistributedLock.cs
@@ -34,10 +34,10 @@ public async Task AcquireAsync(TimeSpan lifetime, TimeSpan timeout)
var acquire = await _locks.Find(bf.Eq(c => c.Id, _lockId)).FirstOrDefaultAsync();
if (acquire is not null && await WaitSignalAsync(acquire.AcquireId, timeout) == false)
{
- return await TryUpdateAsync(lifetime, acquireId) ? new Acquire(acquireId) : new();
+ return await TryUpdateAsync(lifetime, acquireId) ? new Acquire(acquireId, this) : new();
}
}
- return new Acquire(acquireId);
+ return new Acquire(acquireId, this);
}
///
diff --git a/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs b/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs
index ab4f6837..f2604503 100644
--- a/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs
+++ b/src/EasilyNET.MongoSerializer.AspNetCore/ServiceCollectionExtensions.cs
@@ -1,4 +1,5 @@
using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Serializers;
// ReSharper disable UnusedMethodReturnValue.Global
// ReSharper disable MemberCanBePrivate.Global
@@ -25,16 +26,16 @@ public static IServiceCollection RegisterSerializer(this IServiceCollection s
return services;
}
- /////
- ///// 注册动态类型( | )序列化支持
- /////
- /////
- /////
+ ///
+ /// 注册动态类型 [ | ] 序列化支持
+ ///
+ ///
+ ///
//[Obsolete("MongoDB.Drive 2.18之前和2.21之后,又默认支持动态类型的序列化了(2.19-2.20之间的版本,仅允许反序列化被视为安全的类型).暂时标记为过时.以后应该会移除")]
- //public static IServiceCollection RegisterDynamicSerializer(this IServiceCollection services)
- //{
- // var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type) || (type.FullName is not null && type.FullName.StartsWith("<>f__AnonymousType")));
- // BsonSerializer.RegisterSerializer(objectSerializer);
- // return services;
- //}
+ public static IServiceCollection RegisterDynamicSerializer(this IServiceCollection services)
+ {
+ var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type) || (type.FullName is not null && type.FullName.StartsWith("<>f__AnonymousType")));
+ BsonSerializer.RegisterSerializer(objectSerializer);
+ return services;
+ }
}
\ No newline at end of file