Is there a way in StructureMap to do this kind of repetitive mapping with one line or a convention?
For<IRepository<Mailout>>().Use<MailoutRepository>();
For<IRepository<MailServer>>().Use<MailServerRepository>();
For<IRepository<MailoutStatus>>().Use<MailoutStatusRepository>();
For<IRepository<MailoutTemplate>>().Use<MailoutTemplateRepository>();
For<IRepository<Publication>>().Use<PublicationRepository>();
For<IRepository<Recipient>>().Use<RecipientRepository>();
To map IRepository<Mailout>
to MailoutRepository
, use:
var c = new Container(x =>
{
x.Scan(scan =>
{
// there are other options to expand which assemblies to scan for types
scan.TheCallingAssembly();
scan.ConnectImplementationsToTypesClosing(typeof (IRepository<>));
});
});
To map IRepository<Mailout>
to Repository<Mailout>
, use:
var c = new Container(x =>
{
x.For(typeof (IRepository<>)).Use(typeof (Repository<>));
});
You could greate something like Repository base :
public class RepositoryBase<T> : IRepository<T> where T : Entity
then have something like this :
public class UserRepository : RepositoryBase<User>, IUserRepository
public class OtherRepository : RepositoryBase<Other>, IOtherRepository
where your repositories interfaces impelement the generic repository interface like that :
public interface IUserRepository : IRepository<User>
public interface IOtherRepository : IRepository<Other>
and then you could register it like that :
For(typeof (IRepository<>)).Use(typeof (RepositoryBase<>));
It works for me.
Here's a workaround, as we couldn't find any shorter way of making that mapping.
First, map to an open generic implementation class, as discussed elsewhere:
For(typeof(IRepository<>)).Use(typeof(ConcreteRepository<>));
Then, for each repository with custom behavior, add extension methods on the appropriate interface. For instance, supposing your MailoutStatusRepository
has a method GetStatus()
, you might translate that to an extension method on IRepository<MailoutStatusRepository>
:
public static Status GetStatus(this IRepository<MailoutStatusRepository> repo,
Mailout mail)
{
return mail.Status; // or whatever
}
Now you have the custom repository behavior without having to worry about casting StructureMap's output to some custom class:
var repo = container.GetInstance<IRepository<MailoutStatusRepository>>();
var status = repo.GetStatus(mailout);
Another benefit of this approach is that your custom repository behavior works regardless of your repository implementation: in tests and in production code. The only downside (I think) is that your repositories are necessarily stateless, but we haven't found this to be a problem at all.
Scan(x =>
{
x.WithDefaultConventions();
x.AssemblyContainingType(typeof(UserRepository));
x.AddAllTypesOf(typeof(Repository<>));
x.ConnectImplementationsToTypesClosing(typeof(IRepository<>));
});
WithDefaultConventions is the important part of the shown code, because with this setting you say StructureMap to use the convention of mappping IUserRepository to UserRepository . So StructureMap proceed from the assumption that the class is named like the name of the interface without the prefix I.