كيفية كتابة ج # الخدمة التي يمكنني أيضا تشغيل كبرنامج WinForms عناصر؟

StackOverflow https://stackoverflow.com/questions/421516

سؤال

ولدي خدمة ويندوز مكتوب في C # التي تعمل بمثابة وكيل لمجموعة من أجهزة الشبكة إلى قاعدة بيانات النهاية الخلفية. لاختبار وأيضا لإضافة طبقة محاكاة لاختبار النهاية الخلفية أود أن يكون واجهة المستخدم الرسومية للمشغل اختبار ليكون المدى قادرة على محاكاة. أيضا للحصول على إصدار مخطط وصولا الى ترسل كما عرض تجريبي. واجهة المستخدم الرسومية والخدمات لم يكن لديك لتشغيل في نفس الوقت. ما هو أفضل وسيلة لتحقيق هذه العملية مبارزة؟

وتحرير: هنا هو بلدي الحل بتمشيط الاشياء من هذا السؤال و <لأ href = "https://stackoverflow.com/questions/200163/am -i-تشغيل-كما هو وجود خدمة "> أنا تشغيل كخدمة و <لأ href =" https://stackoverflow.com/questions/255056/install-a-net-windows-service- دون-installutil-إكس / 255062 # 255062 "> تثبيت خدمة ويندوز. NET بدون InstallUtil.exe باستخدام <لأ href =" http://groups.google.co.uk/group/microsoft.public.dotnet .languages.csharp / browse_thread / موضوع / 4d45e9ea5471cba4 / 4519371a77ed4a74 "يختلط =" نوفولو noreferrer "> هذا الرمز ممتازة بواسطة مارك Gravell

ويستخدم السطر التالي لاختبار إذا لتشغيل واجهة المستخدم الرسومية أو تشغيل كخدمة.

 if (arg_gui || Environment.UserInteractive || Debugger.IsAttached)

وهنا هو رمز.


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.ComponentModel;
using System.ServiceProcess;
using System.Configuration.Install;
using System.Diagnostics;

namespace Form_Service
{
   static class Program
   {
      /// 
      /// The main entry point for the application.
      /// 
      [STAThread]
      static int Main(string[] args)
      {
         bool arg_install =  false;
         bool arg_uninstall = false;
         bool arg_gui = false;
         bool rethrow = false;
         try
         {
            foreach (string arg in args)
            {
               switch (arg)
               {
                  case "-i":
                  case "-install":
                     arg_install = true; break;
                  case "-u":
                  case "-uninstall":
                     arg_uninstall = true; break;
                  case "-g":
                  case "-gui":
                     arg_gui = true; break;
                  default:
                     Console.Error.WriteLine("Argument not expected: " + arg);
                     break;
               }
            }
            if (arg_uninstall)
            {
               Install(true, args);
            }
            if (arg_install)
            {
               Install(false, args);
            }
            if (!(arg_install || arg_uninstall))
            {
               if (arg_gui || Environment.UserInteractive || Debugger.IsAttached)
               {
                  Application.EnableVisualStyles();
                  Application.SetCompatibleTextRenderingDefault(false);
                  Application.Run(new Form1());
               }
               else
               {
                  rethrow = true; // so that windows sees error... 
                  ServiceBase[] services = { new Service1() };
                  ServiceBase.Run(services);
                  rethrow = false;
               }
            }
            return 0;
         }
         catch (Exception ex)
         {
            if (rethrow) throw;
            Console.Error.WriteLine(ex.Message);
            return -1;
         }
      }

      static void Install(bool undo, string[] args)
      {
         try
         {
            Console.WriteLine(undo ? "uninstalling" : "installing");
            using (AssemblyInstaller inst = new AssemblyInstaller(typeof(Program).Assembly, args))
            {
               IDictionary state = new Hashtable();
               inst.UseNewContext = true;
               try
               {
                  if (undo)
                  {
                     inst.Uninstall(state);
                  }
                  else
                  {
                     inst.Install(state);
                     inst.Commit(state);
                  }
               }
               catch
               {
                  try
                  {
                     inst.Rollback(state);
                  }
                  catch { }
                  throw;
               }
            }
         }
         catch (Exception ex)
         {
            Console.Error.WriteLine(ex.Message);
         }
      }
   }

