Search code examples
c#microservicesasp.net-core-webapiasp.net-core-3.1asp.net-core-identity

Cannot access a disposed context instance


My Application: .Net Core 3.1 Web application using Microservice architecture; Identity for Authorization & Authentication as separate Microservice API.

I have extended the standard AspNetUsers and AspNetRoles table with custom fields. Getting the following error when I am trying to create a new Role using Identity RoleManager.

Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'MembershipDBContext'.

Find my Code below

Startup.cs

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            var idenConnectionString = Configuration["DbContextSettings:IdentityConnectionString"];
            var userConnectionString = Configuration["DbContextSettings:UserConnectionString"];
            var dbPassword = Configuration["DbContextSettings:DbPassword"];
            var builder = new NpgsqlConnectionStringBuilder(idenConnectionString)
            {
                Password = dbPassword
            };
            var userBuilder = new NpgsqlConnectionStringBuilder(userConnectionString)
            {
                Password = dbPassword
            };

            services.AddDbContext<MembershipDBContext>(opts => opts.UseNpgsql(builder.ConnectionString));
            services.AddDbContext<UserDBContext>(opts => opts.UseNpgsql(userBuilder.ConnectionString));

            

            services.AddIdentity<MembershipUser, MembershipRole>(options =>
            {
                options.Password.RequiredLength = 8;
                options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+ ";
                options.SignIn.RequireConfirmedEmail = false;
            }).AddRoles<MembershipRole>().AddEntityFrameworkStores<MembershipDBContext>()
            .AddDefaultTokenProviders();


            services.AddTransient<IIdentityMSService, IdentityMSService>();//IdentityMS
            services.AddTransient<IAdministrationService, AdministrationService>();//IdentityMS

            services.AddTransient<IIdentityMSRepository, IdentityMSRepository>();//IdentityMS
            services.AddTransient<IAdministrationRepository, AdministrationRepository>();//IdentityMS
            services.AddTransient<UserDBContext>();
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
            
            services.AddMediatR(typeof(Startup));
            RegisterServices(services);
        }

MembershipDBContext.cs

    public class MembershipDBContext : IdentityDbContext<MembershipUser,MembershipRole,string>
    {
        public MembershipDBContext(DbContextOptions<MembershipDBContext> options) : base(options)
        {
        }
    }

AdministrationController

 public class AdministrationController : Controller
    {
        private readonly IAdministrationMVCService _adminService;

        public AdministrationController(IAdministrationMVCService adminService)
        {
            _adminService = adminService;            
        }

        // GET: AdministrationController/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: AdministrationController/Create
        [HttpPost]
        //[ValidateAntiForgeryToken]
        public async Task<IActionResult> CreateAsync(MembershipRole rm)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    rm.CompanyId = 1;
                    await _adminService.AddRoles(rm);
                    //return RedirectToAction(nameof(Index));
                    return View();
                }
                catch
                {
                    return View();
                }
            }
            return View();
        }

      
    }

AdministrationApiController

[HttpPost]
        public void Post([FromBody] MembershipRole role)
        {
            _adminMSService.AddRoles(role);
        }

AdministrationRepository

public class AdministrationRepository : IAdministrationRepository
    {
        private readonly RoleManager<MembershipRole> _roleManager;
        private readonly UserManager<MembershipUser> _userManager;

        public AdministrationRepository(RoleManager<MembershipRole> roleManager, UserManager<MembershipUser> userManager)
        {            
            _roleManager = roleManager;
            _userManager = userManager;
        }

        public async Task AddRolesAsync(MembershipRole rvm)
        {
            try
            {
                IdentityResult result = await _roleManager.CreateAsync(rvm);
                if (result.Succeeded) {

                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }

    }

I tried making the services and repositories as singleton but it didn't work either. What am I missing here? Any insights?


Solution

  • Solved the issue! As DavidG pointed out in his comment, I missed the 'await' keyword at certain places like AdministrationApiController. Posting as an 'Answer' here, as I am unable to mark the comment as 'Answer'.