Non-invocable member 'IUnitOfWork.AdminMerchants' cannot be used like a method - c#

In my ASP.NET Core 6 Web API project, I am implementing Repository and UnitOfWork:
I have this code:
IMerchantRepository:
public interface IAdminMerchantRepository : IGenericRepository<Merchant>
{
IQueryable<AllMerchantListDto> GetAllMerchantAsync(PagingFilter filter);
}
MerchantRepository:
public class AdminMerchantRepository : GenericRepository<Merchant>, IAdminMerchantRepository
{
private readonly ApplicationDbContext _dbContext;
private readonly DbSet<Merchant> _adminMerchants;
public AdminMerchantRepository(ApplicationDbContext dbContext) : base(dbContext)
{
_dbContext = dbContext;
_adminMerchants = _dbContext.Set<Merchant>();
}
public IQueryable<AllMerchantListDto> GetAllMerchantAsync(PagingFilter filter)
{
var merchants = _dbContext.Merchants
.Where(x => string.IsNullOrEmpty(filter.SearchQuery) || x.User.UserName.ToLower().Contains(filter.SearchQuery.ToLower())
|| x.User.Email.ToLower().Contains(filter.SearchQuery.ToLower())
|| x.User.FirstName.ToLower().Contains(filter.SearchQuery.ToLower())
|| x.User.LastName.ToLower().Contains(filter.SearchQuery.ToLower())
|| x.MerchantName.ToLower().Contains(filter.SearchQuery.ToLower()))
.Include(x => x.User)
.OrderByDescending(x => x.CreatedAt);
return (IQueryable<AllMerchantListDto>)merchants;
}
}
IUnitOfWork:
public interface IUnitOfWork : IDisposable
{
IAdminMerchantRepository AdminMerchants { get; }
Task Save();
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _dbContext;
private IAdminMerchantRepository _adminMerchants;
public UnitOfWork(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public IAdminMerchantRepository AdminMerchants => _adminMerchants ??= new AdminMerchantRepository(_dbContext);
public async Task Save()
{
await _dbContext.SaveChangesAsync();
}
public void Dispose()
{
_dbContext.Dispose();
GC.SuppressFinalize(this);
}
}
I got this error:
Non-invocable member 'IUnitOfWork.AdminMerchants' cannot be used like a method
Then this AdminMerchants highlighted in:
var merchant = await _unitOfWork.AdminMerchants(filter);

It look like you're calling
var merchant = await _unitOfWork.AdminMerchants(filter);
where you mean to be calling
var merchant = await _unitOfWork.AdminMerchants.GetAllMerchantAsync(filter);.

GetAllMerchantAsync is not async method. You need call await _unitOfWork.AdminMerchants.GetAllMerchantAsync(filter).ToListAsync() and better to rename method to GetAllMerchant.
Your query will fail, because you have produced not IQueryable<AllMerchantListDto> but IQueryable<Merchant>. That's why you have applied wrong explicit cast.
It should be:
return merchants.Select(m => new AllMerchantListDto
{
... // assign properties
});
Do not create additional abstractions if they are not needed. DbContext is already Unit Of Work and DbSet is already Repository. GetAllMerchant can be just extension method and no additional abstractions are needed.

Related

Unit of Work and Repository Pattern in MVC controller constructor injection using Unity not doing any changes to database

1.) I am a building new MVC application with 3 tier project architecture having:
Common Project with entities
Business/Service holding interfaces and logic classes and
Data holding repositories, interfaces, DbContext and UnitOfWorkclasses. I am using Unity Config to register dependencies, DbContext and UnitOfWork.
2.) I created a repository for each table and one generic repository that does basic CRUD operations.
Example Entity residing in Common Project:
public class MenuSecd
{
[Key, Column(Order = 0)]
public string prg_module { get; set; }
[Key, Column(Order = 1)]
public int prg_numb { get; set; }
[Key, Column(Order = 2)]
public string menu_level { get; set; }
}
My generic Entity Logic Interface residing in Business Project:
public interface IEntityLogic<T> : ILogic where T : class
{
void Create(T entity);
void Delete(T entity);
IEnumerable<T> GetAll();
void Update(T entity);
}
Entity Logic Class:
public abstract class EntityLogic<T> : IEntityLogic<T> where T : class
{
IUnitOfWork _unitOfWork;
IGenericRepository<T> _repository;
public EntityLogic(IUnitOfWork unitOfWork, IGenericRepository<T> repository)
{
_unitOfWork = unitOfWork;
_repository = repository;
}
public virtual void Create(T entity)
{
if(entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
_repository.Add(entity);
_unitOfWork.Commit();
}
}
Example Business Logic class for the entity defined in Common Project:
public class MenuSecdLogic : EntityLogic<MenuSecd>, IMenuSecdLogic
{
IUnitOfWork _unitOfWork;
IMenuSecdRepository _repository;
public MenuSecdLogic(IUnitOfWork unitOfWork, IMenuSecdRepository repository) : base(unitOfWork, repository)
{
_unitOfWork = unitOfWork;
_repository = repository;
}
public List<MenuSecd> GetItems(string usrgrp_id)
{
return _repository.GetItems(usrgrp_id);
}
}
My Generic Repository in Data Project looks like:
public abstract class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected DbContext _entities;
protected readonly IDbSet<T> _dbset;
public GenericRepository(DbContext context)
{
_entities = context;
_dbset = context.Set<T>();
}
public virtual T Add(T entity)
{
return _dbset.Add(entity);
}
public virtual T Delete(T entity)
{
return _dbset.Remove(entity);
}
public virtual void Edit(T entity)
{
_entities.Entry(entity).State = EntityState.Modified;
}
}
Repository Interface for the same Entity is defined as:
public interface IMenuSecdRepository : IGenericRepository<MenuSecd>
{
List<MenuSecd> GetItems(string usrgrp_id);
}
Repository class for above mentioned interface is:
public class MenuSecdRepository : GenericRepository<MenuSecd>, IMenuSecdRepository
{
public MenuSecdRepository(DbContext context) : base(context)
{
}
public List<MenuSecd> GetItems(string usrgrp_id)
{
return _dbset.Where(m => m.usrgrp_id == usrgrp_id).ToList();
}
}
My DbContext looks like:
public class DashboardContext : DbContext
{
public DashboardContext() : base("Name=DBEntities")
{
}
public DbSet<MenuSecd> menusecd { get; set; }
public override int SaveChanges()
{
var modifiedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
//future custom implementation like auditing
return base.SaveChanges();
}
}
My UnitOfWork looks like:
public sealed class UnitOfWork : IUnitOfWork
{
private DbContext _dbContext;
public UnitOfWork(DbContext context)
{
_dbContext = context;
}
public int Commit()
{
return _dbContext.SaveChanges();
}
//disposes current object
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
//disposes all external resources
private void Dispose(bool disposing)
{
if (disposing)
{
if (_dbContext != null)
{
_dbContext.Dispose();
_dbContext = null;
}
}
}
}
My controller:
public class DashController : Controller
{
private readonly IMenuSecdLogic _menuSecdLogic;
public DashController(IMenuSecdLogic menuSecdLogic)
{
_menuSecdLogic = menuSecdLogic;
}
public void Save()
{
var menuSecd = new menuSecd();
//populate all fields for entity MenuSecd
_menuSecdLogic.Create(menuSecd);
}
}
My Unity Config in App_Start looks like :
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<DbContext, DashboardContext>();
container.RegisterType<IUnitOfWork, UnitOfWork>();
container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<>));
container.RegisterType<IMenuSecdLogic, MenuSecdLogic>();
container.RegisterType<IMenuSecdRepository, MenuSecdRepository>();
}
So when run above project everything builds fine. But when controller calls:
_menuSecdLogic.Create(menuSecd);
It reaches Entity Logic and adds a new entity to _repository at :
_repository.Add(entity);
_unitOfWork.Commit();
But when it hits next line to actually save it to database which is :
return _dbContext.SaveChanges();
in UnitOfWork.cs file.
It comes to dashboardContext where it finally have to save it to database. But it does execute :
var modifiedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
return base.SaveChanges();
But nothing changes in database. There will be no record in database. To test I have added modifiedEntries to see if it is in context or not. By the time control reaches this point I see no modified entries at all. But in EntityLogic.cs it does add a new entity to local entities in repository.
I am not sure what is happening with UnitOfWork here. I ran SQL Profiler to see if it is hitting database or not. Interestingly it is not hitting database at all. But if my make following changes to EntityLogic like this:
public virtual void Create(T entity)
{
if(entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
_repository.Add(entity);
_repository.Save();
//_unitOfWork.Commit();
}
It hits Database and records gets saved fine. But I am not getting why it is neither tracking changes nor hitting database if I use _unitOfWork.Commit() which I want to do. Please help.
It looks like your issue is the scope of your DbContext. Your UnitOfWork and GenericRepository<T> classes are getting different instances.
Not super familiar with Unity, but it looks like you want to use something like this for your DbContext registration:
container.RegisterType<DbContext, DashboadContext>(new PerRequestLifetimeManager());
This will create a single DashboardContext for each request, and your UnitOfWork and GenericRepository<T> classes will be working within the same context.

Unit testing for IDomainService with ASP.NET Boilerplate

I am unit testing ABP, but I got error below:
Cannot access a disposed object. A common cause of this error is
disposing a context 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, or wrapping the context 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:
'XXXDbContext'.
Here are my detailed steps:
AppService
public async Task<ProductDto> CreateProduct(CreateProductInput input)
{
var existing = // await _productManager.ProductRepository.FirstOrDefaultAsync(p => p.Name == input.Name);
await _productManager.Products.Where(p => p.Name == input.Name).FirstOrDefaultAsync();
if (existing != null) throw new UserFriendlyException(L("ExistedRepeatedAd"));
var newAdEntity = ObjectMapper.Map<Product>(input);
// Rest of the code
}
ProductManager
public class ProductManager : IDomainService
{
private readonly IRepository<Product, long> _ProductRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager;
public ProductsManager(
IRepository<Product, long> ProductRepository,
IUnitOfWorkManager unitOfWorkManager)
{
_ProductRepository = ProductRepository;
_unitOfWorkManager = unitOfWorkManager;
}
#region Products
public IRepository<Product, long> ProductRepository
{
get { return _ProductRepository; }
}
public IQueryable<Product> Products
{
get { return _ProductRepository.GetAll(); }
}
public async Task<Product> CreateProduct(Product input)
{
var result = await _ProductRepository.InsertAsync(input);
await _unitOfWorkManager.Current.SaveChangesAsync();
return result;
}
#endregion
}
It will throw error this line:
await _adManager.Ads.Where(p => p.Name == input.Name).FirstOrDefaultAsync();
But if I use this instead, it will work:
await _adManager.AdRepository.FirstOrDefaultAsync(p => p.Name == input.Name);
In addition, I get _unitOfWorkManager.Current as null in the above code.
Is there any suggestion?
UnitOfWork Attribute
Add [UnitOfWork] attribute and make it a virtual method:
[UnitOfWork]
public virtual async Task<ProductDto> CreateProduct(CreateProductInput input)
{
var existing = await _productManager.Products
.Where(p => p.Name == input.Name)
.FirstOrDefaultAsync();
// ...
}
[UnitOfWork]
public virtual async Task<Product> CreateProduct(Product input)
{
var result = await _ProductRepository.InsertAsync(input);
await _unitOfWorkManager.Current.SaveChangesAsync();
return result;
}
See: UnitOfWork Attribute Restrictions
You can use UnitOfWork attribute for:
All public or public virtual methods for classes that are used over an interface (Like an application service used over a service interface).
All public virtual methods for self-injected classes (Like MVC Controllers and Web API Controllers).
All protected virtual methods.
IUnitOfWorkManager
You can inject IUnitOfWorkManager to begin a UnitOfWork explicitly:
public async Task<Product> CreateProduct(Product input)
{
using (var uow = _unitOfWorkManager.Begin())
{
var result = await _ProductRepository.InsertAsync(input);
await _unitOfWorkManager.Current.SaveChangesAsync();
await uow.CompleteAsync();
return result;
}
}
My issue is resolved by creating Interface for my appservice and then Resolve this Interface in my test projects.
Thanks for the suggestion from aaron, but it would be complex to using uniofwork in my every application service.

Entity Framework read queries locking all database

I'm developing a web application using ASP.NET MVC and EF6 to access the database.
One of the features of my web application allow the user to download a Excel file. The query to get the information from the database takes like 5 seconds and I notice that until the query it's done we can't do anything on the rest of the web application.
Is this the normal behaviour of EF, lock the database even with AsNoTracking on the query?
If I'm not doing anything wrong and this is the default behaviour of EF how should I resolve this locking problem?
(Update)
I'm using a SQL Server database and the "lock" happens when for exemple I export the excel file and at the same time do a search that uses the same table.
To organize my code i'm using Repository and UnitOfWork pattern and to create the instances i'm using DI Unity.
The UnitOfWork implementation:
public class UnitOfWork : IUnitOfWork
{
private bool _disposed;
private DbContext _dbContext;
private Dictionary<string, dynamic> _repositories;
private DbContextTransaction _transaction;
public DbContext DbContext
{
get { return _dbContext; }
}
public UnitOfWork(DbContext dbContext)
{
_dbContext = dbContext;
}
public int SaveChanges()
{
return _dbContext.SaveChanges();
}
public IRepository<TEntity> Repository<TEntity>()
{
try
{
if (ServiceLocator.IsLocationProviderSet)
return ServiceLocator.Current.GetInstance<IRepository<TEntity>>();
if (_repositories == null)
_repositories = new Dictionary<string, dynamic>();
var type = typeof(TEntity).Name;
if (_repositories.ContainsKey(type))
return (IRepositoryAsync<TEntity>)_repositories[type];
var repositoryType = typeof(Repository<>);
_repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof(TEntity)), this));
return _repositories[type];
}
catch(ActivationException ex)
{
throw new ActivationException(string.Format("You need to configure the implementation of the IRepository<{0}> interface.", typeof(TEntity)), ex);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~UnitOfWork()
{
Dispose(false);
}
public void Dispose(bool disposing)
{
if(!_disposed)
{
if(disposing)
{
try
{
_dbContext.Dispose();
_dbContext = null;
}
catch(ObjectDisposedException)
{
//the object has already be disposed
}
_disposed = true;
}
}
}
}
The Repository implementation:
public class Repository<TEntity> : IRepository<TEntity>
where TEntity : class
{
private readonly IUnitOfWork _unitOfWork;
private readonly DbContext _dbContext;
private readonly DbSet<TEntity> _dbSet;
public Repository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_dbContext = unitOfWork.DbContext;
_dbSet = _dbContext.Set<TEntity>();
}
#region IRepository<TEntity> implementation
public void Insert(TEntity entity)
{
_dbSet.Add(entity);
}
public void Update(TEntity entity)
{
_dbContext.Entry(entity).State = EntityState.Modified;
}
public void Delete(TEntity entity)
{
_dbSet.Remove(entity);
}
public IQueryable<TEntity> Queryable()
{
return _dbSet;
}
public IRepository<TEntity> GetRepository<TEntity>()
{
return _unitOfWork.Repository<TEntity>();
}
#endregion
}
The Unity configuration:
container.RegisterType<DbContext, DbSittiusContext>(new PerRequestLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
//Catalog respository register types
container.RegisterType<IRepository<Product>, Repository<Product>>();
UnityServiceLocator locator = new UnityServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => locator);
To create my query have to create a extension method like this:
public static Product FindPublishedAtDateById(this IRepository<Product> repository, int id, DateTime date)
{
return repository.
Queryable().
Where(p => p.Id == id).
Where(p => p.PublishedFrom <= date && (p.PublishedTo == null || p.PublishedTo >= date)).
SingleOrDefault();
}
If you're downloading a lot of data synchronously it will make the UI freeze up on you. Consider doing this asynchronously. What are you using client side, anyway?
I'm assuming you're generating an excel file from data in the database and it's just a matter of it being enough data that it takes ~5 seconds to create the file and send it to the user.

