How to mock EF 6 Async methods using JustMock? - c#

I am trying to Mock Entity Framework 6.0.2 Async methods using JustMock. I am following testing with async queries but it is write using Moq I am trying to convert this into JustMock with help of Mock Multiple Interfaces but getting an exception :
The provider for the source IQueryable doesn't implement
IDbAsyncQueryProvider. Only providers that implement
IDbAsyncQueryProvider can be used for Entity Framework asynchronous
operations. For more details see
http://go.microsoft.com/fwlink/?LinkId=287068.
Here is my code :
var dummyData = GetEmployeeSkills();
var mockSet = Mock.Create<DbSet<EmployeeSkill>>();
(mockSet as IDbAsyncEnumerable<EmployeeSkill>).Arrange(x => x.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<EmployeeSkill>(dummyData.GetEnumerator()));
(mockSet as IQueryable<EmployeeSkill>).Arrange(x => x.Provider).Returns(new TestDbAsyncQueryProvider<EmployeeSkill>(dummyData.Provider));
(mockSet as IQueryable<EmployeeSkill>).Arrange(x => x.Expression).Returns(dummyData.Expression);
(mockSet as IQueryable<EmployeeSkill>).Arrange(x => x.ElementType).Returns(dummyData.ElementType);
(mockSet as IQueryable<EmployeeSkill>).Arrange(x => x.GetEnumerator()).Returns(dummyData.GetEnumerator());
var mockContext = Mock.Create<TimeSketchContext>();
mockContext.Arrange(x => x.Set<EmployeeSkill>()).Returns(mockSet);
baseRepository = new BaseRepository<EmployeeSkill>(mockContext);
private EmployeeSkill GetEmployeeSkill()
{
return new EmployeeSkill
{
SkillDescription = "SkillDescription",
SkillName = "SkillName",
Id = 1
};
}
private IQueryable<EmployeeSkill> GetEmployeeSkills()
{
return new List<EmployeeSkill>
{
GetEmployeeSkill(),
GetEmployeeSkill(),
GetEmployeeSkill(),
}.AsQueryable();
}
Test :
[Fact]
public async Task DbTest()
{
var data = await baseRepository.FindAsync(1);
Assert.NotEqual(null, data);
}
Repository :
public class BaseRepository<T> : IRepositoryBase<T> where T : class, IEntity, new()
{
protected readonly DbContext InnerDbContext;
protected DbSet<T> InnerDbSet;
public BaseRepository(IDbContext innerDbContext)
{
InnerDbContext = innerDbContext as DbContext;
InnerDbSet = innerDbContext.Set<T>();
}
public virtual Task<T> FindAsync(long id)
{
return InnerDbSet.FirstOrDefaultAsync(x=>x.Id == id);
}
}
Interface :
public interface IDbContext
{
DbSet<T> Set<T>() where T : class;
}
Context :
public class TimeSketchContext : DbContext, IDbContext
{
public virtual DbSet<EmployeeSkill> EmployeeSkill { get; set; }
}

Because JustMock can mock non virtual methods when you are writing
var mockContext = Mock.Create<TimeSketchContext>();
mockContext.Arrange(x => x.Set<EmployeeSkill>()).Returns(mockSet);
it will mock the DbContext.Set<> and not your IDbContext.Set<> so you get the exception.
There are at least 2 solution to this:
Mock your IDbContext interface
var mockContext = Mock.Create<IDbContext>();
Or change back your BaseRepository to use a DbContext instead of your interface:
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);
}
}

Related

Generic UnitOfWork

