locked
Blazor (Server App) - System.InvalidOperationException: 'A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext RRS feed

  • Question

  • User135423268 posted

    Good Day Everyone

    IDE: Visual Studio 2019

    Version 16.9

    Project: Blazor Server Application

    ORM: Entity Framwork Core

    SQL Server: MS SQL Server 2016

    I'm currently learning and practicing Blazor Server Application and Entity Framework, but I'm having a error below

    "System.InvalidOperationException: 'A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.'"

    I have created mutliple services for my application, see the codes below.

    Start Up:

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using MyBlazorAppPractice.Data;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace MyBlazorAppPractice
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
            public void ConfigureServices(IServiceCollection services)
                {
                    services.AddRazorPages();
                services.AddServerSideBlazor();
    
    
    
                services.AddScoped<EmployeeServices>();
                services.AddScoped<StoredProcServices>();
                services.AddScoped<StatusServices>();
                services.AddScoped<ActiveService>();
    
                services.AddDbContext<AppDBContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("TestDBConnection")));
    
    
    
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Error");
                }
    
                app.UseStaticFiles();
    
                app.UseRouting();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapBlazorHub();
                    endpoints.MapFallbackToPage("/_Host");
                });
            }
        }
    }
    

    My services

    Employee Services

    using MyBlazorAppPractice.Data;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace MyBlazorAppPractice.Data
    {
        public class EmployeeServices
        {
            private readonly AppDBContext _dbContext;
    
            public EmployeeServices(AppDBContext dbContext)
            {
                _dbContext = dbContext;
            }
    
            public List<Employees> GetEmployees()
            {
                var emplist = _dbContext.Employees.ToList();
                return emplist;
            }
    
            public string AddEmployee(Employees employees)
            {
                try
                {
                    _dbContext.Employees.Add(employees);
                    _dbContext.SaveChanges();
                    return "Save Success";
                }
                catch (Exception ex)
                {
                    string GetError = ex.Message;
                    return "ERROR";
                }
    
            }
    
            public Employees GetEmployeeByID(string id)
            {
                Employees employees = _dbContext.Employees.FirstOrDefault(s => s.EmployeeCode == id);
                return employees;
            }
    
            public string UpdateEmployee(Employees employees)
            {
                try
                {
                    _dbContext.Employees.Update(employees);
                    _dbContext.SaveChanges();
                    return "Save Success";
                }
                catch (Exception ex)
                {
                    string GetError = ex.Message;
                    return "ERROR";
                }
    
            }
    
            public string DeleteEmployee(string EmployeeCode)
            {
                try
                {
                    Employees employees = _dbContext.Employees.Find(EmployeeCode);
                    if (employees != null)
                    {
                        _dbContext.Employees.Remove(employees);
                        _dbContext.SaveChanges();
    
                    }
                    return "SUCCESS";
                }
                catch (Exception ex)
                {
                    string GetError = ex.Message;
                    return "ERROR";
                }
    
            }
    
        }
    }
    

    StatusServices

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace MyBlazorAppPractice.Data
    {
        
        public class StatusServices
        {
            private readonly AppDBContext _dbContext;
    
            public StatusServices(AppDBContext dbContext)
            {
                _dbContext = dbContext;
            }
    
            public List<Status> GetStatuses()
            {
                var statuslist = _dbContext.Status.ToList();
                return statuslist;
            }
    
            public string AddStatus(Status status)
            {
                try
                {
                    _dbContext.Status.Add(status);
                    _dbContext.SaveChanges();
                    return "SAVE SUCCESS";
                }
                catch(Exception ex)
                {
                    string GetError = ex.Message;
                    return "ERROR";
                }
            }
    
        }
    }
    

    StoredProcServices

    using Microsoft.EntityFrameworkCore;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace MyBlazorAppPractice.Data
    {
        public class StoredProcServices
        {
    
            private readonly AppDBContext _dbContext;
    
            public StoredProcServices(AppDBContext dBContext)
            {
                _dbContext = dBContext;
            }
    
            public string GetNewEmpCode()
            {
                string GNewEmpCode = "";
                
                try
                {
                    List<sp_GenEmpCode> GList;
                    string SqlStr = "exec sp_GenEmpCode";
                    GList = _dbContext.sp_GenEmpCodes.FromSqlRaw<sp_GenEmpCode>(SqlStr).ToList();
                    GNewEmpCode = GList[0].NewEmpCode.ToString();
                    return GNewEmpCode;
                }
                catch(Exception ex)
                {
                    string ExMsg = ex.Message;
                    return GNewEmpCode = null;
                }
                
            }
    
        }
    }
    

    ActiveService

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace MyBlazorAppPractice.Data
    {
        public class ActiveService
        {
            private List<GActive> _Active;
    
            public List<GActive> GetIsActive()
            {
                _Active = new List<GActive>() { new GActive() { Active = "True" },
                                               new GActive() { Active = "False"} };
    
                return _Active;
            }
        }
    }
    

    and my AppDbContext

    using Microsoft.EntityFrameworkCore;
    using MyBlazorAppPractice.Data;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace MyBlazorAppPractice.Data
    {
        public class AppDBContext:DbContext
        {
            public AppDBContext(DbContextOptions<AppDBContext> options)
                : base(options)
            {
    
            }
    
            public DbSet<Employees> Employees { get; set; } 
            public DbSet<Items> Items { get; set; }
    
            public DbSet<Status> Status { get; set; }
    
            public DbSet<sp_GenEmpCode> sp_GenEmpCodes { get; set; }
        }
    }
    

    Code Behind: ComponentBase

        public class CreateEmployeeBase: ComponentBase
        {
            [Inject] EmployeeServices objEmpService { get; set; }
            [Inject] StoredProcServices objSPService { get; set; }
            [Inject] StatusServices objStatService { get; set; }
    
            [Inject] ActiveService objActiveService { get; set; }
            [Inject] NavigationManager NavMan { get; set; }
    
            public Employees objEmp = new Employees();
            public List<Status> objStat = new List<Status>();
            public List<GActive> objActive = new List<GActive>();
            public string StatusName { get; set; }
            public string Active { get; set; }
    
            protected override async Task OnInitializedAsync()
            {
                objActive = await Task.Run(() => objActiveService.GetIsActive());
                objStat = await Task.Run(() => objStatService.GetStatuses());
                await base.OnInitializedAsync();
            }
    
            protected void SaveEmployee()
            {
                
                objEmp.EmployeeCode = objSPService.GetNewEmpCode();
                objEmp.Status = StatusName;
                objEmp.Active = bool.Parse(Active);
                string GetResult = objEmpService.AddEmployee(objEmp);
    
    
                if(GetResult == "ERROR")
                {
                    
                }
                else
                {
                    NavMan.NavigateTo("EmployeeInfo/" + objEmp.EmployeeCode);
                }
    
            }
    
    
        }

    Am I doing it wrong?? if you need more details just let me know. Thanks

    Edit:

    If my problem on this cannot be solved, I might get back to using ADO.NET (Microsoft.Data.SqlClient), I know everyone might tell me to use WebAPI , but currently at our company we can only use webapi that can be used globally, or methods/module that can be used by one and more web applications, making a webapi for 1 projects makes us to deploy 2 web instance on our IIS, which currently we have limits on numbers of IP address, that's why I'm practicing and learning the blazor to have his own CRUD inside it's application.

    Tuesday, March 16, 2021 2:39 AM

