简体   繁体   English

在这种情况下,如何使用StructureMap DI?

[英]How can I use StructureMap DI for this situation?

I have a class called unitofwork which implements IUnitOfWork 我有一个叫做unitofwork的类,它实现了IUnitOfWork

public class UnitOfWork : IUnitOfWork
{
    private readonly IDbContext _context;

    private bool _disposed;
    private Hashtable _repositories;

    public UnitOfWork(IDbContext dbContext)
    {
        _context = dbContext;

    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    public void Save()
    {
        _context.SaveChanges();
    }

    public virtual void Dispose(bool disposing)
    {
        if (!_disposed)
            if (disposing)
                _context.Dispose();

        _disposed = true;
    }

    public IRepository<T> Repository<T>() where T : class
    {
        if (_repositories == null)
            _repositories = new Hashtable();

        var type = typeof(T).Name;

        if (!_repositories.ContainsKey(type))
        {
            var repositoryType = typeof(BaseRepository<>);

            var repositoryInstance =
                Activator.CreateInstance(repositoryType
                                             .MakeGenericType(typeof(T)), _context);

            _repositories.Add(type, repositoryInstance);
        }

        return (IRepository<T>)_repositories[type];
    }
}

And two classes which implement IDbContext 还有两个实现IDbContext

 public class SecurityContext:IDbContext{}
 public class HrContext:IDbContext{}

I also have two controllers, which depend on IUnitOfWork 我也有两个控制器,它们依赖于IUnitOfWork

public LoginController(IUnitOfWork _securityContextUow)
{
    // Here the injected unitofwork 
    // object must have  SecurityContext ,as its dependent instance
}

public SalaryController(IUnitOfWork _hrContextUow)
{
    // Here the injected unitofwork 
    // object must have  HrContext,as its dependent instance
}

How can I configure StructureMap to achieve this? 如何配置StructureMap来实现此目的? In my current configuration, I can only configure one instance for IDbContext 在当前配置中,我只能为IDbContext配置一个实例

x.For<IDbContext>().Use<SecurityContext>();

Summary: I want to inject an instance of unitofwork with SecurityContext to LoginController and inject an instance of unitofwork with HrContext to SalaryController . 摘要:我要注入的一个实例unitofworkSecurityContextLoginController ,注入的一个实例unitofworkHrContextSalaryController To do that what are the configuration /changes in constructor required ? 为此,构造函数需要进行哪些配置/更改?

If the UnitOfWork logic is common then the easiest solution is to make UnitOfWork generic 如果UnitOfWork逻辑是通用的,那么最简单的解决方案是使UnitOfWork通用

interface IUnitOfWork<TContext> where TContext: IDbContext { }

public class UnitOfWork<TContext> : IUnitOfWork<TContext>
    where TContext : IDbContext
{
    private readonly TContext context;

    public UnitOfWork(TContext context)
    {
        this.context = context;
    }
}

Then, using the following syntax to register the UnitOfWork and the IDbContext 's 然后,使用以下语法注册UnitOfWorkIDbContext

ObjectFactory.Configure(x =>
{
    x.For(typeof(IUnitOfWork<>)).Use(typeof(UnitOfWork<>));
});

You can control which IDbContext is injected into the UnitOfWork 您可以控制将哪个IDbContext注入到UnitOfWork

public LoginController(IUnitOfWork<SecurityContext> securityContextUow) { }

public SalaryController(IUnitOfWork<HrContext> hrContextUow) { }

Here's a quick unit test to prove it works as expected 这是一个快速的单元测试,可以证明它能按预期运行

public class TestUnitOfWork<TContext> : IUnitOfWork<TContext>
    where TContext : IDbContext
{
    public TContext context { get; set; }

    public TestUnitOfWork(TContext context)
    {
        this.context = context;
    }
}

[Test]
public void GetCorrectUnitOfWork()
{
    ObjectFactory.Configure(x =>
    {
        x.For(typeof(IUnitOfWork<>)).Use(typeof(TestUnitOfWork<>));
    });

    //ObjectFactory.AssertConfigurationIsValid();

    var securityContextUow = ObjectFactory
        .GetInstance<IUnitOfWork<SecurityContext>>();
    var hrContextUow = ObjectFactory
        .GetInstance<IUnitOfWork<HrContext>>();

    Assert
        .That((securityContextUow as TestUnitOfWork<SecurityContext>).context, 
        Is.InstanceOf<SecurityContext>());
    Assert
        .That((hrContextUow as TestUnitOfWork<HrContext>).context, 
        Is.InstanceOf<HrContext>());
}

One approach would be to separate everything out a little more so that you have extra interfaces for each unit of work and related classes. 一种方法是将所有内容分开一些,以便为每个工作单元和相关类提供额外的接口。 Something like this: 像这样:

public interface ISecurityContext : IDbContext {}

public interface IHrContext : IDbContext {}

public interface ISecurityUnitOfWork : IUnitOfWork {}

public interface IHrUnitOfWork : IUnitOfWork {}

Then your unit of work classes take in the relevant context: 然后,您的工作单元类别将包含以下相关上下文:

public class SecurityUnitOfWork : UnitOfWork,ISecurityUnitOfWork 
{
    public SecurityUnitOfWork(ISecurityContext context)
        : base(context)
    {
        // This change
    }    

} }

And your controller can take in the relevant unit of work: 您的控制器可以接管相关的工作单元:

public LoginController(ISecurityUnitOfWork securityUnitOfWork)
{
}

You still have the base IUnitOfWork and IDbContext interfaces but now have a logically related grouping for each set of operations. 您仍然具有基本的IUnitOfWorkIDbContext接口,但是现在对每组操作都有一个逻辑相关的分组。 It's a bit more heavyweight than the approach you're looking for but it should make your DI resolution simpler to understand. 它比您正在寻找的方法要重一些,但是它应该使您的DI分辨率更易于理解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM