Answered by:
Why does my web application hang up on "await _context.SaveChangesAsync();"

Question
-
User-1849651236 posted
Hello,
I have an Asp.Net Core 2.1, MVC, C# Web application in Visual Studio 2017 15.7.5. My Nuget packages show that I am using Microsoft.EntityFrameworkCore.Tools 2.1.1.
In my coding shown at the end of this post, my program hangs up on this statement:
await _context.SaveChangesAsync();
and never returns control to the next statement. I used the Visual Studio debugger to stop on the statement after that one and waited ten minutes. It never gave control back.
I also tried it this way and got the same results:
_context.AddRange(productsRootObject.Products); _context.SaveChanges();
Does anyone know how to debug this issue? Is there some log that I can look at?
Thanks,
TonyHere is my code:
public class ProductListViewComponent : ViewComponent { private readonly ChinavasionAPIContext _context; private readonly IHubContext<ChvHub> _hubContext; public ProductListViewComponent(IHubContext<ChvHub> hubcontext, ChinavasionAPIContext context) { _context = context; _hubContext = hubcontext; } #region snippet1 public async Task<IViewComponentResult> InvokeAsync() { //string MyView = "Default"; var items = await GetItemsAsync(); await this._hubContext.Clients.All.SendAsync("ReceiveMessage", "", "=============================================== Ready to Display Lakeside and Chinavasion Products ==============================================="); return View(items); } public async Task<List<ProductViewModel>> GetItemsAsync() { var model = new AccessModel(); model.UserAccessModel = _context.UserAccessModels.Single(a => a.ID == 1); var accessToken = (model.UserAccessModel.AccessToken ?? TempData["accessToken"]).ToString(); var serverUrl = (model.UserAccessModel.ServerUrl ?? TempData["serverUrl"]).ToString(); var nopApiClient = new ApiClient(accessToken, serverUrl); MultipleProductModel multipleProductModel = new MultipleProductModel(); List<Category> categories = new List<Category>(); string jsonUrl = $"/api/products/count"; object productsCount = nopApiClient.Get(jsonUrl); var nopProductsCount = JsonConvert.DeserializeObject<ProductsCount>(productsCount.ToString()); int sinceID = 0; int productCount = 0; await this._hubContext.Clients.All.SendAsync("ReceiveMessage", "", "============================================= Starting Lakeside Product Retrieval from Live Database =============================================="); do { productCount += 1; await this._hubContext.Clients.All.SendAsync("ReceiveMessage", productCount.ToString(), " Downloading Lakeside products"); jsonUrl = $"/api/products?limit=250&since_id=" + sinceID.ToString() + $"&fields=id,sku,name,images,categories"; object productsData = nopApiClient.Get(jsonUrl); var productsRootObject = JsonConvert.DeserializeObject<ProductsRootObject>(productsData.ToString()); multipleProductModel.MProductsApi.AddRange(productsRootObject.Products); await _context.AddRangeAsync(productsRootObject.Products); await _context.SaveChangesAsync(); var last = multipleProductModel.MProductsApi.LastOrDefault(); sinceID = Convert.ToInt16(last.Id); } while (multipleProductModel.MProductsApi.Count < nopProductsCount.Count); }
using System.Collections.Generic; using Newtonsoft.Json; namespace ChinavasionAPI.DTOs { public class ProductsRootObject { [JsonProperty("products")] public List<ProductApi> Products { get; set; } } }
using Newtonsoft.Json; using System.Collections.Generic; { public class ProductApi { [JsonProperty("id")] public string Id { get; set; } [JsonProperty("sku")] public string Sku { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("images")] public List<Image> Images { get; set; } [JsonProperty("categories")] public string Categories { get; set; } } public class Image { [JsonProperty("id")] public int Id { get; set; } [JsonProperty("position")] public int Position { get; set; } [JsonProperty("src")] public string Src { get; set; } [JsonProperty("attachment")] public string Attachment { get; set; } } }
using System.Collections.Generic; using ChinavasionAPI.DTOs; namespace ChinavasionAPI.Models.CAPIViewModels { public class MultipleProductModel { public List<ProductApi> MProductsApi { get; set; } public List<Product> MProducts { get; set; } public MultipleProductModel() { this.MProductsApi = new List<ProductApi>(); this.MProducts = new List<Product>(); } } }
Friday, August 3, 2018 12:30 PM
Answers
-
User-1849651236 posted
Wenushka,
Your suggested change did not work.
I put in a try/catch on the code where it was hanging up. I saw this error:
An error occurred while updating the entries. See the inner exception for details. Cannot insert explicit value for identity column in table 'ProductApis' when IDENTITY_INSERT is set to OFF.
After Googling that error, I found articles that suggested putting this annotation:
[DatabaseGenerated(DatabaseGeneratedOption.None)]
on the Id properties for the ProductApi and Image models.
That allowed me to run the program without getting the hangup and it populated the tables.
I very much appreciate your help in trying to fix this issue.
Thanks,
Tony- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, August 9, 2018 2:11 PM
All replies
-
User1881638666 posted
Hi TGirgenti,
If there is blocking call inside asynchronous call / path, it could cause deadlock if the both the threads waiting for each other to complete (SynchronizationContext).
This is what happened in your asp.net mvc application.
There is a blocking (sync) call in your method,
object productsData = nopApiClient.Get(jsonUrl);
Fix this, by calling the asynchronous version of the method if available. eg: await nopApiClient.GetAsync(jsonUrl) ;
Note : Fix the both two places where you called blocking Get method inside the method.
Further go through the followings,
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
https://gist.github.com/jonlabelle/841146854b23b305b50fa5542f84b20c
Thanks,
Wenushka
Sunday, August 5, 2018 5:42 AM -
User-1849651236 posted
Hello Wenushka.
Thanks for your help with this issue.
There is one thing that I am confused about. If the blocking call is causing the problem when it gets to this:
await _context.SaveChangesAsync();
why does it not hangup on the await prior to that one?
await _context.AddRangeAsync(productsRootObject.Products);
I will read the information you pointed out and I will try to make the blocking Get you pointed out to an await
Thanks,
TonySunday, August 5, 2018 4:55 PM -
User-1849651236 posted
Hello Wenushka.
I tried your idea of making the calling of the asynchronous version of the methods and it did not work.
I changed all of my methods to public async Task and it still hangs up on "await _context.SaveChangesAsync();"
Does anyone have any idea of how to fix this problem?
Thanks,
TonyTuesday, August 7, 2018 2:33 AM -
User1881638666 posted
Hi TGirgenti,
Could you share the implementation of the ,
ChinavasionAPIContext context
or two methods of that class,
await _context.AddRangeAsync(productsRootObject.Products); await _context.SaveChangesAsync();
Thanks,
Wenushka
Tuesday, August 7, 2018 5:05 AM -
User-1849651236 posted
Wenushka,
Here is my context file:
using ChinavasionAPI.Models; using Microsoft.EntityFrameworkCore; namespace ChinavasionAPI.Data { public class ChinavasionAPIContext : DbContext { public ChinavasionAPIContext (DbContextOptions<ChinavasionAPIContext> options) : base(options) { } public DbSet<ChinavasionAPI.Models.QueryCall> QueryCalls { get; set; } public DbSet<ChinavasionAPI.Models.Setup> Setups { get; set; } public DbSet<ChinavasionAPI.Models.QueryAssignment> QueryAssignments { get; set; } public DbSet<ChinavasionAPI.Models.UserAccessModel> UserAccessModels { get; set; } public DbSet<ChinavasionAPI.DTOs.ProductApi> ProductApis { get; set; } public DbSet<ChinavasionAPI.DTOs.Image> Images { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<QueryCall>().ToTable("QueryCall"); modelBuilder.Entity<Setup>().ToTable("Setup"); modelBuilder.Entity<UserAccessModel>().ToTable("UserAccessModel"); modelBuilder.Entity<QueryAssignment>().ToTable("QueryAssignment"); modelBuilder.Entity<QueryAssignment>() .HasKey(q => new { q.QueryID, q.SetupID }); } } }
Thanks for your help.
Tony
Tuesday, August 7, 2018 12:59 PM -
User1881638666 posted
hi TGirgenti,
Change how the entities is added before committing the changes to db.
Change,
await _context.AddRangeAsync(productsRootObject.Products);
with,
_context.ProductApis.AddRange(productsRootObject.Products);
Note: In adding the entities, you don't have to call async version of DbContext unless we have special requirement mentioned here.
https://docs.microsoft.com/en-us/ef/core/api/microsoft.entityframeworkcore.dbcontext
https://docs.microsoft.com/en-us/ef/core/api/microsoft.entityframeworkcore.dbset-1
Finally, commit the changes as usual with the,
await _context.SaveChangesAsync();
Wednesday, August 8, 2018 9:02 AM -
User-1849651236 posted
Wenushka,
Your suggested change did not work.
I put in a try/catch on the code where it was hanging up. I saw this error:
An error occurred while updating the entries. See the inner exception for details. Cannot insert explicit value for identity column in table 'ProductApis' when IDENTITY_INSERT is set to OFF.
After Googling that error, I found articles that suggested putting this annotation:
[DatabaseGenerated(DatabaseGeneratedOption.None)]
on the Id properties for the ProductApi and Image models.
That allowed me to run the program without getting the hangup and it populated the tables.
I very much appreciate your help in trying to fix this issue.
Thanks,
Tony- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, August 9, 2018 2:11 PM