Ошибка The operation cannot be completed because the DbContext has been disposed

135
12 марта 2021, 07:40

Я решил добавить Ninject в проект из Identity(Проект Web API). Без него все работало нормально. Однако когда я добавил появилась такая проблема:
"The operation cannot be completed because the DbContext has been disposed". Она появляется после первого запроса. Первый запрос работает нормально, но 2 выбивает такую ошибку если это касается Identity. Я сам негде не вызываю метод Dispose().

Код:
Startup:

 public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();
        WebApiConfig.Register(config);
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        AutoMapper.Mapper.Initialize(cfg=>
            {
                cfg.AddProfile(new WebMapperProfile());
                cfg.AddProfile(new BLLMapperProfile());
            }
        );
        var kernel = ConfigureNinject(app, config);
        ConfigureOAuth(app,kernel);
        app.UseWebApi(config);
    }
    public void ConfigureOAuth(IAppBuilder app,IKernel kernel)
    {
        OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = kernel.Get<SimpleAuthorizationServerProvider>()
        };
        // Token Generation
        app.UseOAuthAuthorizationServer(OAuthServerOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    }
    public IKernel ConfigureNinject(IAppBuilder app, HttpConfiguration config)
    {
        var kernel = CreateKernel();
        config.DependencyResolver = new NinjectDependencyResolver(kernel);
        app.UseNinjectMiddleware(()=>kernel);
        //app.UseNinjectWebApi(config);
        return kernel;

    }
    private static StandardKernel CreateKernel()
    {
        var kernel = new StandardKernel(new WebNinjectModule(), new BLLNinjectModule());
        return kernel;
    }

SimpleAuthorizationServerProvider:

IAuthService authService;
    public SimpleAuthorizationServerProvider(IAuthService authService ) {
        this.authService = authService;
    }
    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        context.Validated();
    }
    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        if (!context.OwinContext.Response.Headers.ContainsKey("Access-Control-Allow-Origin"))
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
        List<IdentityRole> roles = new List<IdentityRole>();
        IdentityUser user = await authService.FindUser(context.UserName,context.Password);
        if (user == null)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return; 
        }
        var UserRoles = user.Roles.ToList();
        roles = UserRoles.Select(x=> authService.GetRoleById(x.RoleId)).ToList();
        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim("sub", context.UserName));
        foreach (var role in roles)
        {
            identity.AddClaim(new Claim(ClaimTypes.Role, role.Name));
        }
        context.Validated(identity);
    }
}

AuthService:

    private IUnitOfWork db;
    public AuthService(IUnitOfWork db)
    {
        this.db = db;
    }
    public async Task<IdentityResult> RegisterUser(UserDTO userModel)
    {
        ApplicationUser user = new ApplicationUser() {
            UserName = userModel.UserName
        };
        var result = await db.UserManager.CreateAsync(user, userModel.Password);
        if (result.Succeeded)
        {
            var resUser = await db.UserManager.FindAsync(user.UserName, userModel.Password);
            db.UserManager.AddToRole(resUser.Id, "User");
        }
        return result;
    }
    public async Task<IdentityUser> FindUser(string userName, string password)
    {
        IdentityUser user = await db.UserManager.FindAsync(userName, password);
        return user;
    }
    public async Task<IdentityResult> ChangePassword(string username, string oldpassword, string newPassword)
    {
        IdentityUser user = await db.UserManager.FindAsync(username, oldpassword);
        if (user != null)
        {
           return await db.UserManager.ChangePasswordAsync(user.Id,oldpassword, newPassword);
        }
        return null;
    }
    public IdentityRole GetRoleById(string id) {
        return db.RoleManager.FindById(id);
    }
    public void Dispose()
    {
        db.Dispose();
    }

UnitOfWork:

public class UnitOfWork : IUnitOfWork
{
    EntityContext db;
    AuthContext identityDb;
    private bool disposed = false;
    private IRepository<Product> productRepository;
    private ApplicationUserManager userManager;
    private ApplicationRoleManager roleManager;
    public UnitOfWork(EntityContext db, AuthContext identityDb)
    {
        this.db = db;
        this.identityDb = identityDb;
    }
    public IRepository<Product> Products {
        get
        {
            if (productRepository == null) {
                productRepository = new Repository<Product>(db);
            }
            return productRepository;
        }
    }
    public ApplicationUserManager UserManager {
        get {
            if (userManager == null) {
                userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(identityDb));
            }
            return userManager;
        }
    }
    public ApplicationRoleManager RoleManager
    {
        get
        {
            if (roleManager == null)
            {
                roleManager = new ApplicationRoleManager(new RoleStore<ApplicationRole>(identityDb));
            }
            return roleManager;
        }
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                db.Dispose();
                if(productRepository != null)
                    productRepository.Dispose();
                if (userManager != null)
                    userManager.Dispose();
                if(roleManager != null)
                    roleManager.Dispose();
                identityDb.Dispose();
                db = null;
                identityDb = null;
                productRepository = null;
                userManager = null;
                roleManager = null;
            }
            this.disposed = true;
        }
    }
    public void Save()
    {
        db.SaveChanges();
    }
}

