StructureMap - how to register and enable an open generic type

public interface IRepository<T> where T : Entity { void Delete(T entity); T[] GetAll(); T GetById(int id); void SaveOrUpdate(T enity); void Merge(T entity); } public interface ITeamEmployeeRepository : IRepository<TeamEmployee> { PagedList<TeamEmployee> GetPagedTeamEmployees(int pageIndex, int pageSize); } public class Repository<T> : IRepository<T> where T : Entity { private readonly ISession _session; protected Repository() { _session = GetSession(); } public virtual void Delete(T entity) { _session.Delete(entity); } public virtual T[] GetAll() { return _session.CreateCriteria<T>().List<T>().ToArray(); } public virtual T GetById(int id) { return _session.Get<T>(id); } public virtual void SaveOrUpdate(T enity) { _session.SaveOrUpdate(enity); } public void Merge(T entity) { _session.Merge(entity); } protected ISession GetSession() { return new SessionBuilder().GetSession(); } } public class TeamEmployeeRepository : Repository<TeamEmployee>, ITeamEmployeeRepository { public PagedList<TeamEmployee> GetPagedTeamEmployees(int pageIndex, int pageSize) { return GetSession().QueryOver<TeamEmployee>() .Fetch(x => x.Employee).Eager .Fetch(x => x.Team).Eager .ToPagedList(pageIndex, pageSize); } } 

Now I register the repository as follows:

 For<ILoanedItemRepository>().Use<LoanedItemRepository>(); For<ITeamEmployeeRepository>().Use<TeamEmployeeRepository>(); For<IArticleRepository>().Use<ArticleRepository>(); For<ISalesmanRepository>().Use<SalesmanRepository>(); For<ISalesmanArticleRepository>().Use<SalesmanArticleRepository>(); For<IGoodsGroupRepository>().Use<GoodsGroupRepository>(); For<IEmployeeRepository>().Use<EmployeeRepository>(); 

This is really cumbersome, especially if new repositories appear.

Simpler and more convenient registration:

 For(typeof(IRepository<>)).Use(typeof(Repository<>)); 

But that does not work. Each time, StructureMap tells me that there is no default instance defined for PluginFamily Core.Domain.Bases.Repositories.ITeamEmployeeRepository.

I searched on stackoverflow and found something new:

 Scan(x => { x.AssemblyContainingType(typeof(TeamEmployeeRepository)); x.AddAllTypesOf(typeof (IRepository<>)); x.ConnectImplementationsToTypesClosing(typeof(IRepository<>)); }); 

But this is the same error message.

How do I register my repositories with StructureMap 2.6.1.0?

+6
c # repository ioc-container structuremap
source share
4 answers

I have found a solution.

 Scan(x => { x.WithDefaultConventions(); x.AssemblyContainingType(typeof(TeamEmployeeRepository)); x.AddAllTypesOf(typeof(Repository<>)); x.ConnectImplementationsToTypesClosing(typeof(IRepository<>)); }); 

WithDefaultConventions is an important part of the code shown because you use this parameter to indicate that StructureMap uses the agreement to convert ITeamEmployeeRepository to TeamEmployeeRepository. So, StructureMap assumes that the class is called the name of the interface without the I prefix.

+7
source share

I found this googling question "structuremap solve generic". Existing answers are good, but complex. For those who are looking for a simple answer: for the ISome interface and implementation class. We are writing

 c.For<ISome>().Use<Some>() 

While for the general ISome <T> and the implementation of the Some <T> class, we write

 c.For(typeof(ISome<>)).Use(typeof(Some<>)) 

And that's all

+2
source share

I recently decided something similar by making a small redesign that made everything a lot easier. This might work for you too. You can try to remove specific interfaces, such as ITeamEmployeeRepository and ILoanedItemRepository from your project. The way I did it was using extension methods. Here is an example:

 public static class RepositoryExtensions { public static TeamEmployee GetById( this IRepository<TeamEmployee> repository, int id) { return repository.Single(e => e.TeamEmployeeId == id); } public static IQueryable<Salesman> GetActiveSalesmen( this IRepository<ISalesmanRepository> repository) { return repository.Where(salesman => salesman.Active); } // etc } 

After that, I created an IRepositoryFactory that allowed me to create repositories of a specific type:

 public interface IRepositoryFactory { IRepository<T> CreateNewRepository<T>(); } 

Using this interface, it is easy to create an implementation of this factory that asks the container to create a specific Repository<T> . RepositoryFactory might look like this:

 public class RepositoryFactory : IRepositoryFactory { public IRepository<T> CreateNewRepository<T>() { return ObjectFactory.GetInstance(typeof(Repository<T>)); } } 

With this construct, you only need to register a specific RepositoryFactory using the IRepositoryFactory interface, and you're done. Instead of injecting an IRepository<ITeamEmployeeRepository> into an old project, you now enter an IRepositoryFactory and let the client call the CreateNewRepository<T> method. Due to the use of extension methods, you can invoke type-specific methods in the repository.

Another advantage of this is that you do not need to ITeamEmployeeRepository methods that were originally defined in ITeamEmployeeRepository for each implementation.

This project worked very well in my situation, especially because my IRepository<T> interfaces use expression trees. Of course, it is not possible for me to see if such a design works for you, but I hope that it does.

Good luck.

-one
source share

You will need to create your own ITypeScanner and register it in your Scan() call. See the GenericConnectionScanner source code as a starting point. Instead of looking for types to see if they implement IRepository<T> , you will see if they implement any interface that implements IRepository<T> , and then register the type for that interface.

UPDATE: All the talk about IRepository<T> made me change my mind when these are really irrelevant details. Just use the DefaultConventions scanner suggested by Rookian.

-2
source share

All Articles