代码之家  ›  专栏  ›  技术社区  ›  Beep beep

当关键类需要会话(或其他上下文特定变量)时如何设置IOC

  •  9
  • Beep beep  · 技术社区  · 15 年前

    我正在尝试解决如何在依赖类可以根据应用程序中的某个变量(在本例中是会话状态)进行更改的情况下使用IOC。例如,我们的每个客户机都有一个不同的数据库,因此到数据库的连接需要建立在其会话中存储的值上(特别是因为有些用户如果拥有多个业务,可能拥有多个数据库,并且会在数据库之间切换)。

    下面是我们当前如何设置此结构的一般示例:

    public class MyTestController : ControllerBase
    {
        Repository _rep;
    
        public MyTest(Repository rep)
        {
            _rep = rep;
        }
    
        public MyTest()
        {
            string connString = String.Format("Server={0}; Database={1};"
                , SessionContainer.ServerName, SessionContainer.DatabaseName;
            var dc = new DataContext(connString);
            _rep = new Repository(dc);
        }
    
        public int SampleFn()
        {
            return _rep.GetCountOfEmployees();
        }
    }
    
    public class Repository
    {
        DataContext _context;
    
        public Repository(DataContext context)
        {
            _context = context;
        }
    } 
    

    我们是否可以使用IOC来设置并消除默认的C-TOR?如果是这样,怎么办?我在使用这样的D.I.时没有问题,但我想探讨结构映射或统一的可能性(注意:我们通常将db/server传递给一个构建数据上下文的工厂类…上面的例子只是为了简洁)。

    1 回复  |  直到 14 年前
        1
  •  14
  •   Mark Seemann    15 年前

    存储库实例的创建方式及其生存期与控制器无关。

    在容器中注册组件时,应指定组件的生存期。根据您的实现,您可以简单地选择设置存储库的生命周期以跟踪会话。

    在任何情况下,您都可以使用工厂从会话创建存储库,但要从控制器外部进行此操作。

    您肯定需要去掉默认的构造函数。


    在我的头顶上,我不记得如何在Unity或StructureMap中做到这一点,所以这里有一个温莎城堡的例子。

    定义抽象工厂:

    public interface IRepositoryFactory
    {
        Repository Create();
    }
    

    以及一个实现

    public class MyRepositoryFactory : IRepositoryFactory
    {
        private readonly HttpContextBase httpContext;
    
        public MyRepositoryFactory(HttpContextBase httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }
    
            this.httpContext = httpContext;
        }
    
        #region IRepositoryFactory Members
    
        public Repository Create()
        {
            // return Repository created from this.httpContext
        }
    
        #endregion
    }
    

    现在登记所有的东西

    container.AddFacility<FactorySupportFacility>();
    container.Register(Component.For<IRepositoryFactory>()
        .ImplementedBy<MyRepositoryFactory>()
        .LifeStyle.PerWebRequest);
    container.Register(Component.For<Repository>()
        .UsingFactory((IRepositoryFactory f) => f.Create())
        .LifeStyle.PerWebRequest);
    

    这里我使用了PerwebRequest的生活方式,但是如果你想优化,你可能想创建一个自定义的PerwebSession生活方式。在城堡里这并不难,但我不记得在其他DI容器里有多难。

    您还需要注册httpContextBase,因为myrepositoryFactory依赖它。