   [RunInstaller(true)]
   public sealed class MyServiceInstallerProcess : ServiceProcessInstaller
   {
      public MyServiceInstallerProcess()
      {
         this.Account = ServiceAccount.NetworkService;
      }
   }

   [RunInstaller(true)]
   public sealed class MyServiceInstaller : ServiceInstaller
   {
      public MyServiceInstaller()
      {
         this.Description = "My Service";
         this.DisplayName = "My Service";
         this.ServiceName = "My Service";
         this.StartType = System.ServiceProcess.ServiceStartMode.Manual;
      }
   }

}
هل كانت مفيدة؟

المحلول

وأساسا لديك خيارين. إما فضح API على الخدمة التي يمكنك بعد ذلك الاتصال من التطبيق UI أو تمكين خدمة لتشغيل إما التطبيق WinForms عناصر أو خدمة.

والخيار الأول هو السهل جدا - استخدام الاتصال عن بعد أو WCF لفضح API

وأما الخيار الثاني لا يمكن أن يتحقق عن طريق تحريك "الشجاعة" من التطبيق الخاص بك في فئة منفصلة ثم إنشاء مجمع الخدمات وفوز أشكال إزار أن كلا من الدعوة إلى صفك "الشجاعة".

static void Main(string[] args)
{
    Guts guts = new Guts();

    if (runWinForms)
    {
        System.Windows.Forms.Application.EnableVisualStyles();
        System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);

        FormWrapper fw = new FormWrapper(guts);

        System.Windows.Forms.Application.Run(fw);
    }
    else
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] { new ServiceWrapper(guts) };
        ServiceBase.Run(ServicesToRun);
    }
}

نصائح أخرى

وإنشاء WinForms عناصر تطبيق جديد المراجع تجميع خدمتكم.

إذا كنت تستخدم التعليمة البرمجية أدناه:

[DllImport("advapi32.dll", CharSet=CharSet.Unicode)]
static extern bool StartServiceCtrlDispatcher(IntPtr services);
[DllImport("ntdll.dll", EntryPoint="RtlZeroMemory")]
static extern void ZeroMemory(IntPtr destination, int length);

static bool StartService(){
    MySvc svc = new MySvc(); // replace "MySvc" with your service name, of course
    typeof(ServiceBase).InvokeMember("Initialize", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
        null, svc, new object[]{false});
    object entry = typeof(ServiceBase).InvokeMember("GetEntry",
        BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, svc, null);
    int len = Marshal.SizeOf(entry) * 2;
    IntPtr memory = Marshal.AllocHGlobal(len);
    ZeroMemory(memory, len);
    Marshal.StructureToPtr(entry, memory, false);
    return StartServiceCtrlDispatcher(memory);
}

[STAThread]
static void Main(){
    if(StartService())
        return;

    Application.Run(new MainWnd()); // replace "MainWnd" with whatever your main window is called
}

وبعد ذلك سيتم تشغيل EXE الخاص بك إما خدمة (إذا أطلقها SCM) أو واجهة المستخدم الرسومية (إذا أطلقت من قبل أي عملية أخرى).

وأساسا، كل ما قمت به هنا يستخدم العاكس لمعرفة ما لحوم ServiceBase.Run لا، وتكرار ذلك هنا (التفكير هو مطلوب، لأنه يدعو أساليب خاصة). والسبب في عدم توجيه الدعوة ServiceBase.Run مباشرة هو أنه ينبثق مربع رسالة لنقول لل<م> المستخدم أن الخدمة لا يمكن بدء (إذا لم تطلق من قبل SCM) ولا يعود أي شيء لقول < م> كود أن الخدمة لا يمكن بدء.

