abpvnext 开发中ValidationErrors和LifetimeScope异常的解决办法

  1. abpvnext Method arguments are not valid! See ValidationErrors for details

有道翻译:abpvnext方法参数无效! 有关详细信息,请参阅ValidationErrors

ABP的一个校验异常。请对比传入的实体中是否有字段是必填的,比如我的就发现 input实体里面有很多字段是加了类似这样的属性 [Required(ErrorMessage = "IsOnLine不能为空")],那么带有这些属性的字段都得在传入前赋值。

ABP的两个特性EnableValidation和DisableValidation 用来控制validation。如果想要抛弃验证特性,我们在Add方法上面添加两个特性[HttpPost]与[DisableValidation]


  1. Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it (or one of its parent scopes) has already been disposed.

有道翻译:无法解析实例,也无法从这个LifetimeScope创建嵌套的生命周期,因为它(或它的一个父作用域)已经被处置。

我这个消息队列的订阅事件,在取到消息之后新开一个线程去做解析和数据插入,也就是在数据插入的Repository层方法中GetDbSetAsync()执行时报上面的错误,然后

网上搜到的唯一合适的参考链接:https://www.cnblogs.com/zxsn2014/p/16478922.html

里面有这么一个描述:

生命周期为Scope方式,随着请求的结束,实例生命周期也会被释放,因此在多线程下若共享实例,容易出现实例已释放的错误,报错如下:Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it (or one of its parent scopes) has already been disposed

解决方法:

从当前应用中获取实例,构造函数注入IHost,通过host获取IServiceProvider:

在线程中通过_sp创建新的生命周期:

 using (var sp = _sp.CreateScope())

                      {

                          await Task.Delay(5000);

                          var applyReposity = sp.ServiceProvider.GetRequiredService<IApplyReposity>();

                          Console.WriteLine($"taskCode:{applyReposity.GetHashCode()},taskThreaId:{Thread.CurrentThread.ManagedThreadId}");

                          var model = await applyReposity.GetAsync(c => 1 == 1);

                          sp.Dispose();

                      }

观察curThreaId与taskThreaId,Task.Run开启了新的线程,与当前主线程线程ID不同,当前请求中注入的IApplyReposity的实例_applyReposity编码是57588670,新线程中开启的新生命周期sp.ServiceProvider中获取的实例编码是2837748;主线程与子线程实例不再相关,解决主线程已释放,子线程获取不到实例的问题。

(1)IHOST传递到下层再获取仓储接口实例的解决办法

他的解决方法,这个解决方法是直接通过控制器调用Repository,但是我abp是中间还有service接口和类,还有domain代理类Manager,然后才能到Repository层。

所以我参照这个实例的解决办法如下:

把Ihost从hander构造方法注入,然后传递到application的构造方法注入,再传递到mannager类的构造方法。

最后再manager构造方法里通过如下代码行

_tahmCJWdTmpRepository = host.Services.GetRequiredService<ITahmCJ_wd_tmpRepository>();

取得 Repository 接口实例。

这时候再用Repository实例去操作数据就没问题了。

补充:消息处理程序hander类,HandleEventAsync方法中,还是不能再单独开线程new Thread去调用业务方法,只能在HandleEventAsync中直接调用业务处理方法。否则还是会出现生命周期异常问题。

TahmEventHandler

TahmCJ_wd_tmpAppService

TahmCJ_wd_tmpManager


(2)实际上经过后期测试发现,更改我的EventHandler 事件类继承的注入生命周期的依赖为单例模式就不会报错了。我本来用的是ITransientDependency ,修改为 ISingletonDependency即可。

不过这种方式对于一个消费消息的事件来说我觉得是不妥的。


(3)2023-4-3更新解决方案, 我之所以造出了LifetimeScope生命周期问题,是因为我在cap订阅事件中新开了线程来试图加快消息消费过程。 但是经过大佬指点,cap本身是可以设置多线程数量的,所以我完全可以取消新开线程的代码,直接在cap配置方法里增加线程数量的配置来解决快速消费消息的并发问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Abp框架提供了一些基本的数据访问方法,如GetAll, Get, Insert, Update, Delete等,它们可以满足大多数应用程序的需求。但是,如果需要执行复杂的SQL查询或操作,可以使用Dapper来执行原生SQL。Dapper是一个轻量级的ORM框架,可以在Abp应用程序与Entity Framework Core一起使用。以下是一个使用Dapper执行原生SQL查询的示例: 1. 安装Dapper NuGet包 可以使用NuGet包管理器或在项目文件手动添加以下条目来安装Dapper: ``` Install-Package Dapper ``` 2. 创建DapperRepository 我们可以创建一个名为DapperRepository的仓储类,它将使用Dapper执行原生SQL查询或操作。以下是一个简单的DapperRepository类的示例: ``` public class DapperRepository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity<int> { private readonly IDbConnection _dbConnection; public DapperRepository(IDbConnection dbConnection) { _dbConnection = dbConnection; } public async Task<List<TEntity>> GetAllListAsync() { return (await _dbConnection.GetListAsync<TEntity>()).ToList(); } public async Task<TEntity> GetAsync(int id) { return await _dbConnection.GetAsync<TEntity>(id); } public async Task<TEntity> InsertAsync(TEntity entity) { entity.Id = await _dbConnection.InsertAsync(entity); return entity; } public async Task<TEntity> UpdateAsync(TEntity entity) { await _dbConnection.UpdateAsync(entity); return entity; } public async Task DeleteAsync(int id) { await _dbConnection.DeleteAsync<TEntity>(id); } public async Task<List<TEntity>> QueryAsync(string sql, object param = null) { return (await _dbConnection.QueryAsync<TEntity>(sql, param)).ToList(); } public async Task<TEntity> QueryFirstOrDefaultAsync(string sql, object param = null) { return await _dbConnection.QueryFirstOrDefaultAsync<TEntity>(sql, param); } } ``` 3. 注册DapperRepository 在应用程序的Startup.cs文件,我们可以使用依赖注入将DapperRepository注册到容器: ``` services.AddScoped(typeof(IRepository<>), typeof(DapperRepository<>)); ``` 4. 使用DapperRepository执行查询 现在我们可以在应用程序使用DapperRepository来执行原生SQL查询或操作。以下是一个使用DapperRepository执行查询的示例: ``` public class MyService : IMyService { private readonly IRepository<MyEntity> _repository; public MyService(IRepository<MyEntity> repository) { _repository = repository; } public async Task<List<MyEntity>> GetEntitiesWithComplexQueryAsync() { string sql = "SELECT * FROM MyEntities WHERE MyProperty = @myParam"; var parameters = new { myParam = "someValue" }; return await _repository.QueryAsync(sql, parameters); } } ``` 在上面的示例,我们使用DapperRepository执行了一个带有参数的原生SQL查询,并将结果作为MyEntity对象列表返回。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值