我想調試用C#編寫的服務,而且老式的方式太長了。我必須停止服務,以調試模式啓動我的應用程序(Visual Studio 2008),啓動服務,附加到服務進程,然後在我的Asp.Net應用程序中導航以觸發服務。在控制檯應用程序中包裝C#服務以進行調試
我基本上有服務在後臺運行,等待任務。 Web應用程序將觸發一項任務,由服務提取。
我想要做的是有一個控制檯應用程序,爲我嘗試調試服務。是否有任何人知道的簡單演示?
謝謝 傑克
我想調試用C#編寫的服務,而且老式的方式太長了。我必須停止服務,以調試模式啓動我的應用程序(Visual Studio 2008),啓動服務,附加到服務進程,然後在我的Asp.Net應用程序中導航以觸發服務。在控制檯應用程序中包裝C#服務以進行調試
我基本上有服務在後臺運行,等待任務。 Web應用程序將觸發一項任務,由服務提取。
我想要做的是有一個控制檯應用程序,爲我嘗試調試服務。是否有任何人知道的簡單演示?
謝謝 傑克
這裏是一個blog post有關運行的Windows服務作爲控制檯應用程序。
你也可以只創建引用相同的邏輯爲您服務,測試方法,或設置單元測試你的服務邏輯新的控制檯應用程序
我已經使用單元測試,調試困難的設置過去,只需編寫一個單元測試,用任何參數調用任何服務方法,並在單元測試中設置調試斷點。
使用testdriven.net或jetbrains testrunner使其更容易。
我傾向於有一張配置設置或使用指令的調試版本:
#if DEBUG
Debugger.Break();
#endif
或
if(Settings.DebugBreak)
Debugger.Break();
我提出,在服務組件的OnStart方法。然後,系統會自動提示您並將其附加到流程中。
你可以做這樣的事情在主入口點:
static void Main()
{
#if DEBUG
Service1 s = new Service1();
s.Init(); // Init() is pretty much any code you would have in OnStart().
#else
ServiceBase[] ServicesToRun;
ServicesToRun=new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
#endif
}
,並在你的OnStart事件處理程序:
protected override void OnStart(string[] args)
{
Init();
}
的方法,我總是採取隔離所有的應用程序重刑的邏輯到類庫中。這使得您的服務項目真的只是一個將您的類庫作爲服務託管的shell。
通過這樣做,您可以輕鬆地對代碼進行單元測試和調試,而無需處理通過附加到進程來調試服務的頭痛問題。我當然會推薦單元測試,但如果你沒有這樣做,那麼添加一個調用與您的服務相同的入口點的控制檯應用程序是最好的選擇。
TopShelf是另一個完美的方案。它允許您將流程作爲服務運行,或者以最少的配置作爲常規控制檯應用程序運行。
爲了避免使用全局定義,我通常在運行時測試我是否是通過Environment.UserInteractive屬性的服務或常規應用程序。
[MTAThread()]
private static void Main()
{
if (!Environment.UserInteractive)
{
ServiceBase[] aServicesToRun;
// More than one NT Service may run within the same process. To add
// another service to this process, change the following line to
// create a second service object. For example,
//
// ServicesToRun = New System.ServiceProcess.ServiceBase() {New ServiceMain, New MySecondUserService}
//
aServicesToRun = new ServiceBase[] {new ServiceMain()};
Run(aServicesToRun);
}
else
{
var oService = new ServiceMain();
oService.OnStart(null);
}
}
如果您希望顯示控制檯,請不要忘記在項目屬性中將輸出類型設置爲控制檯應用程序。該程序仍然可以作爲Windows服務運行,無論它是控制檯應用程序還是Windows應用程序,所以不用擔心。 – 2016-03-15 06:48:47
我用它來檢查我的進程是否作爲服務運行或不運行。
public class ServiceDiagnostics
{
readonly bool _isUserService;
readonly bool _isLocalSystem;
readonly bool _isInteractive;
public ServiceDiagnostics()
{
var wi = WindowsIdentity.GetCurrent();
var wp = new WindowsPrincipal(wi);
var serviceSid = new SecurityIdentifier(WellKnownSidType.ServiceSid, null);
var localSystemSid = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
var interactiveSid = new SecurityIdentifier(WellKnownSidType.InteractiveSid, null);
this._isUserService = wp.IsInRole(serviceSid);
// Neither Interactive or Service was present in the current user's token, This implies
// that the process is running as a service, most likely running as LocalSystem.
this._isLocalSystem = wp.IsInRole(localSystemSid);
// This process has the Interactive SID in its token. This means that the process is
// running as a console process.
this._isInteractive = wp.IsInRole(interactiveSid);
}
public bool IsService
{
get { return this.IsUserService || this.IsLocalSystem || !this.IsInteractive; }
}
public bool IsConsole
{
get { return !this.IsService; }
}
/// <summary>
/// This process has the Service SID in its token. This means that the process is running
/// as a service running in a user account (not local system).
/// </summary>
public bool IsUserService
{
get { return this._isUserService; }
}
/// <summary>
/// Neither Interactive or Service was present in the current user's token, This implies
/// that the process is running as a service, most likely running as LocalSystem.
/// </summary>
public bool IsLocalSystem
{
get { return this._isLocalSystem; }
}
/// <summary>
/// This process has the Interactive SID in its token. This means that the process is
/// running as a console process.
/// </summary>
public bool IsInteractive
{
get { return this._isInteractive; }
}
}
您可以通過反射調用服務方法,如下所示。
使用Environment.UserInteractive
可以讓我們知道我們是作爲控制檯應用程序運行還是作爲服務運行。
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
if (!Environment.UserInteractive)
{
// This is what normally happens when the service is run.
ServiceBase.Run(ServicesToRun);
}
else
{
// Here we call the services OnStart via reflection.
Type type = typeof(ServiceBase);
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
MethodInfo method = type.GetMethod("OnStart", flags);
foreach (ServiceBase service in ServicesToRun)
{
Console.WriteLine("Running " + service.ServiceName + ".OnStart()");
// Your Main method might not have (string[] args) but you could add that to be able to send arguments in.
method.Invoke(service, new object[] { args });
}
Console.WriteLine("Finished running all OnStart Methods.");
foreach (ServiceBase service in ServicesToRun)
{
Console.WriteLine("Running " + service.ServiceName + ".OnStop()");
service.Stop();
}
}
+1 - 我已經寫了幾個服務幾乎完全相同的代碼。 – 37Stars 2010-03-25 19:01:20