How to mock Entity Framework 6 Async methods?

I am new in mocking. I want to mock up my base repository which is depend on Entity Framework 6 DbContext But I fail. I searched in Google a lot but did not get any sufficient result. At last I got an example at testing with async queries and try to follow but it is worked for me.
Here is my code :
DbContext :
public class TimeSketchContext : DbContext
{
public virtual DbSet<EmployeeSkill> EmployeeSkill { get; set; }
}
Base Repository :
public class BaseRepository<T> : IRepositoryBase<T> where T : class, IEntity, new()
{
protected readonly DbContext InnerDbContext;
protected DbSet<T> InnerDbSet;
public BaseRepository(DbContext innerDbContext)
{
InnerDbContext = innerDbContext;
InnerDbSet = InnerDbContext.Set<T>();
}
public virtual Task<T> FindAsync(long id)
{
return InnerDbSet.FirstOrDefaultAsync(x=>x.Id == id);
}
}
Test :
[Fact]
public async Task DbTest()
{
var dummyData = GetEmployeeSkills();
var mockSet = new Mock<DbSet<EmployeeSkill>>();
mockSet.As<IDbAsyncEnumerable<EmployeeSkill>>()
.Setup(x => x.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<EmployeeSkill>(dummyData.GetEnumerator()));
mockSet.As<IQueryable<EmployeeSkill>>()
.Setup(x => x.Provider)
.Returns(new TestDbAsyncQueryProvider<EmployeeSkill>(dummyData.Provider));
mockSet.As<IQueryable<EmployeeSkill>>().Setup(m => m.Expression).Returns(dummyData.Expression);
mockSet.As<IQueryable<EmployeeSkill>>().Setup(m => m.ElementType).Returns(dummyData.ElementType);
mockSet.As<IQueryable<EmployeeSkill>>().Setup(m => m.GetEnumerator()).Returns(dummyData.GetEnumerator());
var mockContext = new Mock<TimeSketchContext>();
mockContext.Setup(c => c.EmployeeSkill).Returns(mockSet.Object);
var baseRepository = new BaseRepository<EmployeeSkill>(mockContext.Object);
var data = await baseRepository.FindAsync(1);
Assert.NotEqual(null, data);
}
private EmployeeSkill GetEmployeeSkill()
{
return new EmployeeSkill
{
SkillDescription = "SkillDescription",
SkillName = "SkillName",
Id = 1
};
}
private IQueryable<EmployeeSkill> GetEmployeeSkills()
{
return new List<EmployeeSkill>
{
GetEmployeeSkill(),
GetEmployeeSkill(),
GetEmployeeSkill(),
}.AsQueryable();
}
Result is :
Assert.NotEqual() Failure
I think problem is
public BaseRepository(DbContext innerDbContext)
{
InnerDbContext = innerDbContext;
InnerDbSet = InnerDbContext.Set<T>(); <<<<<<<<<<<
}
But don`t understand why and how to solve this.
I am using :
Visual Studio 2013 Ultimate
Moq
xUnit
Thank`s in advance.
You are right the problem is in your InnerDbContext.Set<T>(); statement.
In the current version of the EF (6.0.2) the DbContext.Set<T> method is not virtual so it cannot be mocked with Moq.
So you cannot easily make your test pass except by changing your design of the BaseRepository to not depend on the whole DbContext but on one DbSet<T>:
So something like:
public BaseRepository(DbSet<T> dbSet)
{
InnerDbSet = dbSet;
}
Then you can pass directly in your mocked DbSet.
Or you can create a wrapper interface for DbContext:
public interface IDbContext
{
DbSet<T> Set<T>() where T : class;
}
public class TimeSketchContext : DbContext, IDbContext
{
public virtual DbSet<EmployeeSkill> EmployeeSkill { get; set; }
}
Then use IDbContext in your BaseRepository:
public class BaseRepository<T> : IRepositoryBase<T> where T : class, IEntity, new()
{
protected readonly IDbContext InnerDbContext;
protected DbSet<T> InnerDbSet;
public BaseRepository(IDbContext innerDbContext)
{
InnerDbContext = innerDbContext;
InnerDbSet = InnerDbContext.Set<T>();
}
public virtual Task<T> FindAsync(long id)
{
return InnerDbSet.FirstOrDefaultAsync(x => x.Id == id);
}
}
And finally you just need to change two lines in your test to make it pass:
var mockContext = new Mock<IDbContext>();
mockContext.Setup(c => c.Set<EmployeeSkill>()).Returns(mockSet.Object);

