C# – asp.net core A second operation started on this context before a previous operation completed

asp.net-corecdependency-injectionrouting

I have an ASP.Net Core 2 Web application.

I'm trying to create a custom routing Middleware, so I can get the routes from a database.

In ConfigureServices I have:

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

In Configure:

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

In the 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
    }
}

The IServiceConfig it is just a class where I access the database to get data, in this case the routes, but also othe configuration data I need for the application.

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;
    }
}

The problem is I'm getting this message when I test with multiple tabs opened and try to refresh all at the same time:
"A second operation started on this context before a previous operation completed"

I'm sure there is something I'm doing wrong, but I don't know what. It has to be a better way to access the db inside the custom route middleware or even a better way for doing this.

For example, on a regular Middleware (not the routing one) I can inject the dependencies to the Invoke function, but I can't inject dependencies here to the RouteAsync or the GetVirtualPath.

What can be happening here?

Thanks in advance.

UPDATE
These are the exceptions I'm getting. I think are related…

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()

And this one:

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()

This is the UnitOfWork

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();
    }
}

UPDATE

After reviewing the comments and making a lot of tests, the best clue I have is when I remove the CustomRoute line the problem disapear. Removing this line from Configure function on Startup.cs

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

Also I have tried removing, first the RouteAsync and then the GetVirtualPath methods, but if one of those is present I get an error, so it is clear that the problem is in this CustomRoute class.

In the TenantMiddleware, which is called first for any request, I'm injecting the UnitOfWork and I have no problem. This middleware is create in the Configure function:

app.UseMiddleware<TenantMiddleware>();

And inside, I'm injecting the UnitOfWork, and using it on every request, like this:

public async Task Invoke(HttpContext httpContext, IServiceTenant serviceTenant)
{
…performing DB operations to retrieve the tenent's data.

}

public class ServiceTenant : IServiceTenant
{
    public ServiceTenant(IHttpContextAccessor contextAccessor, IMemoryCache memoryCache, IUnitOfWorkMaster unitOfWorkMaster)
    {
        _unitOfWorkMaster = unitOfWorkMaster;
    }

    ...performing DB operations
}

SO, the problem with the CustomROute is I can't inject the dependencies by adding to the Invoke function like this:

public async Task Invoke(HttpContext httpContext, IServiceTenant serviceTenant)

So I have to call the corresponding Service (Inside that service I inject the UnitOfWork and perform the DB operations) like this, and I think this can be the thing that is causing problems:

public async Task RouteAsync(RouteContext context)
{
    _serviceConfig = context.HttpContext.RequestServices.GetRequiredService<IServiceConfig>();
    ....
}

bacause this is the only way I know to "inject" the IServiceConfig into the RouteAsync and GetVirtualPath…

Also, I'm doing that in every controller since I'm using a BaseCOntroller, so I decide which os the injection services I use…

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>();        }
    ...
}

And then in every controller, instead of referencing all of the injected services, I can do it only for those I need, like this:

public class HomeController : BaseWebController
{
    private readonly IUnitOfWork _unitOfWork;

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

    public IActionResult Index()
    {
        ...
    }
}

I don't know if this has something to do with my problem, but I'm just showing you what I think can be the problem, so you can have more information.

Thanks.

UPDATE

This is the code of the db to retrieve the routes:

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();
    }
}

Where PagesWebTrs are the translations of the pages (multilanguage) and PagesWeb is the main table.

Best Answer

This issue is indeed within the route middleware.

Per definition, a middleware is a singleton, so a single instance handles all requests. This results into the instance state (the IServiceConfigwith hooked up DbContext) being accessed and changed by multiple simultaneous requests; it's a well disguished classical concurrency issue.

An example.

Request A executes RouteAsync, sets the _serviceConfig and executes a query on the DbContext. Nano seconds (or less :)) later, request B does the same. While request B's query is being executed, request A executes GetVirtualPath, but this time on the DbContext set by request B. This results in a second query being executed on the DbContext of request B which still has one running and you get the mentionned error.

The solution is to prevent shared state, by retrieving the IServiceConfig at the start of each method.

As you already said, getting such a dependency injected via the Invoke method does not work; the Invokemethod does not get executed.

Here below is the reworked 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>();
        // ...

    }
}
Related Topic