I am trying to create a Repository & UnitOfWork for Data Access Layer. In my current implementation I have to modify my UnitOfWork everytime I create a new repository. I would like to avoid that and also keep the functionality to extend my repository abstract class.
Following is my generic Repository & UnitOfWork interface & classes
public interface IRepositoryBase<T> where T : class
{
IList<T> FindAll();
T FindByCondition(Expression<Func<T, bool>> expression);
void Create(T entity);
void Update(T entity);
void Delete(T entity);
}
public abstract class RepositoryBase<T> : IRepositoryBase<T> where T : class
{
protected DBContext _dbContext { get; set; }
public RepositoryBase(DBContext dbContext)
{
_dbContext = dbContext;
}
//other methods removed
public void Create(T entity)
{
_dbContext.Set<T>().Add(entity);
}
}
public interface IUnitOfWork
{
IReminderRepository Reminder { get; }
void Save();
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
protected DBContext _dbContext { get; set; }
private IReminderRepository _reminderRepository;
public UnitOfWork(DBContext dbContext)
{
_dbContext = dbContext;
}
public IReminderRepository Reminder
{
get
{
return _reminderRepository = _reminderRepository ?? new ReminderRepository(_dbContext);
}
}
public void Save()
{
_dbContext.SaveChanges();
}
public void Dispose()
{
_dbContext.Dispose();
}
}
Here I can extend my Repository as per my specific needs by implementing the specific Repository as
public interface IReminderRepository : IRepositoryBase<Reminder>
{
IList<Reminder> GetAllReminders();
Reminder GetReminderById(Guid id);
Reminder GetReminderByName(string name);
void CreateReminder(Reminder reminder);
void UpdateReminder(Reminder reminder);
void DeleteReminder(Reminder reminder);
}
public class ReminderRepository : RepositoryBase<Reminder>, IReminderRepository
{
public ReminderRepository(DBContext dbContext)
: base(dbContext)
{
_dbContext = dbContext;
}
//other methods removed
public Reminder GetReminderByName(string name)
{
return FindAll()
.OrderByDescending(r => r.Name)
.FirstOrDefault(r => r.Name == name);
//return FindByCondition(r => r.Name == name);
}
}
This is ok but when ever I will create a new Specific Repository I will have to modify the UnitOfWork class as well by adding a new property for the new Repository.
While searching online I found following but it does not work in my case as my RepositoryBase is an abstract class.
public interface IUnitOfWork
{
void Save();
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly DBContext _dbContext { get; set; }
private readonly Dictionary<Type, object> _repositories = new Dictionary<Type, object>();
public Dictionary<Type, object> Repositories
{
get { return _repositories; }
set { Repositories = value; }
}
public UnitOfWork(DBContext dbContext)
{
_dbContext = dbContext;
}
public IRepositoryBase<T> Repository<T>() where T : class
{
if (Repositories.Keys.Contains(typeof(T)))
{
return Repositories[typeof(T)] as IRepositoryBase<T>;
}
IRepositoryBase<T> repo = new RepositoryBase<T>(_dbContext);//This does not work
Repositories.Add(typeof(T), repo);
return repo;
}
public void Save()
{
_dbContext.SaveChanges();
}
}
You obviously need to get a reference to a IReminderRepository somewhere in your code to be able to use the remainder specific APIs.
If you don't want to extend your UnitOfWork class to return an IReminderRepository, you may create one yourself in the method that actually uses the specific repository, e.g.:
using (var context = new DBContext())
{
IUnitOfWork uow = new UnitOfWork(context);
ReminderRepository repository = new ReminderRepository(context);
Reminder remainder = repository.GetReminderByName("...");
remainder.SomeProperty = "updated value..";
uow.Save();
}
The only purpose of using the unit of work is to be able to share the same context between several different repositories anyway. Exposing a Dictionary<Type, object> in your UnitOfWork won't solve anything as the purpose of using generics is to provide compile-time type safety.

Mocking a Service using Moq in C#