ولأن هذا يستخدم انعكاس للاتصال أساليب الإطار خاصة، فإنه قد لا تعمل بشكل صحيح في المراجعات المستقبلية للإطار. التحذير codor.

وهناك أيضا FireDaemon . هذا يسمح لك بتشغيل أي تطبيق ويندوز كخدمة.

أنا تشغيل والخدمة للحصول على بعض من المفيد مزيد المعلومات.

وأهم شيء هو مغطى كيفية تحديد ما إذا كنا موثوق تشغل تفاعلي أو عن طريق الخدمة.

وكان لديك لتنفيذ عملية منفصلة قادرة على التواصل مع الخدمة الخاص بك. في حين أنه من الممكن على XP ونظم في وقت سابق أن يكون خدمة تظهر على واجهة المستخدم، وهذا لم يعد ممكنا على ويندوز فيستا وفي وقت لاحق.

والاحتمال الآخر هو أن NOT استخدام الخدمة، ولكن لاستخدام التطبيق الذي يقيم في شريط المهام (اعتقد برنامج Roxio السحب إلى القرص، وعلى الأرجح برامج مكافحة الفيروسات يعيش هناك في الأسفل) والذي يحتوي على رمز أسفل من قبل على مدار الساعة، والتي تطلق القائمة، عندما يكون بالنقر بزر الفأرة الأيمن، وUI عند النقر المزدوج.

إذا هو منظم الخدمة بشكل صحيح، هل يمكن استضافة خدمة إما في تنفيذ كخدمة، أو مع قابل للتنفيذ مع واجهة المستخدم الرسومية للاختبار. نحن نستخدم هذا الأسلوب مع خدمتنا جدا، والخدمة القابلة للتنفيذ المضيفين مستقل الخدمة في بيئة منتجة، ولكن لدينا وحدة التطبيق لاستضافة الخدمة أيضا.

وفصل التعليمات البرمجية إلى مكونات مختلفة: عنصر واحد لإدارة الجوانب الخدمية واحد لأداء منطق الأعمال الفعلي. إنشاء والتفاعل مع منطق الأعمال من مكون خدمة. لاختبار (المنطق عملك) يمكنك إنشاء WinForm أو وحدة التحكم تطبيق يستخدم المكون منطق الأعمال دون مكون خدمة. والأفضل من ذلك، استخدام إطار وحدة اختبار الجزء الأكبر من الاختبار. العديد من الأساليب في مكون خدمة سيكون بلا شك وحدة قابلة للاختبار أيضا.

إذا تغلف منطق عملك في صفوف الخدمة وثم استخدام نمط مصنع لإنشاء تلك الخدمات، يمكنك استخدام نفس مجموعة من الخدمات لتطبيقات سطح المكتب (مصنع سطح المكتب) وإلى خدمات الإنترنت (المضيف في WCF).

وتعريف الخدمة:

[ServiceContract]
public interface IYourBusinessService
{
    [OperationContract]
    void DoWork();
}

public class YourBusinessService : IYourBusinessService
{
    public void DoWork()
    {
        //do some business logic here
    }

}

ومصنع للWinForms عناصر سطح المكتب للحصول على الخدمات في القيام بأعمال تجارية:

public class ServiceFactory
{
    public static IYourBusinessService GetService()
    {
        //you can set any addition info here
        //like connection string for db, etc.
        return new YourBusinessService();
    }
}

وأنت استضافة هذا إما مع الطبقة WCF ServiceHost، أو في IIS. كلا تسمح لك القدرة على تحديد كيفية مثيل كل مثيل الخدمة بحيث يمكنك القيام التهيئة مثل سلاسل اتصال، الخ.

ويمكنك إنشاء خدمة للاتصال تنفيذ آخر مع وسيطة سطر الأوامر بحيث يتم تشغيله بدون النموذج. عندما يتم استدعاء أن إكس دون وسيطة سطر الأوامر فإنه يدل على شكل وعمل كالمعتاد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top