Модуль уровня Web API

 public class WebNinjectModule : NinjectModule
{
    public override void Load() {
        Bind<IAuthService>().To<AuthService>().InRequestScope();
        Bind<IProductService>().To<ProductService>().InRequestScope();
        Bind<SimpleAuthorizationServerProvider>().ToSelf().InRequestScope();
    }
}

Controller:

[RoutePrefix("api/Account")]
public class AccountController : ApiController
{
    private IAuthService authService;
    public AccountController(IAuthService authService)
    {
        this.authService = authService;
    }
    // POST api/Account/Register
    [AllowAnonymous]
    [Route("Register")]
    public async Task<IHttpActionResult> Register(UserModel userModel)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        IdentityResult result = await authService.RegisterUser(Mapper.Map<UserDTO>(userModel));
        IHttpActionResult errorResult = GetErrorResult(result);
        if (errorResult != null)
        {
            return errorResult;
        }
        return Ok();
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            authService.Dispose();
        }
        base.Dispose(disposing);
    }
    private IHttpActionResult GetErrorResult(IdentityResult result)
    {
        if (result == null)
        {
            return InternalServerError();
        }
        if (!result.Succeeded)
        {
            if (result.Errors != null)
            {
                foreach (string error in result.Errors)
                {
                    ModelState.AddModelError("error", error);
                }
            }
            if (ModelState.IsValid)
            {
                // No ModelState errors are available to send, so just return an empty BadRequest.
                return BadRequest();
            }
            return BadRequest(ModelState);
        }
        return null;
    }
}

Трассировка стека из запроса:

    [ArgumentNullException: Значение не может быть неопределенным.
Имя параметра: context]
   Microsoft.AspNet.Identity.EntityFramework.UserStore`6..ctor(DbContext context) +335
   Microsoft.AspNet.Identity.EntityFramework.UserStore`1..ctor(DbContext context) +5
   DAL.Repositories.UnitOfWork.get_UserManager() in D:\programming\projects\vs_projects\web\identity_bearer\DAL\Repositories\UnitOfWork.cs:42
   BLL.Services.&lt;FindUser&gt;d__3.MoveNext() in D:\programming\projects\vs_projects\web\identity_bearer\BLL\Services\AuthService.cs:43
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +28
   identity_bearer.Providers.&lt;GrantResourceOwnerCredentials&gt;d__3.MoveNext() in D:\programming\projects\vs_projects\web\identity_bearer\identity_bearer\Providers\SimpleAuthorizationServerProvider.cs:33
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   Microsoft.Owin.Security.OAuth.&lt;InvokeTokenEndpointResourceOwnerPasswordCredentialsGrantAsync&gt;d__10.MoveNext() +447
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) +25
   Microsoft.Owin.Security.OAuth.&lt;InvokeTokenEndpointAsync&gt;d__8.MoveNext() +1487
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   Microsoft.Owin.Security.OAuth.&lt;InvokeAsync&gt;d__5.MoveNext() +984
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   Microsoft.Owin.Security.Infrastructure.&lt;Invoke&gt;d__5.MoveNext() +360
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   Ninject.Web.Common.OwinHost.&lt;&lt;Execute&gt;b__1&gt;d.MoveNext() +267
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   Microsoft.Owin.Cors.&lt;Invoke&gt;d__4.MoveNext() +653
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.&lt;RunApp&gt;d__7.MoveNext() +179
   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.&lt;DoFinalWork&gt;d__12.MoveNext() +180
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +69
   Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar) +64
   System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +380
   System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +48
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean&amp; completedSynchronously) +159

Примечание: Перепробовал я уже много всего. Так же если заменить app.UseWebApi(config) на app.UseNinjectWebApi(config) то нечего не работает. Знаю что может быть много ошибок в коде. Пожалуйста пишите о них.
Спасибо за помощь.

Answer 1

Решил ошибку. Оказалось что контексты нужно отдельно биндить в модуле

Bind<IUnitOfWork>().To<UnitOfWork>(); 
Bind<AuthContext>().ToSelf().WithConstructorArgument("AuthConnection");
READ ALSO
C# - Process | Манипуляции

C# - Process | Манипуляции

C# Пример: BEServiceexe - Приостановлено

103
OleDbConnection не получает команды извне

OleDbConnection не получает команды извне

Написал класс по примеру из https://stackoverflowcom/questions/13135321/how-to-create-a-method-in-a-class-that-would-connect-to-my-database-on-calling

111