最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

asp.net core mvc - An operation started on this context before a previous operation completed - Stack Overflow

programmeradmin2浏览0评论

I am getting an error while running my ASP.NET Core 8 MVC app.

These are my controller methods hit by Ajax calls by Kendo controls:

public List<Location> GetLocations()
{
    return _db.Locations.ToList();  
}

public List<Region> GetRegions()
{
    return _db.Regions.ToList();
}

Now as the MS documentation says, it's because of database operations happening at the same time.

When I change the code to the following, it works:

public async Task<List<Location>> GetRegions()
{
    return _db.Locations.ToList(); 
}

public async Task<List<Region>> GetRegions()
{
    return _db.Regions.ToList();
}

I don't understand how this works. The same code can also hit database at the same time.

My only theory is that, Framework calls them

await GetLocation();
await GetRegion();

Or the framework just holds the new async calls until the executing ones are completed.

But that defeats the purpose of async.

Please let me know.

Thanks in advance

I am getting an error while running my ASP.NET Core 8 MVC app.

These are my controller methods hit by Ajax calls by Kendo controls:

public List<Location> GetLocations()
{
    return _db.Locations.ToList();  
}

public List<Region> GetRegions()
{
    return _db.Regions.ToList();
}

Now as the MS documentation says, it's because of database operations happening at the same time.

When I change the code to the following, it works:

public async Task<List<Location>> GetRegions()
{
    return _db.Locations.ToList(); 
}

public async Task<List<Region>> GetRegions()
{
    return _db.Regions.ToList();
}

I don't understand how this works. The same code can also hit database at the same time.

My only theory is that, Framework calls them

await GetLocation();
await GetRegion();

Or the framework just holds the new async calls until the executing ones are completed.

But that defeats the purpose of async.

Please let me know.

Thanks in advance

Share Improve this question edited Mar 31 at 3:51 marc_s 756k184 gold badges1.4k silver badges1.5k bronze badges asked Mar 30 at 23:38 GulumalGulumal 612 silver badges8 bronze badges 5
  • How is _db defined and created? Are you using DI (dependency injection) to create it? – Peter B Commented Mar 31 at 0:35
  • You might take a look at this case about ef core dbcontext not thread-safe. It also refernces this section. By the way, I think you need to use await _db.xx.ToListAsync(); instead of ToList() – Tiny Wang Commented Mar 31 at 7:35
  • About why just setting Task as response could resolve the issue --> this is due to how asp core handles task. – Tiny Wang Commented Mar 31 at 10:14
  • @PeterB Its injected. builder.Services.AddDbContext<DBContext>(options => options.UseSqlServer(connectionString)); yes DI. – Gulumal Commented Mar 31 at 11:44
  • @TinyWang your first response makes sense. Second response: Does it say anywhere in MS documentation, its how core handle tasks? If its working by fluke, it might fail sooner or later. – Gulumal Commented Mar 31 at 11:49
Add a comment  | 

2 Answers 2

Reset to default 0

I had a test within my 8 MVC app, I created a button click event handler which would send 2 ajax requests to call my controller action. These 2 requests will call 2 methods like what you shared but I didn't get your exception. Based on my log, I can also see that the 2 requests has 2 different session ids.

private readonly ApplicationDbContext _context;
 private readonly ILogger<MoviesController> _logger;

 public MoviesController(ApplicationDbContext context, ILogger<MoviesController> logger)
 {
     _context = context;
     _logger = logger;
 }

public string test1() {
    var sessionId = HttpContext.Session.Id;
    _logger.LogError("sessionId is =====================: "+sessionId);
    GetMovie();
    return "success1";
}

public string test2()
{
    var sessionId = HttpContext.Session.Id;
    _logger.LogError("sessionId2 is =====================: " + sessionId);
    GetMovieDesc();
    return "success2";
}

public List<Movie> GetMovie()
{
    return _context.Movie.ToList();
}

public List<MovieDesc> GetMovieDesc()
{
    return _context.MovieDesc.ToList();
}

Based on this section, we know that we should avoid using the same DbContext instance to run multiple parallel operations as DbContext is not thread safe. Therefore I deduce you are using the same _db instance to get your data from database. To resolve the issue, following the document:

always await async calls immediately, or use separate DbContext instances for operations that execute in parallel

The reason why your code could work only change the response type to asyn Task without changing to use await _db.Locations.ToListAsync(); shall relate to how .Net core handle tasks, if we don't add await but only return Task, your app will return the Task object immediately, and ASP.NET Core awaits it later --> you have await GetLocation(); which will wait for task completion as well. While both setting await and Task, it will wait for the task to complete inside the method, then return the result. I didn't find official MS document explained it, but I find this case. I trust it could help to understand.

@Tiny Wang

You can reproduce it with following code in a form.

 @(Html.Kendo().DropDownListFor(c => c.reg)
     .Filter(FilterType.Contains)
     .OptionLabel("Please select a region...")
     .DataTextField("RegName")
     .DataValueField("RegID")
     .Events( e=>e.Change("onRegionChange"))
     .DataSource(source =>
     {
         source.Read(read =>
         {
             read.Action("GetRegions", "Location");
         });
     })
     )

 @Html.HiddenFor(m => m.LocationId)
 @(
     Html.Kendo().DropDownListFor(c => Location)
         .Filter(FilterType.Contains)
         .OptionLabel("Please select an office...")
         .DataTextField("OfficeName")
         .DataValueField("OfficeId")
         .Events(e => e.Change("changeDefLocation"))
         .AutoBind(true)
         .DataSource(source =>
         {
             source.Read(read =>
             {
             read.Action("GetLocations", "Location").Data("additionalInfo");
             });
     })
     )


@(Html.Kendo().MultiSelectFor(m => m.OtherLocation)
    .DataTextField("OfficeName")
    .DataValueField("OfficeId")
    .DataSource(dataSource =>
    dataSource.Read(x => x.Action("GetLocationss", "Location").Data("sdaAndLocinfo"))
    .ServerFiltering(false)
    )
    .Events( x=>x.Change("OnOfficeChange"))
    .AutoBind(true)
    )
     
发布评论

评论列表(0)

  1. 暂无评论