2014-04-01 48 views
3

我正在开发一个Windows服务将举办两件事情:SimpleInjector结合WCF和“正规”注册

  • WCF服务
  • 一个周期性作业执行“常规”窗口服务(使用Quartz.net )

因此,基本上,一个应用程序(可执行文件)的托管这两种服务类型。

这两种服务类型需要使用存储库和其他注射依赖。我正在使用SimpleInjector。

我已经得到了WCF部分启动和运行,使用SimpleInjectors WCF的一些推广:

public class DependencyResolver : IPackage 
{ 
    public void RegisterServices(Container container) 
    { 
     container.EnablePerWcfOperationLifestyle(); 
     var wcfLifestyle = new WcfOperationLifestyle(); 

     container.Register<IUnitOfWork, UnitOfWork>(wcfLifestyle); 
     container.Register<ICustomerRepository, CustomerRepository>(wcfLifestyle); 
     //etc... 

     container.RegisterWcfServices(Assembly.GetExecutingAssembly()); 
    } 
} 

我的问题:我可以重复使用这些存储库和其他注册的“常规”窗口服务部内,即一个NOT使用WCF?因为我不知道该WcfOperationLifestyle将如何影响他们,如果我这样做。

我想每一个石英作业点火时间,需要一个或多个库使用短暂的生活方式。并且,在该作业正在运行时,显然会有WCF调用进来,然后应该使用独立于当前在计划作业中使用的存储库的新存储库实例。

我应该创建新的注册吗?如果是这样,那么我应该如何从执行的代码中调用它们?

感谢

+0

请您描述或给出一个关于您如何做自己托管的WCF + WindowsService + SimpleInjectors(特别感兴趣的DI)的链接 – aleha

回答

3

这不太可能对任何部件有一个范围的生活方式在一个其他部分的应用程序(WCF)和充当过渡的一个组成部分。在你的情况下,你的工作单元很可能也必须在Quartz中作用域,但由于没有隐式作用域(例如HTTP请求,WCF会话等),你将不得不明确地开始/结束一些作用域这些操作运行并注册它们。

简单的喷油器有几个隐含的特定技术范围的生活方式,例如:

  • WebApiRequestLifestyle
  • WebRequestLifestyle
  • WcfOperationLifestyle

明确scped的生活方式是:

  • LifetimeScopeLifestyle(它定义了一个 线程特定范围)
  • ExecutionContextScopingLifestyle(它定义了一个异步上下文特定范围)。

因此,在Quartz内部运行时,您的工作单元应该有LifetimeScopeLifestyleExecutionContextScopeLifestyle。两者之间的选择很简单:如果操作是异步的并且您的方法返回Task<T>,则需要ExecutionContextScopeLifestyle,否则需要LifetimeScopeLifestyleThis Q/A提供了有关如何启动和lifetimescope与石英的更多信息。

考虑到这一点

所以,我认为你基本上有三种选择:

  1. 见碰巧住在同一个AppDomain中这两种服务(WCF和Quartz)作为两个独立的应用程序,并创建两个Composition Roots每个他们自己的SimpleInjector.Container实例。 (你也可能要考虑真正分裂服务了两个单独的服务应用程序)
  2. 您沟WCF的生活方式和解决执行该操作的服务前明确开始在每个WCF操作的新LifetimeScope
  3. 将两个服务看作是一个内在整体,并且有一个组合根与一个容器,但在WCF服务类中保留使用依赖注入。这意味着你将不得不使用混合生活方式来获得适当的生活方式。

哪个选项最适合您取决于很多因素。例如,创建两个组合根可能非常容易,通过将共同注册提取到共享方法,可以使组合根很好地维护。所有范围内的生活方式都从ScopedLifestyle继承,这允许你让这个共享方法接受ScopedLifestyle,这允许共享方法不知道被调用哪个服务。当变得很难的是当你有完整的AppDomain中只有一个实例必须存活的组件时(因为Singleton意味着'每个容器一个')。

而不是让你的WCF服务有任何逻辑,你可以让它们成为真正的薄层,它们只是WCF,你的IOC容器和应用程序之间的粘合剂。因此,而不是依赖注入到你的WCF服务,你可以简单地解决实际服务时,WCF操作被称为:

[OperationContract] 
public SomeData DoSomething() { 
    using (Bootstrapper.Container.BeginLifetimeScope()) { 
     return Bootstrapper.Container.GetInstance<IDoSomethingService>() 
      .DoSomething(); 
    } 
} 

这使您可以用相同的LifetimeScopeLifestyle注册所有范围的部件。当你有一个消息驱动的体系结构时,这个模型工作得很好,因为这意味着你的WCF层最多可以包含两个方法,可以被读取为here。这种方法可以让事情变得更容易,因为WcfOperationLifestyle有一点意外的行为,因为它的每WCF操作“不缓存服务,而是为WCF服务类(包含这些操作方法的类)的持续时间,并在最后它是WCF,而你的配置决定了这种服务应该存在多长时间。这可以是PerCall, PerSession or even Single。然而,这种方法的缺点是,如果你有一个非常宽泛的WCF服务(有许多方法),你可能需要重构很多才能达到这个目的,并且在你的WCF服务类中有很多仪式。

第三个选项是如下使用一个混合的生活方式:

ScopedLifestyle hybridLifestyle = Lifestyle.CreateHybrid(
    container.GetCurrentWcfOperationScope() != null, 
    new WcfOperationLifestyle(), 
    new LifetimeScopeLifestyle()); 

container.Register<IUnitOfWork, UnitOfWork>(hybridLifestyle); 

您可以使用此hybridLifestyle的生活方式注册您的实例。这允许您的配置与两个WCF一起作为外部WCF工作。这当然意味着你必须明确地开始一个生命周期范围,如讨论here

+0

非常感谢您对此进行的解释。你会推荐将WCF和Windows服务分成两个单独的exe文件吗?我想知道是否有通常的做法,让Windows服务运行预定的作业,同时有一个WCF外观允许交互。 – tjeuten

+0

@tjeuten:我会说这是常见的做法。 IIS在回收(查杀)AppDomain方面非常积极,而且您的后台进程可能会受此影响。 – Steven

+0

好的,谢谢,我知道IIS回收,因此决定在Windows服务中托管WCF服务。我的意思是询问在同一个Windows服务应用程序域(可执行文件)中托管WCF和周期性作业是否是常见做法 – tjeuten