Self Installing WindowsService -שרות שיודע להתקין את עצמו
post זה הוא השלישי והאחרון בסדרה אודות תמיכה ב WindowsService בסביבת פיתוח
קדמו לו:
הפעם נראה, כיצד נוכל שאותה אפליקציה, תוכל:
-
להתקין את ה Service ב Service Control Managment
-
להסיר את ההתקנה
-
להריץ את ה Service
-
לעצור אותו
-
ובהמשך, ניתן גם פתרון ל Service שרץ תחת סביבה אינטראקטיבית, ולא יכול להשתמש ביכולת שהצגנו ב post הראשון.
כדי לבצע את המשימה, נקלוט את שורת הפקודה, ובהתאם לקלט, נבצע את אחת מן הפקודות הנ"ל.
בנוסף, על האפליקציה לדעת מה שם ניתן לה בSCM (קרי: Service Control Managment) , ולשם כך נשתמש בקונפיגורציה.
אז איך מתקינים?
1: public static void Install(string serviceName)
2: {
3: IDictionary savedState = new Hashtable();
4:
5: using (var installer =
6: new AssemblyInstaller(typeof(TService).Assembly,
7: new string[] { "/logFile=WindowsServiceRunner-" + typeof(TService).Name + "-.log" }) { UseNewContext = true })
8: {
9: CatchExceptions(() =>
10: {
11: installer.Install(savedState);
12: installer.Commit(savedState);
13: });
14: }
15: Start(serviceName);
16: }
17:
המתודה Install, מתקינה את ה Service לתוך ה SCM, את ה log עם התוצאות היא מפיקה לתוך קובץ בספריית ההתקנה, כאשר בשם הקובץ, משובץ שם המחלקה.
בסופו של התהליך נקראת המתודה Start שמריצה את ה Service. (ניתן בהחלט, לנתק בין שתי הפעולות)
הפעולות שקיימת סבירות שיזרקו חריגה, עטופות במתודה CatchExceptions המוגדרת כך:
1: static void CatchExceptions(Action action)
2: {
3: try
4: {
5: action();
6: }
7: catch (Exception ex)
8: {
9: Console.WriteLine(ex.ToString());
10: Console.ReadLine();
11: }
12: }
13:
שאר הפעולות (הסרת ההתקנה, עצירה והרצה) הם פשוטות יותר, וניתן לעיין בהן בקוד המקור המצורף.
כדי לקרוא לפעולות אלו, נשתמש בארגומנטים המתקבלים בשורת הפקודה
(המתודה CompareInput מחלצת ובודקת האם הארגומנטים מתאימים לקלט. כמובן די באחת משתי האפשרויות המוצגות להלן)
1: public static void Run(string[] args, string serviceName)
2: {
3: if (Environment.UserInteractive)
4: {
5: if (args.Length > 0)
6: {
7: if (CompareInput(args[0], "i", "/i"))
8: {
9: ServiceControlManager<TService>.Install(serviceName);
10: }
11: else if (CompareInput(args[0], "u", "/u"))
12: {
13: ServiceControlManager<TService>.Uninstall();
14: }
15: else if (CompareInput(args[0], "r", "/r"))
16: {
17: ServiceControlManager<TService>.Start(serviceName);
18: }
19: else if (CompareInput(args[0], "s", "/s"))
20: {
21: ServiceControlManager<TService>.Stop(serviceName);
22: }
23: else if (CompareInput(args[0], "?", "/?"))
24: {
25: ShowHelp();
26: }
27: else
28: {
29: RunServiceInConsole(args);
30: }
31: }
32: else
33: {
34: RunServiceInConsole(args);
35: }
36: }
37: else
38: {
39: RunService();
40: }
41: }
כדי להתקין את האפליקציה מתוכנת התקנה, נוסיף Commit Action שיקבל כארגומנט i. (ניתן לראות דוגמא בקוד המקור).
וכך נראית ה Main בקוד הדוגמא שלנו:
1: static void Main(string [] args)
2: {
3: WindowsServiceRunner<MyService>.Run(args, Settings.Default.ServiceName);
4: }
אחרי שהצגנו את הפתרון הנ"ל, נוכל לתת פתרון גם ל Service שהינו אינטארקטיבי, ובמקרה זה Environment.UserInteractive מחזיר תמיד true.
לשם כך הוספנו בקוד המקור את המחלקה InteractiveWindowsServiceRunner המטפלת במקרה זה.
כאן הטיפול הוא ע"י העברת ארגומנט d בסביבת הפיתוח:
1: if (CompareInput(args[0], "d", "/d"))
2: {
3: ServiceControlManager<TService>.Install(serviceName);
4: }
להורדת הקוד לכל הסדרה