תמיכה ב WindowsService בזמן פיתוח
בעבודה עם WindowsService קיימת אי נוחות בסביבת הפיתוח.
- אי אפשר סתם כך להריץ אותו ב VisualStudio (לא ניתן ללחוץ F5 ולהריץ).
- יש צורך להוסיף שורה שטוענת את ה Debugger , זו שורה שנוספת לקוד על כל המשתמע מכך, ויש גם לדאוג שלא תופיע בסביבת Realese.
- לא ניתן להדפיס הודעות ל Console
סדרת פוסטים זו , נועדה כדי לפתור בעיות אלו.
הרצת ה Service כ Console בזמן debug.
כדי להריץ את ה Service בלחיצת F5 (או סתם כך משורת הפקודה) , יש ליצור הבחנה בין הסביבה בה רצה האפליקציה כ Service לבין הסביבה בה רצה האפליקציה שלא כ Service.
הפתרון הפשוט הוא, לבצע אבחנה האם למשתמש יש אינטראקציה עם שלחן העבודה. למי אין? ל WindowsService (אלא אם כן הוגדר אחרת – ולזה ניתן פתרון אחר).
בעת עליית המערכת נבדוק:
if (Environment.UserInteractive())
בדיקה זו תספק כמעט את כל הפתרון, וכך נוכל לבדל בין שתי סביבות ההרצה.
if (Environment.UserInteractive)
{
RunServiceInConsole();
}
else
{
RunAsWindowsService();
}
המתודה RunAsWindowsService תספק את המימוש הרגיל
private static void RunService()
{
ServiceBase.Run(new[] { new MyService() });
}
המתודה RunServiceInConsole תקרא למתודות של ה Service באמצעות Reflection:
private static void RunServiceInConsole(string[] args)
MyService service = new MyService();
Console.WriteLine("Press <ENTER> to terminate service.");
המתודה service.Start אינה קיימת, אלא זו הרחבה:
public static class WindowsServiceHelper
{
private static MethodInfo MethodInfo { get; set; }
public static void Start(
this ServiceBase service, string[] args)
{
if (MethodInfo == null)
{
MethodInfo = service.GetType()
.GetMethod("OnStart",
BindingFlags.Instance | BindingFlags.NonPublic);
Debug.Assert(MethodInfo != null
, "Can't get method OnStart");
}
MethodInfo.Invoke(service, new[] { args })
}
}
בשיטה המתוארת כאן, נוכל להריץ את ה Service שלנו משורת הפקודה, והוא יריץ אותו כאפליקצית Console רגילה.
במידה ובחרנו שלService שלנו תהיה אינטראקציה עם ה desktop הפתרון המוצע כאן לא יועיל. למקרה זה יהיה פתרון ב post נוסף.
נקודה נוספת שחשוב להדגיש היא, שיש לשנות את סוג הפרויקט ל Console Application
כמובן שעדיף לשפר את הפתרון, ולהשתמש לשם כך ב generics:
public static class WindowsServiceRunner<TService>
where TService : ServiceBase, new()
{
public static void Run(string[] args, string serviceName)
{
if (Environment.UserInteractive)
{
RunServiceInConsole(args);
}
else
{
RunService();
}
}
private static void RunService()
{
ServiceBase.Run(new[] { new TService() });
}
private static void RunServiceInConsole(string[] args)
{
TService service = new TService();
service.Start(args);
Console.WriteLine("Press <ENTER> to terminate service.");
Console.ReadLine();
service.Stop();
}
}
להורדת הקוד לכל הסדרה
הפוסטים הבאים: