Reputation: 21
I´m try to implement UnitOfWork patron and when execute my app, after acces to DB, receive the error: System.ObjectDisposedException: 'Cannot access a disposed context instance
This is my OnPost Method in the model:
Register.cshtml
public async void OnPost(string name, string email, string emailConfirm, string password, string passworConfirm)
{
try
{
var user = mapUser(name, email, password);
await _securityService.RegisterNewUserAsync(user);
}
catch
(Exception ex)
{
}
}
It is the part of my RegisterNewUser method that fail (_userService.GetByNameOrEmailAsync)
namespace CompanyMannager.Services.Security
{
public class SecurityService : ISecurityService
{
private readonly IUserService _userService;
public SecurityService(IUserService userService)
{
_userService = userService;
}
public async Task RegisterNewUserAsync(User user)
{
// var userTokenService = new UserTokenService(_unitOfWork);
var users = await _userService.GetByNameOrEmailAsync(user.Name, user.Email);
if (users.Any())
{
throw new DuplicateNameException("The name or email is already in use, please try when other email and name.");
}
await _userService.CreateUser(user, Convert.ToBase64String(salt));
}
}
}
It is the UserService:
namespace CompanyMannager.Services
{
public class UserService : IUserService
{
private readonly IUnitOfWork _unitOfWork;
public UserService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public async Task<IEnumerable<User>> GetByNameOrEmailAsync(string name, string email)
{
return await _unitOfWork._userRepository.GetAsync(x => x.Name == name || x.Email == email);
}
}
}
It´s the UserRepository:
public class UserRepository : BaseRepository<User>, IUserRepository
{
public UserRepository(CompanyMannagerDBContext context) : base(context)
{
}
}
It´s the BaseRepository:
public class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class
{
private readonly CompanyMannagerDBContext _Context;
internal DbSet<TEntity> dbSet;
public BaseRepository(CompanyMannagerDBContext context)
{
_Context = context;
dbSet = context.Set<TEntity>();
}
public async Task<IEnumerable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
query = query.Where(filter);
foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
return await orderBy(query).ToListAsync();
else
return await query.ToListAsync();
}
}
}
And it´s the UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
public IUserRepository _userRepository { get; }
public IUserTokenRepository _userTokenRepository { get; }
private readonly CompanyMannagerDBContext _context;
public UnitOfWork(CompanyMannagerDBContext context, IUserRepository userRepository, IUserTokenRepository userTokenRepository)
{
_context = context;
_userRepository = userRepository;
_userTokenRepository = userTokenRepository;
/* public IUserRepository UserRepository => _userRepository ??= new UserRepository(_context);
public IUserTokenRepository UserTokenRepository => _userTokenRepository ??= new UserTokenRepository(_context); */
}
public async Task<int> CommitAsync()
{
return await _context.SaveChangesAsync();
}
public void Dispose()
{
_context.Dispose();
}
}
}
Wath i´s my error?
Thank´s
I tryed to modify de dependecy inyections, because i´m new in it, but the error persist
Share the new's: I altered my code to use basic EF, must the error persist:
System.ObjectDisposedException: '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. ObjectDisposed_ObjectName_Name'
CompanyMannager.Services.UserService.GetByNameOrEmailAsync(string, string) en UserService.csCompanyMannager.Services.Security.SecurityService.RegisterNewUserAsync(CompanyMannager.Core.Entities.User) en SecurityService.cs CompanyMannager.UI.Areas.Identity.Pages.RegisterModel.OnPost(string, string, string, string, string) en Register.cshtml.cs
Register.cshtml:
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace CompanyMannager.UI.Areas.Identity.Pages
{
public class RegisterModel : PageModel
{
public bool RegisterError = false;
private readonly ISecurityService _securityService;
public RegisterModel (ISecurityService securityService)
{
_securityService = securityService;
}
public void OnGet()
{
}
public async void OnPost(string name, string email, string emailConfirm, string password, string passworConfirm)
{
try
{
var user = mapUser(name, email, password);
await _securityService.RegisterNewUserAsync(user);
}
catch
(Exception ex)
{
}
}
private User mapUser(string name, string email, string password)
{
var user = new User()
{
Name = name,
Email = email,
PasswordHash = password
};
return user;
}
}
}
UserService.cs:
{
public class UserService : IUserService
{
private readonly CompanyMannagerDBContext _companyMannagerDBContext;
public UserService(CompanyMannagerDBContext context)
{
_companyMannagerDBContext = context;
}
public async Task<User> CreateUser(User user, string salt)
{
try
{
var usrCreated = await _companyMannagerDBContext.Users.AddAsync(user);
await _companyMannagerDBContext.SaveChangesAsync();
return await GetUserById(usrCreated.Entity.UserId);
}
catch (Exception ex)
{
//_unitOfWork.Dispose();
throw new ApplicationException($"Create user error - {ex.Message} ");
}
}
public async Task<IEnumerable<User>> GetByNameOrEmailAsync(string name, string email)
{
return await _companyMannagerDBContext.Users.Where(x => x.Name == name || x.Email == email).ToListAsync();
}
}
}
User.cs
public partial class User
{
public int UserId { get; set; }
public string? Name { get; set; }
public string? NormalizedName { get; set; }
public string? PasswordHash { get; set; }
public string? CreateUser { get; set; }
public DateTime? CreateDate { get; set; }
public string? LastUpdatedUser { get; set; }
public DateTime? LasteUpdatedDate { get; set; }
public string? Email { get; set; }
public string? NormalizeEmail { get; set; }
public string? EmailVerified { get; set; }
public DateTime? ExpirationDate { get; set; }
public User() { }
}
I share the code:
Program.cs
using CompanyMannager.Core.Interfaces.Repositories;
using CompanyMannager.Core.Interfaces.Services;
using CompanyMannager.Infraestructure.Data;
using CompanyMannager.Infraestructure.Repositories;
using CompanyMannager.Services;
using CompanyMannager.Services.Security;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddDbContext<CompanyMannagerDBContext>(options =>options.UseSqlServer(builder.Configuration.GetConnectionString("DbConnection")));
builder.Services.AddScoped<IUserTokenRepository, UserTokenRepository>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<ISecurityService, SecurityService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<CompanyMannagerDBContext>();
await DbInitializer.Initialize(context);
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred creating the DB.");
}
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
It's the DBInitializer:
using CompanyMannager.Core.Entities;
using Microsoft.EntityFrameworkCore;
namespace CompanyMannager.Infraestructure.Data
{
public static class DbInitializer
{
public static async Task Initialize(CompanyMannagerDBContext context)
{
context.Database.EnsureCreated();
// Look for any user.
if (context.Users.Any())
{
await context.Users.AnyAsync();
}
else
{
// Create test user
var users = new User[]
{
new User()
{
Name="Prueba",
PasswordHash="miPassWord",
CreateDate= DateTime.Now,
CreateUser= "1",
Email="[email protected]",
EmailVerified= "1",
ExpirationDate= DateTime.Now.AddDays(90),
LasteUpdatedDate = DateTime.Now,
LastUpdatedUser= "1",
NormalizedName= "PRUEBA",
NormalizeEmail = "[email protected]"
},
};
foreach (User user in users)
{
await context.Users.AddAsync(user);
}
await context.SaveChangesAsync();
var usersTokens = new UserToken[]
{
new UserToken()
{
UserId= 1,
TokenHash = "hash"
},
};
foreach (UserToken usersToken in usersTokens)
{
await context.UsersTokens.AddAsync(usersToken);
}
await context.SaveChangesAsync();
}
}
}
}
I made the user query work by having the initial query answer a TASK instead of VOID in the DBinitializer. line 15, but then it gives the same error when I insert the user.
Upvotes: 0
Views: 58