【问题标题】:How to use the same DI code in asp.net and a windows service如何在 asp.net 和 windows 服务中使用相同的 DI 代码
【发布时间】:2011-06-21 01:20:45
【问题描述】:

我有一个关于如何在 ASP.NET mvc 应用程序和 Windows 服务中使用相同 DI 代码的问题,因为它们都使用 NHibernate 与同一个数据库进行交互。但是,Windows 服务会执行后台任务。

和大家一样,我有一个新的控制器工厂,它知道如何使用 StructureMap 实例化控制器。因此,我可以将所需的存储库作为其构造函数的参数提供给我的控制器。由于 Structuremap 使用 HTTPContextScope 控制 ISession 生命周期,因此我可以确定所有存储库都会为每个 Web 请求接收相同的 ISession 实例。

但是,在 Windows 服务中并使用 Structuremap(相同的 DI 代码),我不知道有一种很好的方法可以在逻辑上隔离不同的后台任务以拥有一个唯一的 ISession 实例并与他们使用的存储库共享它。我希望同时执行多个任务,因此 ISession 不能是单例对象(推荐用于使用 NHibernate 的桌面应用程序)。

我想在我的 Windows 服务信任结构映射中保留并引入每个请求一个会话模式,以便为每个任务提供相同的 ISession 实例。谁能指出我正确的方向?

谢谢


编辑

Corey Coogan 的这两部分帖子非常符合我认为应该解决这个问题的思路。但是,我对 WCF 并不熟悉,并且容易对文章中的部分感到困惑。

http://blog.coreycoogan.com/2010/05/26/structuremap-wcf-nhibernate-part-1/ http://blog.coreycoogan.com/2010/05/27/structuremap-wcf-nhibernate-part-2/

【问题讨论】:

    标签: asp.net asp.net-mvc dependency-injection structuremap


    【解决方案1】:

    在我的 Windows 服务中,我有一个引导程序,它与 ASP.NET MVC 中的引导程序完全相同:

    public static class Bootstrapper
    {
        public static void Initialize()
        {
            StructureMap.ObjectFactory.Initialize(cfg =>
            {
                cfg.UseDefaultStructureMapConfigFile = false;
                cfg.IgnoreStructureMapConfig = true;
                cfg.AddRegistry<Web.Core.DI.NhibernateRegistry>();
                cfg.AddRegistry<Web.Core.DI.DomainRegistry>();
                cfg.AddRegistry<Web.Core.DI.ServicesRegistry>();
                cfg.AddRegistry<Web.Core.DI.QuartzRegistry>();
            });
            ServiceLocator.SetLocatorProvider(() => new StructureMapServiceLocator(ObjectFactory.Container));
        }
    }
    

    然后我为每个模块定义了一个注册表:

    public class NhibernateRegistry: Registry
    {
        public NhibernateRegistry()
        {
            SchemaOperation schemaOperation = SchemaOperation.None; 
    
            For<ISessionFactory>()
                .Singleton()
                .Use(new BpReminders.Data.NH.NHibernateSessionFactory(connectionString, schemaOperation).SessionFactory);
    
            For<IUnitOfWork>()
                .HybridHttpOrThreadLocalScoped()
                .Use<BpReminders.Data.NH.UnitOfWork>();
    
            For<ISession>()
                .HybridHttpOrThreadLocalScoped()
                .Use(o => ((BpReminders.Data.NH.UnitOfWork)o.GetInstance<IUnitOfWork>()).CurrentSession);
        }
    }
    

    服务启动后,我会立即引导所有内容:

    protected override void OnStart(string[] args)
    {
        Bootstrapper.Initialize();
    }
    

    最后我采用了单例模式,因为我的 Windows 服务不使用任何额外的线程。 我知道 StructureMap 有一个关键字 AlwaysUnique,它可能对您尝试做的事情有用:

    For<ISession>()
        .AlwaysUnique()
    

    代码 cmets 说(关于 AlwaysUnique)

    /// 强制 StructureMap 始终使用唯一实例
    /// 停止“BuildSession”缓存

    你必须深入研究这个,因为我刚刚做了几个测试。不多。

    【讨论】:

      【解决方案2】:

      我认为你可以使用 ThreadLocal Lifeycle。我自己从未使用过它,但听起来像您要找的东西:

      PerRequest - 默认操作。一种 将为每个创建新实例 要求。单身人士 - 单身人士 实例将在所有人之间共享 请求

      ThreadLocal - 将为每个请求线程创建一个实例。 缓存实例 线程本地存储。

      HttpContext - 单个实例将 为每个 HttpContext 创建。 将实例缓存在 HttpContext.Items 集合。

      HttpSession - 单个实例将 为每个 HttpSession 创建。 将实例缓存在 HttpContext.Session 集合。采用 慎用。

      Hybrid - 使用 HttpContext 存储,如果 它存在,否则使用 ThreadLocal 存储

      【讨论】:

      • 我认为你是对的,但我不知道从哪里开始。可以举个例子吗?
      猜你喜欢
      • 1970-01-01
      • 2018-02-24
      • 1970-01-01
      • 2012-02-29
      • 1970-01-01
      • 1970-01-01
      • 2018-07-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多