how can I test method from service when I use unit of work and repository pattern

How can I test ClassifyComment() method from my service. I have that test code:
[TestClass]
public class SpamServiceTest
{
[TestMethod]
public void ClassifyCommentTest()
{
var spamComments = Builder<Comments>.CreateListOfSize(10).All().With(x => x.Content = "spam spam spam")
.Build().AsQueryable();
var mocker = new AutoMoqer();
mocker.GetMock<IUnitOfWork>()
.Setup(x => x.CommentsRepository.GetComments(It.Is<bool>(y => y == true)))
.Returns(spamComments);
//.......
}
}
But it gives me error: Can not instantiate proxy of class: CommentsRepository. Could not find a parameterless constructor.
Below is my code which I want test:
public class SpamService : ISpamService
{
private readonly IUnitOfWork _unitOfWork;
public SpamService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public bool ClassifyComment(Comments comment)
{
var spam = _unitOfWork.CommentsRepository.GetComments(true).ToList();
//.............
}
}
public class UnitOfWork : IUnitOfWork
{
private DatabaseContext context = new DatabaseContext();
private CommentsRepository commentsRepository;
public CommentsRepository CommentsRepository
{
get
{
if (this.commentsRepository == null)
{
this.commentsRepository = new CommentsRepository(context);
}
return commentsRepository;
}
}
}
public class CommentsRepository : ICommentsRepository
{
private DatabaseContext context;
public CommentsRepository(DatabaseContext context)
{
this.context = context;
}
public virtual IQueryable<Comments> GetComments(bool isSpam)
{
//.......
}
}
IUnityOfWork should return a ICommentsRepository, i.e. an interface, not an implementation. The mock of IUnityOfWork should return a mock of ICommentsRepository.
Let the abstraction work with other abstractions, not with implementations.

Categories