asp.net core 在前一个操作完成之前在此上下文上启动了第二个操作

Posted

技术标签:

【中文标题】asp.net core 在前一个操作完成之前在此上下文上启动了第二个操作【英文标题】:asp.net core A second operation started on this context before a previous operation completed 【发布时间】:2018-11-07 00:36:02 【问题描述】:

我有一个 ASP.Net Core 2 Web 应用程序。

我正在尝试创建自定义路由中间件,以便可以从数据库中获取路由。

在 ConfigureServices 我有:

services.AddDbContext<DbContext>(options => options.Usemysql(configuration.GetConnectionString("ConnectionClient")));
services.AddScoped<IServiceConfig, ServiceConfig>();

在配置中:

        app.UseMvc(routes =>
        
            routes.Routes.Add(new RouteCustom(routes.DefaultHandler);
            routes.MapRoute(name: "default", template: "controller=Home/action=Index/id?");
        );

在 RouteCustom 中

public class RouteCustom : IRouteCustom

    private readonly IRouter _innerRouter;
    private IServiceConfig _serviceConfig;

    public RouteCustom(IRouter innerRouter)
    
        _innerRouter = innerRouter ?? throw new ArgumentNullException(nameof(innerRouter));
    

    public async Task RouteAsync(RouteContext context)
    
        _serviceConfig = context.HttpContext.RequestServices.GetRequiredService<IServiceConfig>();
        ...
        Operations inside _serviceConfig to get the route
    

    public VirtualPathData GetVirtualPath(VirtualPathContext context)
    
        _serviceConfig = context.HttpContext.RequestServices.GetRequiredService<IServiceConfig>();
        ...
        Operations inside _serviceConfig to get the route
    

IServiceConfig 它只是我访问数据库以获取数据的一个类,在这种情况下是路由,还有应用程序所需的其他配置数据。

public interface IServiceConfig

    Config GetConfig();
    List<RouteWeb> SelRoutesWeb();


public class ServiceConfig : IServiceConfig

    private readonly IMemoryCache _memoryCache;
    private readonly IUnitOfWork _unitOfWork;
    private readonly IServiceTenant _serviceTenant;

    public ServiceConfig(IMemoryCache memoryCache, IUnitOfWork unitOfWork, IServiceTenant serviceTenant)
    
        _memoryCache = memoryCache;
        _unitOfWork = unitOfWork;
        _serviceTenant = serviceTenant;
    


    public Config GetConfig()
    
        var cacheConfigTenant = Names.CacheConfig + _serviceTenant.GetId();

        var config = _memoryCache.Get<Config>(cacheConfigTenant);
        if (config != null) return config;

        config = _unitOfWork.Config.Get();
        _memoryCache.Set(cacheConfigTenant, config, new MemoryCacheEntryOptions()  SlidingExpiration = Names.CacheExpiration );

        return config;
    


    public List<RouteWeb> SelRoutesWeb()
    
        var cacheRoutesWebTenant = Names.CacheRoutesWeb + _serviceTenant.GetId();

        var routesWebList = _memoryCache.Get<List<RouteWeb>>(cacheRoutesWebTenant);
        if (routesWebList != null) return routesWebList;

        routesWebList = _unitOfWork.PageWeb.SelRoutesWeb();
        _memoryCache.Set(cacheRoutesWebTenant, routesWebList, new MemoryCacheEntryOptions()  SlidingExpiration = Names.CacheExpiration );

        return routesWebList;
    

问题是我在打开多个标签进行测试并尝试同时刷新所有标签时收到此消息: "在前一个操作完成之前,在此上下文中启动了第二个操作"

我确定我做错了什么,但我不知道是什么。它必须是访问自定义路由中间件中的数据库的更好方法,甚至是更好的方法。

例如,在常规中间件(不是路由中间件)上,我可以将依赖项注入 Invoke 函数,但我不能在此处将依赖项注入 RouteAsync 或 GetVirtualPath。

这里会发生什么?

提前致谢。

更新 这些是我得到的例外。我认为是相关的......

An unhandled exception occurred while processing the request.
InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.

Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()
Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider+ExceptionInterceptor+EnumeratorExceptionInterceptor.MoveNext()
System.Collections.Generic.List.AddEnumerable(IEnumerable<T> enumerable)
System.Linq.Enumerable.ToList<TSource>(IEnumerable<TSource> source)
MyProject.Repository.Repositories.PageWebRepository.SelRoutesWeb() in PageWebRepository.cs
+
            return Context.PagesWebTrs.Include(p => p.PageWeb).Where(p => p.PageWeb.Active)
MyProject.Web.AppControl.ServiceConfig.SelRoutesWeb() in ServiceConfig.cs
+
            routesWebList = _unitOfWork.PageWeb.SelRoutesWeb();
MyProject.Web.AppConfig.RouteCustom.GetVirtualPath(VirtualPathContext context) in RouteCustom.cs
+
            var routeWeb = _serviceConfig.SelRoutesWeb().FirstOrDefault(p => p.Area == routeInfo.Area && p.Controller == routeInfo.Controller && p.Action == routeInfo.Action && p.LanguageCode == routeInfo.Culture);
Microsoft.AspNetCore.Routing.RouteCollection.GetVirtualPath(VirtualPathContext context, List<IRouter> routes)
Microsoft.AspNetCore.Routing.RouteCollection.GetVirtualPath(VirtualPathContext context)
Microsoft.AspNetCore.Mvc.Routing.UrlHelper.GetVirtualPathData(string routeName, RouteValueDictionary values)
Microsoft.AspNetCore.Mvc.Routing.UrlHelper.Action(UrlActionContext actionContext)
Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, string action, string controller, object values, string protocol, string host, string fragment)
Microsoft.AspNetCore.Mvc.UrlHelperExtensions.Action(IUrlHelper helper, string action, string controller, object values)
Microsoft.AspNetCore.Mvc.ViewFeatures.DefaulthtmlGenerator.GenerateForm(ViewContext viewContext, string actionName, string controllerName, object routeValues, string method, object htmlAttributes)
Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGeneratorExtensions.GenerateForm(IHtmlGenerator generator, ViewContext viewContext, string actionName, string controllerName, string fragment, object routeValues, string method, object htmlAttributes)
Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper.Process(TagHelperContext context, TagHelperOutput output)
Microsoft.AspNetCore.Razor.TagHelpers.TagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner+<RunAsync>d__0.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
AspNetCore._Views_Contents_NewsList_cshtml+<ExecuteAsync>d__21.MoveNext() in NewsList.cshtml
+
    <h1>@Model.BasePage.PageTitle</h1>
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Razor.RazorView+<RenderPageCoreAsync>d__16.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Razor.RazorView+<RenderPageAsync>d__15.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Mvc.Razor.RazorView+<RenderAsync>d__14.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor+<ExecuteAsync>d__22.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor+<ExecuteAsync>d__21.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.ViewResult+<ExecuteResultAsync>d__26.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeResultAsync>d__19.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeNextResultFilterAsync>d__24.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeNextResourceFilter>d__22.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeFilterPipelineAsync>d__17.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeAsync>d__15.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Builder.RouterMiddleware+<Invoke>d__4.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+<Invoke>d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
MyProject.Web.AppConfig.TenantMiddleware+<Invoke>d__3.MoveNext() in Tenant.cs
+
            await _next.Invoke(httpContext);
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+<Invoke>d__7.MoveNext()