I have a service that is setup in this way.
public Interface IDataService : IDisposable
{
IQueryable<T> Set<T>() where T : class;
IDbSet<T> WritableSet<T>() where T : class;
}
IDataService is inherited by DataService.
public abstract class DataService : IDataService
{
public IDataContext DataContext { get; private set; }
public IQueryable<T> Set<T>() where T : class
{
return DataContext.Set<T>().AsNoTracking();
}
public IDbSet<T> WritableSet<T>() where T : class
{
return DataContext.Set<T>();
}
public AddResult<T> Add<T>(T obj) where T : class, IPersistentEntity
{
if (obj == null)
return new AddResult<T>() { IsValid = false };
else
{
if (obj.Id == Guid.Empty)
WritableSet<T>().Add(obj);
bool success = DataContext.SaveChanges() > 0;
return new AddResult<T>() { Entity = obj, IsValid = success };
}
}
}
And The DataService is inherited by EntityService.
public class EntityService : DataService
{
public EntityService(IDataContext DataContext) : base(DataContext)
{
}
public void EntityStarted(Guid Id)
{
var a = GetWriteableById<Entity>(Id);
a.Status = 1;
DataContext.SaveChanges();
}
}
This EntityService is used in one of my components. EntityService's object is created and passed to the component's constructor.
I'm using Moq to perform some tests on the component and for that, the plan was to mock the EntityService such that the EntityService uses a fake db container with dummy data for database like operations. But, I'm not having the best idea to mock this with minimum amount of new code.
The least appealing idea that I have is to create a fake EntityService class using the interface and have it's own implementation suitable for tests.
Help is appreciated! :)
As per #JLe and #Chetan's comment on the question, I had to mock the DbContext.
I followed this article to mock the DbContext.
Mocking DbContext with Moq
Here is how the code looks like.
private void Setup()
{
List<Entity> entityData = new List<Entity>();
entityData.Add(new Entity
{
Id = Guid.NewGuid()
});
DbSet<Entity> MockEntitySet = GetSet(entityData);
MockContext = new Mock<IDbContext>();
MockContext.Setup(m => m.Set<Entity>()).Returns(MockEntitySet);
}
public static DbSet<T> GetSet<T>(List<T> sourceList) where T : class
{
return GetSet(sourceList.ToArray());
}
public static DbSet<T> GetSet<T>(T[] sourceList) where T : class
{
var name = typeof(T).Name;
var queryable = sourceList.AsQueryable();
Mock<DbSet<T>> dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
dbSet.Setup(m => m.AsNoTracking()).Returns(dbSet.Object);
return dbSet.Object;
}
[TestMethod]
public void Test()
{
EntityService service = new EntityService(MockContext.Object);
ComponentToTest compObj = new ComponentToTest(service);
compObj.MethodToTest(...);
// Assertions
}
Thank you guys! Appreciate your help and suggestions.
To mock you need an Interface, if not, you need to mark the methods that you want to mock as virtual.
Under the hood the mocking framework is going to create a new implementation for you that behaves as you configured the mock.
Hope it helps.

Unit Testing Generic Methods (NUnit)

