asp.net - 在前一个上下文之前开始了第二个操作
问题描述
使用 EntityFramework 时遇到一个常见错误,但我无法找出原因。错误是
“在前一个操作完成之前,在此上下文上启动了第二个操作。这通常是由使用相同 DbContext 实例的不同线程引起的。有关如何避免 DbContext 线程问题的更多信息,请参阅 https://go.microsoft.com /fwlink/?linkid=2097913。”
我正在使用 GraphQL 中间件来处理请求。
堆栈跟踪:
at Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
at Test.DataAccess.Intranet.Repository.Admin.UserModule.Query.GetUserDataQuery.Execute(String username) in C:\Projects\GIT Projects\SWDi\Intranet\Test.Backend\Test.DataAccess.Intranet\Repository\Modules\Admin\UserManagement\Query\Implementation\GetUserDataQuery.cs:line 34
at Test.Web.Base.Services.UserService.GetUserContext(HttpContext context) in C:\Projects\GIT Projects\Test\Intranet\Test.Backend\Test.Web.Base\Services\UserService.cs:line 55
at Test.API.Middleware.GraphQLMiddleware.InvokeAsync(HttpContext httpContext) in C:\Projects\GIT Projects\Test\Intranet\Test.Backend\Test.Web.API\Middleware\GraphQLMiddleware.cs:line 71
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Test.Web.API.Middleware.NtlmAndAnonymousSetupMiddleware.Invoke(HttpContext context) in C:\Projects\GIT Projects\Test\Intranet\SWDi.Backend\Test.Web.API\Middleware\NtlmAndAnonymousSetupMiddleware.cs:line 39
at Test.API.Middleware.ExceptionMiddleware.Invoke(HttpContext context) in C:\Projects\GIT Projects\Test\Intranet\Test.Backend\Test.Web.API\Middleware\ExceptionMiddleware.cs:line 40"
在这里,我处理 GraphQLMiddleware.cs 中的 POST 请求:
public async Task InvokeAsync(HttpContext httpContext)
{
if (
(httpContext.Request.Path.StartsWithSegments(CATCHURLPATH) || httpContext.Request.PathBase.StartsWithSegments(CATCHURLPATH))
&& string.Equals(httpContext.Request.Method, CATCHURLMETHOD, StringComparison.OrdinalIgnoreCase))
{
string body;
var userContext = await this.userService.GetUserContext(httpContext);
using (var streamReader = new StreamReader(httpContext.Request.Body))
{
body = await streamReader.ReadToEndAsync();
var request = JsonConvert.DeserializeObject<GraphQLQueryBase>(body);
var result = await this.executor.ExecuteAsync(doc =>
{
doc.ThrowOnUnhandledException = true;
doc.Schema = this.schema;
doc.Query = request.Query;
doc.Inputs = request.Variables.ToInputs();
doc.ExposeExceptions = true;
doc.UserContext = new Dictionary<string, object>()
{
{ "UserId", userContext.UserId },
{ "Username", userContext.Username },
};
}).ConfigureAwait(false);
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Factory.StartNew(() => this.queryLogMutation.Execute(userContext.UserId, request.Query));
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
httpContext.Response.ContentType = "application/json";
await this.writer.WriteAsync(httpContext.Response.Body, result);
}
}
else
{
await this.next(httpContext);
}
}
如您所见,我正在调用userService.GetUserContext
实现为的方法
public class UserService : IUserService
{
private const string CACHEKEY = "userContext_";
private readonly IMemoryCache cache;
private readonly IGetUserDataQuery getUserByUsernameQuery;
/// <summary>
/// Initializes a new instance of the <see cref="UserService"/> class.
/// </summary>
/// <param name="cache">Get the cache from DI.</param>
/// <param name="getUserByUsernameQuery">The Data Repository from DI.</param>
public UserService(IMemoryCache cache, IGetUserDataQuery getUserByUsernameQuery)
{
this.cache = cache;
this.getUserByUsernameQuery = getUserByUsernameQuery;
}
/// <summary>
/// Created the user context information.
/// </summary>
/// <param name="context">The current Httpcontext.</param>
/// <returns>The user context.</returns>
public async Task<UserContext> GetUserContext(HttpContext context)
{
UserContext returnContext;
var username = this.GetUsername(context);
if (!this.cache.TryGetValue(CACHEKEY + username, out returnContext))
{
var dbuser = await this.getUserByUsernameQuery.Execute(username);
if (dbuser == null)
{
throw new NullReferenceException("Username " + username + " not found in user table. Please run AD update or insert user manually.");
}
returnContext = new UserContext()
{
Username = username,
UserContextObject = context.User,
UserId = dbuser.UserId,
};
this.cache.Set(CACHEKEY + username, returnContext);
}
return returnContext;
}
/// <summary>
/// Splits the username out of a Domain//Username.
/// </summary>
/// <param name="context">The current Http Context.</param>
/// <returns>The username of the given http context identity.</returns>
internal string GetUsername(HttpContext context)
{
return context.User.Identities.First().Name.Split("\\")[1];
}
}
最后是getUserByUsername
查询:
public class GetUserDataQuery : IGetUserDataQuery
{
/// <summary>
/// Initializes a new instance of the <see cref="GetUserDataQuery"/> class.
/// </summary>
/// <param name="context">Intranet Context by DI.</param>
public GetUserDataQuery(IntranetContext context)
{
this.Context = context;
}
private IntranetContext Context { get; }
/// <summary>
/// Get the Intranet user context using the users (AD) username.
/// </summary>
/// <param name="username">The username.</param>
/// <returns>The DB user context.</returns>
public async Task<MainUserModel> Execute(string username)
{
var userInformation = await this.Context.VUser.Where(x => x.Username == username).SingleOrDefaultAsync();
var userRights = await this.Context.UserModule.Where(x => x.UserId == userInformation.UserId).Include(x => x.RefModule).ToListAsync();
var userFunctions = await this.Context.UserModuleFunction.Where(x => x.UserId == userInformation.UserId).Include(x => x.RefModuleFunction).ToListAsync();
var memberList = await this.Context.UserGroupMember.Where(x => x.UserId == userInformation.UserId).Include(x => x.UserGroup).ToListAsync();
var isCashier = await this.Context.UserCashbox.Where(x => x.UserId == userInformation.UserId).AnyAsync();
return new MainUserModel(userInformation, userFunctions, userRights, memberList, isCashier);
}
}
即使我做了dbContext
瞬态,检查了忘记的 async/await 关键字甚至嵌套的异步,错误仍然发生。如果您需要更多信息或有任何想法,请告诉我。
解决方案
推荐阅读
- javascript - 即使存在捕获处理程序,也未处理的承诺拒绝
- php - 在 null 上调用成员函数 - 从多对多关系中检索数据
- javascript - 无法从 mongoDB 下载文件(我没有使用 gridfs)
- actions-on-google - Actions on Google - 在我的 Android 设备上测试我的项目
- pandas - 创建一个基于现有 DateTimeIndex 值的列表
- pycharm - Pycharm 不会为“for”循环自动添加缩进
- app-store - Apple 应用隐私数据收集:如果我们要求用户的电子邮件在应用中创建帐户,这是否算作“收集”电子邮件地址?
- java - 使用 ical 在活动和邀请中具有不同的内容
- javascript - 从 Redux Saga 调用 Promise.all 中的方法
- html - 我可以用什么替换“-moz-column-count”和“-webkit-column-count”?