还有这个:

An unhandled exception occurred while processing the request.
MySqlException: There is already an open DataReader associated with this Connection which must be closed first.
MySql.Data.MySqlClient.Interceptors.ExceptionInterceptor.Throw(Exception exception)

Stack Query Cookies Headers
MySqlException: There is already an open DataReader associated with this Connection which must be closed first.
MySql.Data.MySqlClient.Interceptors.ExceptionInterceptor.Throw(Exception exception)
MySql.Data.MySqlClient.MySqlCommand.Throw(Exception ex)
MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
System.Data.Common.DbCommand.ExecuteReader()
Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary<string, object> parameterValues)
Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary<string, object> parameterValues)
Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable+Enumerator.BufferlessMoveNext(bool buffer)
Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable+Enumerator.MoveNext()
Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.GetResult<TResult>(IEnumerable<ValueBuffer> valueBuffers, bool throwOnNullResult)
lambda_method(Closure , QueryContext )
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler+<>c__DisplayClass17_1.<CompileQueryCore>b__0(QueryContext qc)
System.Linq.Queryable.Count<TSource>(IQueryable<TSource> source)
X.PagedList.PagedList..ctor(IQueryable<T> superset, int pageNumber, int pageSize)
X.PagedList.PagedListExtensions.ToPagedList<T>(IEnumerable<T> superset, int pageNumber, int pageSize)
MyProject.Repository.Repositories.LinkRepository.SelSearchWeb(string searchText, int pageNumber, int pageSize) in LinkRepository.cs
+
            return Context.LinksTrs.Include(p => p.Link)