I have been trying to implement the repository pattern in .Net Core using a generic class. This is what i have come up with (ive taken out all but one method to keep it simple). The class / method works, but im trying to write a unit(integration) test for it, in this case the Add Method.
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly DbContext Context;
public Repository(DbContext context)
{
Context = context;
}
public void Add(TEntity entity)
{
Context.Set<TEntity>().Add(entity);
}
}
So far my integration test is as follows,
Set Up makes a SqlLite database to save to
Sets up the DbContext
Sets up a Unit of Work - The unit of work is needed to SaveChanges the the DbContext and can be ignored for the most part
Then im creating a "StorageSystem" Domain Object and testing the Generic class. But it feels like I should be able to test it with out passing a specific domain model. Or at the very least, enter the different domain models as parameterised tests.
[TestFixture]
public class RepositoryTests
{
SqliteConnection _connection;
DbContextOptions<ApplicationDbContext> _options;
ApplicationDbContext _context;
UnitOfWork _uow;
[SetUp]
public void SetUp()
{
_connection = new SqliteConnection("DataSource=:memory:");
_connection.Open();
_options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseSqlite(_connection)
.Options;
using (var context = new ApplicationDbContext(_options))
{
context.Database.EnsureCreated();
}
_context = new ApplicationDbContext(_options);
_uow = new UnitOfWork(_context);
}
[TearDown]
public void TearDown()
{
_connection.Close();
}
[Test]
public void Add_AddsEntityToRepository()
{
//arrange
var storageSystem = new StorageSystem {Id = 1, Name = "Storage1"};
var repo = new Repository<StorageSystem>(_context);
//act
repo.Add(storageSystem);
_uow.Complete();
//assert
Assert.AreEqual(1, _context.StorageSystems.Count());
}
I am fairly new to working with Generics, The closest solution I could find was using an abstract class. However I couldnt make it working with me code with it not detecting the tests as an abstract class and not being able to make a repository of type TEntity.
Example taken from here
[TestFixture]
public abstract class RepositoryTests1<TEntity>
{
SqliteConnection _connection;
DbContextOptions<ApplicationDbContext> _options;
ApplicationDbContext _context;
UnitOfWork _uow;
[SetUp]
public void SetUp()
{
_connection = new SqliteConnection("DataSource=:memory:");
_connection.Open();
_options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseSqlite(_connection)
.Options;
using (var context = new ApplicationDbContext(_options))
{
context.Database.EnsureCreated();
}
_context = new ApplicationDbContext(_options);
_uow = new UnitOfWork(_context);
}
[TearDown]
public void TearDown()
{
_connection.Close();
}
[Test]
public void Add_AddsEntityToRepository_GenericAttempt()
{
//arrange
TEntity entityToAdd = this.CreateEntity();
var repo = new Repository<TEntity>(_context); //ERROR HERE - TEntity must be a reference type
//act
repo.Add(entityToAdd);
_uow.Complete();
//assert
//NO IDEA WHAT THE ASSERTION WOULD BE
}
protected abstract TEntity CreateEntity();
}
So in short, how do i unit test this Generic Repository?
You could Restrict your Repository to a certain base class created by you like EntityBase (this should be abstract)
public class EntityBase
{
public int Id { get; set; }
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : EntityBase
{
...
}
Then you are able to pass your base type to this test methods.
[Test]
public void Add_AddsEntityToRepository()
{
//arrange
var storageSystem = new StorageSystem {Id = 1, Name = "Storage1"};
var repo = new Repository<EntityBase>(_context);
//act
repo.Add(storageSystem);
_uow.Complete();
//assert
Assert.AreEqual(1, _context.StorageSystems.Count());
}
Since you are ensuring through inherintance, that every type has at least the members of EntityBase, you do not have to test further more down the inheritance tree of your entity types. (unless you have a certain use-case for that)
If you certain methods, that you need to know on the base-type, but the implementation depends on the child class, simply put the method as abstract member in the base class and override it in the child class.
public class EntityBase
{
public int Id { get; set; }
// sample method that copies member values from other object to current instance
public abstract void CopyProperties(EntityBase other);
}
public class Student : EntityBase
{
public int Id { get; set; }
public override void CopyProperties(EntityBase other)
{
...
}
}

Moq - Update with DbEntityEntry

I'm using EF6. The generated code is something like:
public partial class MyDataContext : DbContext
{
public MyDataContext() : base("name=mydata")
{
}
public virtual DbSet<Book> Books { get; set; }
}
Then I have a generic repository like:
public class GenericRepository<TObject> where TObject : class
{
protected readonly MyDataContext Context;
protected GenericRepository(MyDataContext context)
{
Context = context;
}
public virtual TObject Update(TObject data, int id)
{
if (data == null)
return null;
TObject obj = Context.Set<TObject>().Find(id);
if (obj != null)
{
Context.Entry(obj).CurrentValues.SetValues(data);
Context.SaveChanges();
}
return obj;
}
}
Then I have a service that uses the GenericRepository to update data:
public class MyDataService<TObject> where TObject : class
{
private readonly MyDataContext context;
public MyDataService(MyDataContext ct)
{
context = ct;
}
public TObject Update(TObject obj, int id)
{
var r = new GenericRepository<TObject>(context);
return r.Update(obj, id);
}
}
So I can update a books with something like this:
var ds = new MyDataService<Book>(new MyDataContext());
var data = ds.Update(new Book { Name = "New Name" }, 1);
This is working fine. Next I try to use Moq to unit test the above code with something like:
var updatedBook = new Book { Name = "Update Book Name" };
var mockSet = new Mock<DbSet<Book>>();
var mockContext = new Mock<MyDataContext>();
mockContext.Setup(c => c.Books).Returns(mockSet.Object);
mockContext.Setup(c => c.Set<Book>().Find(It.IsAny<object[]>()))
.Returns<object[]>(ids => chips.FirstOrDefault(d => d.Id == (int)ids[0]));
var service = new MyDataService<Book>(mockContext.Object);
var data = service.Update(updatedBook, 1);
However, I get an exception on the Context.Entry(obj).CurrentValues.SetValues(data) line.
How do I mock the Update method properly?
You could implement an interface for MyDataService to be able to mock it
public Interface IMyDataService<TObject> where TObject : class
{
TObject Update(TObject obj, int id);
}
public class MyDataService<TObject>:IMyDataService<TObject>
where TObject : class
{
private readonly MyDataContext context;
public MyDataService(MyDataContext ct)
{
context = ct;
}
public TObject Update(TObject obj, int id)
{
var r = new GenericRepository<TObject>(context);
return r.Update(obj, id);
}
}
Moq:
var mockDataService = new Mock<IMyDataService<Book>>();
mockDataService.Setup(c=> c.Update(It.Any<Book>(),It.Any<int>()).Returns(updatedbook);
The service should be dependent on the repository. Passing the context directly to the service is misleading as what the service really needs and uses is the repository.
Your classes should depend on abstractions and not on concretions. That said, all the above classes could be abstracted behind interfaces. but for now I'll focus on the service class and it's dependence on the repository. You are coupling different layers too closely. Service layer doesn't need to know about data context
Abstract the repository to allow for easier testability
interface IGenericRepository<TObject> where TObject : class {
TObject Update(TObject data, int id);
}
public class GenericRepository<TObject> : IGenericRepository<TObject> where TObject : class {
protected readonly MyDataContext Context;
public GenericRepository(MyDataContext context) {
Context = context;
}
public virtual TObject Update(TObject data, int id) {
if (data == null)
return null;
TObject obj = Context.Set<TObject>().Find(id);
if (obj != null) {
Context.Entry(obj).CurrentValues.SetValues(data);
Context.SaveChanges();
}
return obj;
}
}
The service would only now need to know about the repository abstraction, not its implementation details.
public class MyDataService<TObject> where TObject : class {
private readonly IGenericRepository<TObject> repository;
public MyDataService(IGenericRepository<TObject> repository) {
this.repository = repository;
}
public TObject Update(TObject obj, int id) {
return repository.Update(obj, id);
}
}
So now the service can be tested in isolation without any need to worry about any data context
//Arrange
var updatedBook = new Book { Name = "Update Book Name" };
var id = 1;
var mockRepository = new Mock<IGenericRepository<Book>>();
mockRepository
.Setup(m => m.Update(updatedBook, id))
.Returns(updatedBook);
var service = new MyDataService<Book>(mockRepository.Object);
//Act
var data = service.Update(updatedBook, id);
//Assert
//...
When it's time to unit test the repository implementation in isolation, then you can follow the same structure and abstract the context for the repository implementation.
I would suggest the small refactoring in order to make the testing easier and even possible. With this implementation you are relying on the implementation of the DbContext and DbEntityEntry.
At first extract interface for your context:
public inteface IMyDataContext<TObject> where TObject is class
{
TObject FindById(int id); //call FindId
void Update(TObject); //call DbEntityEntry SetValues
void SaveChanges();
}
In the GenericRepository then inject the interface. This will make your life easier, you can then easily mock all method. Unit tests of the repository should verify that right methods of the context are called.

Simple Injector with Generic interfaces and composition - Not registering interfaces

I am moving from inheritance to compositon, as you can see from here https://stackoverflow.com/questions/29653153/composition-migrating-from-inheritance
Now i have got it all working, but simple injector wants me to manually register each interface with each type being passed in. Here is the striped down code.
I have IBaseEntityService, which BaseEntityService implements, like so
public interface IEntityBaseService<T> where T : class, IEntityBase
{
IDataContext Context { get; }
Task<ICollection<T>> GetAllAsync();
Task<T> GetAsync(long id);
}
public class EntityBaseService<T> : IEntityBaseService<T>
where T : class, IEntityBase
{
protected IDataContext _context;
public IDataContext Context
{
get
{
return _context;
}
}
public EntityBaseService(IDataContext context)
{
_context = context;
}
public async Task<ICollection<T>> GetAllAsync()
{
return await _context.Set<T>().ToListAsync();
}
public Task<T> GetAsync(long id)
{
return _context.Set<T>().Where(e => e.Id == id).FirstOrDefaultAsync();
}
}
Now i have a IValidationService and ValidationService implements that, like so
public interface IValidationService<T>
where T : class, IEntityBase
{
Task<ValidationResult> ValidateAsync(T entity);
Task<int> AddAsync(T entity);
Task<int> UpdateAsync(T entity);
}
public class ValidationService<T> : IValidationService<T>
where T : class, IEntityBase
{
private IEntityBaseService<T> _service;
private IValidator<T> _validator = null;
public IDataContext Context
{
get
{
return _service.Context;
}
}
public ValidationService(IEntityBaseService<T> service, IValidator<T> validator)
{
_service = service;
_validator = validator;
}
public Task<ValidationResult> ValidateAsync(T entity)
{
if (_validator == null) throw new MissingFieldException("Validator does not exist for class " + entity.GetType().ToString() + ". override method if no validation needed");
return _validator.ValidateAsync(entity);
}
public async Task<int> AddAsync(T entity)
{
var results = await ValidateAsync(entity);
if (!results.IsValid)
{
throw new ValidationException(results.Errors);
}
return await _service.AddAsync(entity);
}
public async Task<int> UpdateAsync(T entity)
{
var results = await ValidateAsync(entity);
if (!results.IsValid)
{
throw new ValidationException(results.Errors);
}
return await _service.UpdateAsync(entity);
}
}
Now i can use services, and pass in each interface. So i have a IContentService and ContentService which implements that. This service uses both IEntityBaseService and IValidationService
public interface IContentService
{
Task<Content> GetAsync(long id);
Task<int> AddAsync(Content entity);
Task<int> UpdateAsync(Content entity);
}
public class ContentService : IContentService
{
private IEntityBaseService<Content> _service;
private IValidationService<Content> _validation;
public ContentService(IEntityBaseService<Content> service, IValidationService<Content> validation)
{
_service = service;
_validation = validation;
}
public async Task<Content> GetAsync(long id)
{
var content = await _service.Context.Contents
.Where(e => e.Id == id)
.WhereNotDeleted()
.FirstOrDefaultAsync();
if (content != null)
{
content.Attachments = await _service.Context.Attachments
.Where(e => e.ContentId == id)
.WhereNotDeleted()
.ToListAsync();
}
return content;
}
public Task<int> AddAsync(Content entity)
{
return _validation.AddAsync(entity);
}
public Task<int> UpdateAsync(Content entity)
{
return _validation.UpdateAsync(entity);
}
}
Now in my config file, i have this, which works, but if i have another service, and i have about 20 of them, i do not want to type this out for each one.
container.Register<IEntityBaseService<Content>, EntityBaseService<Content>>();
container.Register<IValidationService<Content>, ValidationService<Content>>();
container.Register<IValidator<Content>, ContentValidator>();
container.Register<IContentService, ContentService>();
So i looked online and i think i can use the RegisterManyForOpenGeneric method instead of registering IEntityBaseService and IValidatioNService, but i cannot get it too work. I have wrote
container.RegisterManyForOpenGeneric(typeof(IEntityBaseService<>), typeof(IEntityBaseService<>).Assembly);
container.RegisterManyForOpenGeneric(typeof(IValidationService<>), typeof(IValidationService<>).Assembly);
And i get an error saying
The constructor of type ContentService contains the parameter of type
IEntityBaseService with name 'service' that is not
registered. Please ensure IEntityBaseService is registered in
the container, or change the constructor of ContentService.
Maybe i have set up my entities incorrectly, so just encase, here are the basic entities for this example
public interface IEntityBase
{
long Id { get; set; }
}
public abstract class EntityBase : IEntityBase
{
public long Id { get; set; }
}
public class Content : EntityBase, IAudit
{
public short Position { get; set; }
public Content()
{
Position = 1;
}
}
Any help much appreciated on both simple injector and the code in general
You're using the wrong registration method.
RegisterManyForOpenGeneric exists to support the following scenario:-
container.Register<IValidate<Customer>, CustomerValidator>();
container.Register<IValidate<Employee>, EmployeeValidator>();
container.Register<IValidate<Order>, OrderValidator>();
container.Register<IValidate<Product>, ProductValidator>();
// can replace the above with the following:-
container.RegisterManyForOpenGeneric(
typeof(IValidate<>),
typeof(IValidate<>).Assembly);
By default RegisterManyForOpenGeneric searches the supplied assembly for all types that implement the [specified open generic] interface and registers each type by their specific (closed generic) interface. [Emphasis mine]
Note how the concrete types aren't themselves generic (i.e. CustomerValidator implements the closed generic interface IValidate<Customer>). This works fine for your ContentValidator but is no good for open generic classes implementing open generic interfaces like your EntityBaseService<Content> and ValidationService<Content>.
You're looking for:-
container.RegisterOpenGeneric(
typeof(IEntityBaseService<>),
typeof(EntityBaseService<>));
RegisterManyForOpenGeneric has been marked obsolete now.
container.Register(typeof(IValidator<>), new[] { typeof(IValidator<>).Assembly });
Is the way to go now.
http://simpleinjector.readthedocs.org/en/latest/advanced.html

Categories

Resources