2009-01-07 14 views
7

मेरे पास सी # में लिखा गया एक विंडोज सेवा है जो बैक एंड डेटाबेस में नेटवर्क उपकरणों के समूह के लिए प्रॉक्सी के रूप में कार्य करती है। परीक्षण के लिए और बैक एंड का परीक्षण करने के लिए सिमुलेशन परत जोड़ने के लिए मैं परीक्षण ऑपरेटर के लिए सिमुलेशन चलाने में सक्षम होने के लिए एक जीयूआई रखना चाहता हूं। डेमो के रूप में भेजने के लिए एक धारीदार संस्करण के लिए भी। जीयूआई और सेवा को एक ही समय में चलाने की ज़रूरत नहीं है। इस द्वंद्वयुद्ध ऑपरेशन को हासिल करने का सबसे अच्छा तरीका क्या है?सी # सेवा कैसे लिखें जिसे मैं Winforms प्रोग्राम के रूप में भी चला सकता हूं?

संपादित करें: यहाँ से Marc Gravell

मेरी समाधान this question, Am I Running as a Service और Install a .NET windows service without InstallUtil.exethis excellent code का उपयोग करने से सामान में कंघी है यह अगर जीयूआई चलाने के लिए या सेवा के रूप में चलाने के लिए परीक्षण करने के लिए निम्न पंक्ति का उपयोग करता है।

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; 
     } 
    } 

} 
+0

मैं इसे सेवा के रूप में कैसे चला सकता हूं? मैं cmd ​​से अपना प्रोग्राम चलाता हूं मैं लिखता हूं c: \ myservice.exe -install कुछ भी नहीं चल रहा है। अगर मैं केवल अपना आवेदन खोलने के लिए c: \ myservice.exe लिखता हूं। मैं क्या गलत कर रहा हूँ। या मैं इसका उपयोग कैसे कर सकता हूं? –

+0

क्या आपने कभी नीचे दिए गए समाधान का एहसास किया है? जहां तक ​​रैपर वर्ग और ऐसे बनाते हैं? –

उत्तर

17

आपके मूल रूप से दो विकल्प हैं। या तो सेवा पर एक एपीआई का पर्दाफाश करें जिसे आप यूआई ऐप से कॉल कर सकते हैं या Winforms ऐप या सेवा के रूप में चलाने के लिए सेवा को सक्षम कर सकते हैं।

पहला विकल्प बहुत आसान है - एपीआई का पर्दाफाश करने के लिए रिमोटिंग या डब्ल्यूसीएफ का उपयोग करें।

दूसरा विकल्प आपके ऐप के "गले" को एक अलग वर्ग में ले जाकर हासिल किया जा सकता है, फिर एक सेवा रैपर और एक जीत-फॉर्म रैपर बनाएं जो दोनों आपके "गेट्स" वर्ग में कॉल करें।

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); 
    } 
} 
+0

इस उत्तर में आया और विधि दो में रुचि है कि आपको यह कोड नमूना मिला है। क्या आपके पास इस रैपर कक्षाओं को बनाने और "गड़बड़" के इस उदाहरण में पास करने का कोई उदाहरण है। मैं थोड़ा उलझन में हूं कि आप यह कैसे करते हैं। –

2

एक नया Winforms ऐप बनाएं जो आपकी सेवा की असेंबली का संदर्भ देता है।

1

FireDaemon भी है। यह आपको किसी भी विंडोज़ एप्लिकेशन को सेवा के रूप में चलाने की अनुमति देता है।

0

आपको एक अलग प्रक्रिया को लागू करना है जो आपकी सेवा के साथ संवाद कर सकता है। हालांकि एक्सपी और पहले सिस्टम पर यूआई दिखाने की सेवा होने पर यह संभव है, यह Vista और बाद में अब संभव नहीं है।

0

एक और संभावना है कि सेवा का उपयोग न करें, लेकिन टास्कबार में रहने वाले एप्लिकेशन का उपयोग करने के लिए (सोचें कि रोक्सियो ड्रैग-टू-डिस्क, & अधिकतर आपके एंटी-वायरस सॉफ़्टवेयर वहां रहते हैं) जिसका आइकन नीचे है घड़ी, जो मेनू को लॉन्च करती है, जब इसे राइट-क्लिक किया जाता है, और डबल-क्लिक होने पर यूआई।

+0

सेवा होना मेरी पसंद नहीं है। –

+0