MyProject.Web.Controllers.ContentsController.LinksList(LinksSearchModelWeb searchModel) in ContentsController.cs
+
            var items = _unitOfWork.Link.SelSearchWeb(searchModel.SearchText, searchModel.PageNumber ?? 1, searchModel.PageSize ?? 10);
lambda_method(Closure , object , Object[] )
Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(object target, Object[] parameters)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeActionMethodAsync>d__12.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeNextActionFilterAsync>d__10.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeInnerFilterAsync>d__14.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeNextResourceFilter>d__22.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeFilterPipelineAsync>d__17.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeAsync>d__15.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Builder.RouterMiddleware+<Invoke>d__4.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+<Invoke>d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
MyProject.Web.AppConfig.TenantMiddleware+<Invoke>d__3.MoveNext() in Tenant.cs
+
            await _next.Invoke(httpContext);
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+<Invoke>d__7.MoveNext()

这是工作单元

public interface IUnitOfWork : IDisposable

    ICompanyRepository Company  get; 
    IConfigRepository Config  get; 
    ...

    void Complete();



public class UnitOfWork : IUnitOfWork

    private readonly DbContext _context;

    public UnitOfWork(DbContext context)
    
        _context = context;

        Company = new CompanyRepository(_context);
        Config = new ConfigRepository(_context);
        ...
    

    public ICompanyRepository Company  get; private set; 
    public IConfigRepository Config  get; private set; 
    ...

    public void Complete()
    
        _context.SaveChanges();
    

    public void Dispose()
    
        _context.Dispose();
    

更新

在查看 cmets 并进行大量测试后,我得到的最好线索是当我删除 CustomRoute 行时问题消失了。从 Startup.cs 上的 Configure 函数中删除此行

routes.Routes.Add(new RouteCustom(routes.DefaultHandler));

我也尝试过删除,首先是 RouteAsync,然后是 GetVirtualPath 方法,但如果其中一个方法存在,我会收到错误消息,因此很明显问题出在这个 CustomRoute 类中。

在针对任何请求首先调用的 TenantMiddleware 中,我正在注入 UnitOfWork,我没有任何问题。这个中间件是在 Configure 函数中创建的:

app.UseMiddleware<TenantMiddleware>();

在内部,我正在注入 UnitOfWork,并在每个请求中使用它,如下所示:

公共异步任务调用(HttpContext httpContext, IServiceTenant serviceTenant) ...执行数据库操作以检索租户的数据。



public class ServiceTenant : IServiceTenant

    public ServiceTenant(IHttpContextAccessor contextAccessor, IMemoryCache memoryCache, IUnitOfWorkMaster unitOfWorkMaster)
    
        _unitOfWorkMaster = unitOfWorkMaster;
    

    ...performing DB operations

所以,CustomRute 的问题是我无法通过像这样添加到 Invoke 函数来注入依赖项:

public async Task Invoke(HttpContext httpContext, IServiceTenant serviceTenant)

所以我必须像这样调用相应的服务(在该服务中注入 UnitOfWork 并执行数据库操作),我认为这可能是导致问题的原因:

public async Task RouteAsync(RouteContext context)

    _serviceConfig = context.HttpContext.RequestServices.GetRequiredService<IServiceConfig>();
    ....

因为这是我知道将 IServiceConfig “注入”到 RouteAsync 和 GetVirtualPath 中的唯一方法...

另外,我在每个控制器中都这样做,因为我使用的是 BaseCONtroller,所以我决定使用哪个操作系统的注入服务...

public class BaseWebController : Controller

    private readonly IMemoryCache _memoryCache;
    private readonly IUnitOfWork _unitOfWork;
    private readonly IUnitOfWorkMaster _unitOfWorkMaster;
    private readonly IServiceConfig _serviceConfig;
    private readonly IServiceFiles _serviceFiles;
    private readonly IServiceFilesData _serviceFilesData;
    private readonly IServiceTenant _serviceTenant;

    public BaseWebController(IServiceProvider serviceProvider)
    
        _memoryCache = serviceProvider.GetRequiredService<IMemoryCache>();
        _unitOfWork = serviceProvider.GetRequiredService<IUnitOfWork>();
        _unitOfWorkMaster = serviceProvider.GetRequiredService<IUnitOfWorkMaster>();
        _serviceConfig = serviceProvider.GetRequiredService<IServiceConfig>();
        _serviceFiles = serviceProvider.GetRequiredService<IServiceFiles>();
        _serviceFilesData = serviceProvider.GetRequiredService<IServiceFilesData>();
        _serviceTenant = serviceProvider.GetRequiredService<IServiceTenant>();        
    ...

