【发布时间】:2021-01-04 22:04:42
【问题描述】:
我有一个通过 EF 连接到数据库的 WPF 应用程序。但是当我调用 await DbSet().SingleAsync() 我的 UI 线程被卡住并且没有响应。我发现当我运行 await 时,它仍会在主 UI 线程上运行,因此我可以访问 UI。这将解释为什么当我只使用Task.Delay() 时它可以工作,因为SingleAsync 正在使用线程,但Task.Delay() 没有。
ConfigureAwait(false) 应该解决这个问题并在不同的线程上运行它。但它没有,我的 UI 仍然冻结。
我做错了吗?
代码:
private async void Button_Login_Click(object sender, RoutedEventArgs e)
{
await userService.ValidateCredentials(textBoxLogin.Text, textBoxLogin.Text).ConfigureAwait(false);
}
public async Task<bool> ValidateCredentials(string username, string password)
{
User user = await userDao.SingleOrNull(true, o => o.Username == username && o.Password == password);
if (user == null)
return (false);
return (true);
}
public async Task<ResourceDbType> SingleOrNull(bool noTracking, Expression<Func<ResourceDbType, bool>> where)
{
ResourceDbType ret;
try
{
if (noTracking)
{
ret = await GetDbSet().AsNoTracking().SingleAsync(where);
}
else
ret = await GetDbSet().SingleAsync(where);
}
catch (Exception ex)
{
return null;
}
return ret;
}
编辑: BaseDao 应该只公开 DbContext 中的函数,并在 MainDbContext 注册选定的 DbSet 模型。我们在 RestApi 服务中使用了这段代码,所以我重用了它,因为我已经习惯了。
[RegisterClass(Lifetime.Scoped)] 是标记类的属性,以便在应用程序启动时通过反射将其注册到 DependencyInjection。
道码:
public class BaseDao<ResourceDbType> : IDisposable where ResourceDbType : class, new()
{
public DbContext DbContext { get; protected set; }
public BaseDao(MainDbContext mainDbContext)
{
DbContext = mainDbContext;
}
public DbSet<ResourceDbType> GetDbSet()
{
return this.DbContext.Set<ResourceDbType>();
}
public List<ResourceDbType> ToList()
{
return this.GetDbSet().ToList();
}
public ResourceDbType[] ToArray()
{
return this.GetDbSet().ToArray();
}
public async Task<ResourceDbType> SingleOrNull(bool noTracking, Expression<Func<ResourceDbType, bool>> where)
{
ResourceDbType ret;
try
{
if (noTracking)
{
ret = await GetDbSet().AsNoTracking().SingleAsync(where);
}
else
ret = await GetDbSet().SingleAsync(where);
}
catch (Exception ex)
{
return null;
}
return ret;
}
public void Dispose()
{
this.DbContext?.Dispose();
}
}
UserDao 代码:
[RegisterClass(Lifetime.Scoped)]
public class UserDao : BaseDao<User>
{
public UserDao(MainDbContext mainDbContext) : base(mainDbContext)
{
}
}
【问题讨论】:
-
不应该是
private async Task Button_Login_Click(object sender, RoutedEventArgs e)而不是private async void Button_Login_Click(object sender, RoutedEventArgs e)吗? -
@Delphi.Boy 不,它应该是异步 void
-
对于 OP,这里也有很多假设,其中很多是错误的或不正确的
-
这里没有典型的死锁问题(在显示的代码中)。故事可能还有更多内容,但根据当前代码很难知道在哪里
-
@Andy 我在所有地方都尝试过 ConfigureAwait,但结果相同。
标签: c# wpf multithreading entity-framework async-await