How to use a convention for IRepository with St

2019-04-08 21:07发布

问题:

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>();

回答1:

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<>));
});


回答2:

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.



回答3:

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.



回答4:

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.