簡體   English   中英

Windows服務設計幫助

[英]Windows Service Design Help

我正在設計我正計划構建的應用程序的體系結構,並且需要一些關於實現下面描述的特定Windows服務組件的最佳方法的建議。 我將使用.net 4.0構建服務,以便我可以利用新的並行和任務API,我也看過使用MSMQ服務但是我不確定這是否適合我希望實現的目標。

解釋我的用例的最簡單方法是,用戶可以為他們需要完成的任務創建許多不同類型的提醒,他們使用ASP.NET MVC 2中內置的基於Web的應用程序創建。這些提醒可以是各種類型的例如電子郵件和SMS,其原因必須在指定的到期時間發送。 提醒可以更改,直到它們被發送給用戶,暫停和取消一起,我想這使得基於排隊的服務,如MSMQ不合適?

我計划定期托管一個Windows服務(除非有更合適的方式?)檢查是否有任何提醒到期,確定其類型並將它們傳遞給特定組件以處理它們並將其發送出去。 如果發生異常,提醒將按設定的間隔排隊並再次嘗試,這將繼續發生,間隔增加,直到它們達到設定的閾值,此時它們將被丟棄並記錄為失敗。 為了向服務添加最后一層復雜性,我希望在配置文件中指定每種類型的具體實現(這意味着我可以說由於成本或其他原因而更改SMS服務),這些服務在服務啟動時加載動態。 任何未知或不可用類型的提醒都會自動失敗並像以前一樣記錄。

一旦成功發送了提醒,它就會丟棄它,但是對於我打算使用的SMS網關,它要求我調用它的API以確定消息是否成功傳遞,這意味着需要額外的計時器以設定的間隔檢查這一點。 能夠在服務啟動時添加符合統一接口的其他提醒類型服務而不需要更改其代碼也是很好的。

最后,我不知道這是否應該作為一個單獨的問題發布,但我想知道是否可以說構建一個可以隨時啟動/停止的控制台應用程序,當運行時可以看到當前的Windows服務是什么在做什么?

這是我有關Stackoverflow的第一個問題,即使我已經使用社區一段時間了,所以如果我做錯了,我會道歉。

謝謝,韋恩

對於問題的第二部分,我一直在考慮這個問題,這是一個我放在一起的類,它有助於創建一個既可以作為控制台應用程序也可以作為Windows服務運行的服務。 這是新聞,所以可能有一些問題需要解決,一些重構需要esp。 圍繞反射代碼。

注意:您應該將服務項目輸出類型設置為Console Application ,這仍然可以作為普通服務正常工作。

using System;
using System.Collections.Generic;
using System.Reflection;
using System.ServiceProcess;
using System.Threading;

namespace DotNetWarrior.ServiceProcess
{  
  public class ServiceManager
  {
    private List<ServiceBase> _services = new List<ServiceBase>();

    public void RegisterService(ServiceBase service)
    {
      if (service == null) throw new ArgumentNullException("service");
      _services.Add(service);
    }

    public void Start(string[] args)
    {
      if (Environment.UserInteractive)
      {
        foreach (ServiceBase service in _services)
        {
          Start(service, args);
        }
        Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
        Thread.Sleep(Timeout.Infinite);
      }
      else
      {
        ServiceBase.Run(_services.ToArray());
      }
    }    

    public void Stop()
    {
      foreach (ServiceBase service in _services)
      {
        Stop(service);
      }
    }

    private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
    {
      Stop();
      Environment.Exit(0);
    }

    private void Start(ServiceBase service, string[] args)
    {
      try
      {
        Type serviceType = typeof(ServiceBase);       

        MethodInfo onStartMethod = serviceType.GetMethod(
          "OnStart", 
          BindingFlags.NonPublic | BindingFlags.Instance, 
          null, 
          new Type[] { typeof(string[]) }, 
          null);

        if (onStartMethod == null)
        {
          throw new Exception("Could not locate OnStart");
        }

        Console.WriteLine("Starting Service: {0}", service.ServiceName);
        onStartMethod.Invoke(service, new object[] { args });
        Console.WriteLine("Started Service: {0}", service.ServiceName);
      }
      catch (Exception ex)
      {
        Console.WriteLine("Start Service Failed: {0} - {1}", service.ServiceName, ex.Message);
      }
    }

    private void Stop(ServiceBase service)
    {
      try
      {
        Type serviceType = typeof(ServiceBase);
        MethodInfo onStopMethod = serviceType.GetMethod(
          "OnStop", 
          BindingFlags.NonPublic | BindingFlags.Instance);
        if (onStopMethod == null)
        {
          throw new Exception("Could not locate OnStart");
        }
        Console.WriteLine("Stoping Service: {0}", service.ServiceName);
        onStopMethod.Invoke(service, null);
        Console.WriteLine("Stopped Service: {0}", service.ServiceName);
      }
      catch (Exception ex)
      {
        Console.WriteLine("Stop Service Failed: {0} - {1}", service.ServiceName, ex.Message);
      }
    }
  }
}

要使用此功能,您可以將標准代碼從服務的Main入口點中刪除,並將其替換為以下內容。

static void Main(string[] args)
{
  ServiceManager services = new ServiceManager();
  services.RegisterService(new Service1());

  services.Start(args);      
}

services.Start()方法將檢測服務作為交互式應用程序運行並手動調用所有已注冊服務的OnStart方法,一旦啟動主線程進入休眠狀態。 要停止服務,只需按“Ctrl + C”,這將導致通過調用服務的OnStop方法停止服務。

當然,應用程序由SCM作為服務運行,然后每個人都可以作為普通服務運行。 唯一需要注意的是,服務不應該要求“允許服務與桌面交互”,因為這將使服務以交互方式運行,即使它是作為服務運行的。 如果需要,這可以解決,但嘿,我只是編寫代碼。

監視和啟動/停止服務

從命令行,您可以使用NET.EXE來啟動/停止服務

Start a service
net start <service name>

Stop a service
net stop <service name>

要從.NET管理服務,您可以使用System.ServiceProcess.ServiceController

// Stop a service
System.ServiceProcess.ServiceController sc = new
  System.ServiceProcess.ServiceController("<service name>");
sc.Stop();

對於通過ServiceController提供的服務之外的一般通信,我建議您將WCF服務作為服務的一部分進行托管,然后您可以使用該服務與服務進行通信以查詢特定於您的服務的內部詳細信息。

處理調度

說實話,我對回答問題的這個方面猶豫不決,因為有很多方法都有優點/缺點。 所以我將給出一些高級選項供您考慮。 你可能已經想到了這一點,但這里有一些不可思議的東西

如果您使用SQL Server存儲通知。

有一個SP,您可以調用它來檢索到期的提醒,然后處理結果以適當地提出提醒。

有了這個SP你有一些選擇

  1. 定期從您的服務呼叫SP並處理提醒
  2. 擁有一個定期運行SP的SQL作業,並向Service Broker隊列添加提醒。 然后,您的服務可以訂閱隊列並處理隊列中顯示的提醒。 這種方法的優點是,您可以使用多個服務器進行擴展,無需任何特殊編碼即可處理提醒通知生成,只需添加另一台運行服務的服務器,消息將自動在兩台服務器之間分配。

如果您不使用SQL Server存儲提醒

您仍然可以使用與SQL Server類似的方法。 當然,Windows服務可以使用合適的內容查詢數據存儲並處理提醒。 由於您需要確保多個服務器不處理相同的提醒等但不是火車粉碎,因此要進行此擴展會有點困難。

我認為這涵蓋了它的要點,其他一切都是上面的一些變化。 最終,您的決定將取決於目標量,可靠性要求等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM