在单独的线程中运行Windows服务并使用autofac进行DI

时间:2013-06-28 03:35:14

标签: multithreading windows-services autofac

我正在尝试创建一个长时间运行的Windows服务,所以我需要在一个单独的线程上运行实际的worker类,以避免当我右键单击并选择start时“服务没有及时响应”错误在Windows服务管理器中。

worker类(“NotificationProcess”)有很多依赖项,我正在使用Autofac来满足这些要求。

我真的不确定如何为worker类设置Autofac。目前,当我在工人类的“执行”方法中使用它时,我收到错误告诉我DbContext已被处理。

我想我正在寻找如何编写一个Windows服务并为工作类使用一个新线程,其中依赖项由autofac满足。

我用谷歌搜索,找不到任何这方面的例子。

任何建议都很棒。

这是我到目前为止所得到的......

的Program.cs:

    static class Program
{
    static void Main()
    {
        using (var container = ServiceStarter.CreateAutoFacContainer())
        {
            var service = container.Resolve<NotificationService>();
            if (Environment.UserInteractive)
            {
                service.Debug();
            }
            else
            {
                ServiceBase.Run(container.Resolve<NotificationService>());
            }
        }

服务类:

public partial class NotificationService : ServiceBase
{
    private NotificationProcess _app;
    readonly ILifetimeScope _lifetimeScope;

    public NotificationService(ILifetimeScope lifetimeScope)
    {
        _lifetimeScope = lifetimeScope;
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        _app = _lifetimeScope.Resolve<NotificationProcess>();
        _app.Start();
    } 

工人阶级:

    public class NotificationProcess
{
    private Thread _thread;

    private readonly IBankService _bankService;
    private readonly IRateService _rateService;
    private readonly IEmailService _emailService;
    private readonly IRateChangeSubscriberService _rateChangeSubscriberService;
    private readonly IRateChangeNotificationService _rateChangeNotificationService;
    private readonly ILogManager _logManager;

    public NotificationProcess(IBankService bankService, ILogManager logManager, IRateService rateService, IEmailService emailService, 
        IRateChangeSubscriberService rateChangeSubscriberService, IRateChangeNotificationService rateChangeNotificationService)
    {
        _bankService = bankService;
        _rateService = rateService;
        _emailService = emailService;
        _rateChangeSubscriberService = rateChangeSubscriberService;
        _rateChangeNotificationService = rateChangeNotificationService;
        _logManager = logManager;
    }

    public void Start()
    {
        _thread = new Thread(new ThreadStart(Execute));
        _thread.Start();
    }

    public void Execute()
    {
        try
        {
            var rateChangeToNotify = _rateService.GetRateChangesForNotification();

            foreach (var rateChange in rateChangeToNotify)
            {
                 //do whatever business logic.....
            }
        }
    }

1 个答案:

答案 0 :(得分:3)

答案很简单:使用范围!您应该执行以下操作:

  1. 注册所有服务(例如DbContext),这些服务应在LifetimeScope生活方式的请求或操作期间生效。您通常会在Windows服务中使用计时器。每个'脉冲'都可以被视为一个请求。
  2. 在每个请求的开头开始一个生命周期范围。
  3. 在该范围内,从对象图解析根对象并调用其方法。
  4. 处理范围。
  5. 在您的情况下,这意味着您需要更改设计,因为NotificationService已解决一次并且其依赖项在另一个线程上重用。这是依赖注入土地中的no-no

    这是另一种设计:

    // This method is called on a background thread 
    // (possibly in a timely manner)
    public void Run()
    {
        try
        {
            using (var scope = container.BeginLifetimeScope())
            {
                var service = scope.Resolve<NotificationService>();
                service.Execute();
            }
        }
        catch (Exception ex)
        {
            // IMPORTANT: log exception. 
            // Not logging an exception will leave us in the dark.
            // Not catching the exception will kill our service 
            // because we run in a background thread.
        }
    }
    

    使用生命周期范围可以为每个请求获得新的DbContext,甚至可以让您并行运行请求(每个请求都有自己的DbContext)。