Answers

  • User135423268 posted

    Hi Everyone

    I noticed that there is no one response here, though a friend of mine teach me how to fix this, and the answer is using Asynchronous programming, here's a sample code.

        public class EmployeeServices
        {
            private readonly AppDBContext _dbContext;
    
            public EmployeeServices(AppDBContext dbContext)
            {
                _dbContext = dbContext;
            }
    
            public async Task<List<Employees>> GetEmployees()
            {
                return await _dbContext.Employees.ToListAsync();
    
            }
    
            public async Task<Employees> GetEmployeeByID(string id)
            {
                return await _dbContext.Employees.FindAsync(id);
                
            }
    
            public async Task<string> AddEmployee(Employees employees)
            {
                try
                {
                    _dbContext.Employees.Add(employees);
                    await _dbContext.SaveChangesAsync();
                    return "SUCCESS";
                }
                catch (Exception ex)
                {
                    string GetError = ex.Message;
                    return "ERROR";
                }
    
            }
    
    
    
            public async Task<string> UpdateEmployee(Employees employees)
            {
                try
                {
                    _dbContext.Employees.Update(employees);
                    await _dbContext.SaveChangesAsync();
                    return "SUCCESS";
                }
                catch (Exception ex)
                {
                    string GetError = ex.Message;
                    return "ERROR";
                }
    
            }
    
            public async Task<string> DeleteEmployee(string EmployeeCode)
            {
                try
                {
                    Employees employees = _dbContext.Employees.Find(EmployeeCode);
                    if (employees != null)
                    {
                        _dbContext.Employees.Remove(employees);
                        await _dbContext.SaveChangesAsync();
    
                    }
                    return "SUCCESS";
                }
                catch (Exception ex)
                {
                    string GetError = ex.Message;
                    return "ERROR";
                }
    
            }
    
        }
    }

    If you have any questions kindly let me know.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, March 24, 2021 1:32 AM