我有一个 .NET 8 wpf 应用程序,它使用 Microsoft Community Toolkit 进行 MVVM 和 Microsoft 扩展依赖项注入以及 EF-Core 框架。 除了 Views 和 Viewmodels 之外,我还有一个 Repo 类,它使用异步消息来使用 EF-Core 查询数据。
该应用程序创建一个列表视图,用户单击一个项目会触发项目属性更改,并调用存储库中的异步方法从数据库中检索记录。
如果用户在检索前一个项目之前选择一个新项目(即他们单击了错误的项目并想要单击另一个项目),则会出现问题。 我收到错误“在上一个操作完成之前,在此上下文实例上启动了第二个操作。”
我尝试过更改数据上下文和服务范围,但并不能解决问题。让我们将该问题保存到另一个线程。
在这种情况下,只要用户更改所选项目,就会对异步方法进行新的调用。 在执行新的调用之前,如何确定先前的调用是否已完成?
我在确定任务是否完成的方法中设置属性时实现的解决方案是有效的,但是是否有更好的方法来确定任务是否完成?我可以让新请求等待上一个任务完成,或者取消上一个任务并开始新的任务吗? (任一场景都足以满足应用程序的需求,因为一旦用户单击新项目,前一个场景就不再相关)。
附件是我认为的 App.cs、ViewModel 和 Repo 的相关代码片段。
public partial class App : Application
{
public IServiceProvider serviceProvider { get; set; }
public App()
{
serviceProvider = CreateServiceProvider();
}
public new static App Current => (App)Application.Current;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
}
private IServiceProvider CreateServiceProvider()
{
IServiceCollection services = new ServiceCollection();
services.AddDbContext<bardv2hContext>(options => { options.UseSqlServer("defaultconnstring"); },ServiceLifetime.Transient);
services.AddTransient<ILocalRepo, LocalRepo>();
services.AddTransient<ViewModel>();
return services.BuildServiceProvider();
}
}
public partial class ViewModel : ObservableObject
{
private ILocalRepo _localRepo;
private bool _taskcompleted = true;
[ObservableProperty]
private short ubCounter;
[ObservableProperty]
private short selectedCounter;
async partial void OnSelectedCounterChanged(short value)
{
await getSelectedResearch(value);
}
async partial void OnUbCounterChanged(short value)
{
await getSelectedResearch(value);
}
async internal Task getSelectedResearch(short value)
{
if (!_taskcompleted)
{
await Task.Delay(1500);
}
_taskcompleted = false;
SelectedResearch = await _localRepo.OneResearchbyCounter(value);
_taskcompleted = true;
}
public ResearchViewModelC1()
{
_localRepo = App.Current.serviceProvider.GetService<ILocalRepo>();
}
}
public class LocalRepo : ILocalRepo
{
private readonly bardv2hContext _localdb;
public LocalRepo(bardv2hContext localdb)
{
_localdb = localdb;
}
public async Task<Research> OneResearchbyCounter(short counter)
{
var res = await _localdb.Researches
.Where(r=>r.Counter == counter)
.Include(r=>r.Inres)
.Include(r=>r.ApprovedResearch)
.Include(r=>r.Actualpayments)
.Include(r=>r.FiscalReports)
.Include(r=>r.Scireports)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
return res;
}
}
我尝试使用基于此sample的DBContextFactory,但我无法让它工作。 我将我的 app.cs 更改为:
public partial class App : Application
{
public IServiceProvider serviceProvider { get; set; }
public App()
{
serviceProvider = CreateServiceProvider();
}
public new static App Current => (App)Application.Current;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
}
private IServiceProvider CreateServiceProvider()
{
IServiceCollection services = new ServiceCollection();
services.AddDbContextFactory<bardv2hContext><bardv2hContext>(options => { options.UseSqlServer("defaultconnstring"); });
services.AddTransient<ILocalRepo, LocalRepoWF>();
services.AddTransient<ViewModel>();
return services.BuildServiceProvider();
}
}
以及此的存储库:
public LocalRepoWF(Func<dbContext> localdb)
{
_factory = localdb;
dbContext _localdb;
} public LocalRepoWF(Func<dbContext> localdb)
{
_factory = localdb;
}
public async Task<Mymodel> selModel(string InvCode)
{
using (var _localdb = _factory.Invoke())
{ return await _localdb.Model.Find(InvCode); }
}
但我收到错误
无法解析类型“System.Func`1[dbContext]”的服务 尝试激活“LocalRepoWF”
我尝试像这样注册服务:
.AddScoped<ILocalRepo, LocalRepoWF>(lr => new LocalRepoWF(() => lr.GetService<dbContext>()))
但是在调用存储库中的过程时,我收到一条错误消息:“无法访问已处置的上下文实例。此错误的常见原因是处置从依赖项注入解析的上下文实例,然后尝试使用相同的上下文实例在你的申请的其他地方。”
谢谢 Rufo 先生,使用 IDBContextFactory 解决了我的问题。 它不仅消除了错误,而且程序的响应速度更快了。 我将在这里发布我更正后的代码以供将来参考。 它基于这个样本服务注入更改为:
public partial class App : Application
{
public IServiceProvider serviceProvider { get; set; }
public App()
{
serviceProvider = CreateServiceProvider();
}
public new static App Current => (App)Application.Current;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
}
private IServiceProvider CreateServiceProvider()
{
IServiceCollection services = new ServiceCollection();
services.AddDbContextFactory<bardv2hContext>(options => { options.UseSqlServer("defaultconnstring"); },ServiceLifetime.Singleton);
services.AddTransient<ILocalRepo, LocalRepo>();
services.AddTransient<ViewModel>();
return services.BuildServiceProvider();
}
我的仓库被更改为这个。 (请注意,原始问题中的代码基于旧的 efcore 版本)(ViewModel 保持不变)
private readonly IDbContextFactory<bardv2hContext> _factory;
public LocalRepoWF(IDbContextFactory<bardv2hContext> localdb)
{
_factory = localdb;
}
public async Task<Models.Localdbc.Investigator> selInvestigatorbyInvCode(string InvCode)
{
using (var _localdb = _factory.CreateDbContext())
{ return await _localdb.Investigators.Where(i => i.InvCode == InvCode).Include(i => i.InvTypes).FirstOrDefaultAsync(); }
}