然后在每个控制器中,我可以只为我需要的那些服务而不是引用所有注入的服务,如下所示:

public class HomeController : BaseWebController

    private readonly IUnitOfWork _unitOfWork;

    public HomeController(IServiceProvider serviceProvider) : base(serviceProvider)
    
        _unitOfWork = serviceProvider.GetRequiredService<IUnitOfWork>();
    

    public IActionResult Index()
    
        ...
    

我不知道这是否与我的问题有关,但我只是向您展示我认为可能存在的问题,以便您了解更多信息。

谢谢。

更新

这是检索路由的数据库代码:

public class PageWebRepository : Repository<PageWeb>, IPageWebRepository

    public PageWebRepository(DbContext context) : base(context)  


    public List<RouteWeb> SelRoutesWeb()
    
        return Context.PagesWebTrs.Include(p => p.PageWeb).Where(p => p.PageWeb.Active)
            .Select(p => new RouteWeb
            
                PageWebId = p.PageWebId,
                LanguageCode = p.LanguageCode,
                Route = p.Route,
                Regex = p.PageWeb.Regex.Replace("<route>", p.Route),
                Params = p.PageWeb.Params,
                Area = p.PageWeb.Area,
                Controller = p.PageWeb.Controller,
                Action = p.PageWeb.Action,
                Type = p.PageWeb.Type,
                Sidebar = p.PageWeb.Sidebar,
                BannerIsScript = p.PageWeb.BannerIsScript,
                Title = p.Title,
                Description = p.Description,
                Keywords = p.Keywords,
                ScriptHead = p.ScriptHead,
                ScriptBody = p.ScriptBody,
                BannerScript = p.BannerScript,
                BannerUrl = p.BannerUrl,
            ).ToList();
    

其中 PagesWebTrs 是页面的翻译(多语言),PagesWeb 是主表。

【问题讨论】:

请发布异常的完整堆栈跟踪以及所有其内部异常 谢谢 Steven,我已经用完整的堆栈跟踪更新了我的问题 你能展示一下 IUnitOgWork 的实现吗? 我已经用 IUnitOfWork 更新了我的问题 似乎同一个 DbContext 实例同时在 2 个不同的地方或线程中以某种方式被访问 【参考方案1】:

这个问题确实在路由中间件内部。

根据定义,中间件是一个单例,因此单个实​​例处理所有请求。这导致实例状态(the IServiceConfigwith hooked up DbContext)被多个同时请求访问和更改;这是一个伪装得很好的经典并发问题。

一个例子。

请求 A 执行 RouteAsync,设置 _serviceConfig 并在 DbContext 上执行查询。纳秒(或更少:))之后,请求 B 也会这样做。在执行请求 B 的查询时,请求 A 执行 GetVirtualPath,但这次在请求 B 设置的 DbContext 上执行。这导致在请求 B 的 DbContext 上执行第二个查询,该查询仍然有一个正在运行并且你得到提到的错误。

解决方案是通过在每个方法的开头检索IServiceConfig 来防止共享状态。

正如你已经说过的,通过Invoke 方法注入这样的依赖是行不通的; Invoke方法没有被执行。

下面是修改后的RouteCustom

public class RouteCustom : IRouteCustom

    private readonly IRouter _innerRouter;

    public RouteCustom(IRouter innerRouter)
    
        _innerRouter = innerRouter ?? throw new ArgumentNullException(nameof(innerRouter));
    

    public async Task RouteAsync(RouteContext context)
    
        var serviceConfig = context.HttpContext.RequestServices.GetRequiredService<IServiceConfig>();
        // ...

    

    public VirtualPathData GetVirtualPath(VirtualPathContext context)
    
        var serviceConfig = context.HttpContext.RequestServices.GetRequiredService<IServiceConfig>();
        // ...

    

【讨论】:

您给我的解决方案不仅有效(我必须做更多测试),而且您还给了我一个解释。我不知道中间件是这样工作的。非常感谢。

以上是关于asp.net core 在前一个操作完成之前在此上下文上启动了第二个操作的主要内容,如果未能解决你的问题,请参考以下文章

使用依赖注入时,如何修复“在前一个操作完成之前在此上下文中启动的第二个操作......”?

Blazor:在前一个操作完成之前在此上下文上启动了第二个操作

UserManager 错误 - 在前一个异步操作完成之前在此上下文上启动了第二个操作

UserManager 错误“在前一个操作完成之前在此上下文上启动了第二个操作”

EF 错误:在前一个异步操作完成之前在此上下文上启动了第二个操作

在前一个异步操作完成之前,在此上下文上启动了第二个操作。使用“等待”来确保