Я решил добавить 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.<FindUser>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.<GrantResourceOwnerCredentials>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.<InvokeTokenEndpointResourceOwnerPasswordCredentialsGrantAsync>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.<InvokeTokenEndpointAsync>d__8.MoveNext() +1487
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Security.OAuth.<InvokeAsync>d__5.MoveNext() +984
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Security.Infrastructure.<Invoke>d__5.MoveNext() +360
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Ninject.Web.Common.OwinHost.<<Execute>b__1>d.MoveNext() +267
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58
Microsoft.Owin.Cors.<Invoke>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.<RunApp>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.<DoFinalWork>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& completedSynchronously) +159
Примечание: Перепробовал я уже много всего. Так же если заменить app.UseWebApi(config) на app.UseNinjectWebApi(config) то нечего не работает. Знаю что может быть много ошибок в коде. Пожалуйста пишите о них.
Спасибо за помощь.
Решил ошибку. Оказалось что контексты нужно отдельно биндить в модуле
Bind<IUnitOfWork>().To<UnitOfWork>();
Bind<AuthContext>().ToSelf().WithConstructorArgument("AuthConnection");
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Доброго времени суток всем читающим!
Написал класс по примеру из https://stackoverflowcom/questions/13135321/how-to-create-a-method-in-a-class-that-would-connect-to-my-database-on-calling