कृपया, यदि आपको नहीं करना है तो टास्कबार में और बकवास न डालें। –

+0

वर्णित आवश्यकताओं को पूरा करने की संभावना है .. मैं जरूरी कार्रवाई के उस पाठ्यक्रम की सिफारिश नहीं कर रहा था। –

0

यदि आपकी सेवा ठीक से संशोधित है, तो आप सेवा के रूप में निष्पादन योग्य में या मेजबान के साथ निष्पादन योग्य के साथ सेवा होस्ट कर सकते हैं। हम इस विधि का उपयोग हमारी सेवा के साथ भी करते हैं, स्टैंडअलोन सेवा-निष्पादन योग्य उत्पादक वातावरण में सेवा होस्ट करता है, लेकिन हमारे पास सेवा की मेजबानी के लिए एक कंसोल-ऐप भी है।

0

अपने कोड को विभिन्न घटकों में अलग करें: सेवा घटक पहलुओं को प्रबंधित करने के लिए एक घटक और वास्तविक व्यापार तर्क करने के लिए एक घटक। सेवा घटक से व्यापार तर्क बनाएँ और बातचीत करें। परीक्षण (आपके व्यवसाय तर्क के) के लिए आप WinForm या कंसोल एप्लिकेशन बना सकते हैं जो सेवा घटक के बिना व्यावसायिक तर्क घटक का उपयोग करता है। बेहतर अभी तक, अपने परीक्षण के लिए एक इकाई परीक्षण ढांचे का उपयोग करें। सेवा घटक में कई विधियां निस्संदेह यूनिट टेस्टेबल भी होंगी।

2

आप नीचे दिए गए कोड का उपयोग करें: (यदि कोई अन्य प्रक्रिया द्वारा शुरू की)

[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 (यदि एससीएम द्वारा शुरू की) या तो एक सेवा के रूप में चलेंगे या एक जीयूआई के रूप में।

अनिवार्य रूप से, सब मैं यहाँ किया है Reflector प्रयोग किया जाता है यह पता लगाने की क्या ServiceBase.Run का मांस होता है, और इसे यहाँ नकल करने (प्रतिबिंब की आवश्यकता है, क्योंकि यह निजी तरीकों कॉल)। ServiceBase.Run पर कॉल न करने का कारण यह है कि उपयोगकर्ता को यह बताने के लिए एक संदेश बॉक्स पॉप अप करता है कि सेवा शुरू नहीं की जा सकती है (यदि एससीएम द्वारा लॉन्च नहीं किया गया है) और कोड को सेवा देने के लिए कुछ भी वापस नहीं करता है शुरू नहीं किया जा सकता

क्योंकि यह निजी ढांचे के तरीकों को कॉल करने के प्रतिबिंब का उपयोग करता है, यह ढांचे के भविष्य के संशोधन में सही ढंग से कार्य नहीं कर सकता है। कैविट कोडर।

0

आप सेवा की कक्षाओं में अपने व्यापार तर्क को संपुटित और फिर उन सेवाओं को बनाने के लिए एक कारखाना पैटर्न का उपयोग करते हैं, तो आपको डेस्कटॉप एप्लिकेशन (डेस्कटॉप कारखाना) के लिए सेवाओं के एक ही सेट का उपयोग कर सकते हैं और के रूप में वेब सेवाओं (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 में इस होस्ट करते हैं। दोनों आपको सेवा के प्रत्येक इंस्टेंस को तुरंत चालू करने के तरीके को निर्दिष्ट करने की क्षमता प्रदान करते हैं ताकि आप कनेक्शन स्ट्रिंग आदि जैसे प्रारंभिक कर सकें।

1

कुछ और उपयोगी जानकारी के लिए Am I running as a service देखें।

सबसे महत्वपूर्ण बात यह है कि कैसे विश्वसनीय रूप से यह निर्धारित करना है कि हम अंतःक्रियात्मक रूप से या सेवा के माध्यम से चल रहे हैं या नहीं।

0

आप कमांड लाइन तर्क के साथ किसी अन्य निष्पादन योग्य को कॉल करने के लिए सेवा बना सकते हैं ताकि यह फ़ॉर्म के बिना चलाया जा सके। जब उस exe को कमांड लाइन तर्क के बिना बुलाया जाता है तो यह फ़ॉर्म को दिखाता है और सामान्य के रूप में कार्य करता है।

संबंधित मुद्दे