Laden...

[erledigt] Windows-Service von der Kommandozeile starten

Erstellt von mrbob vor 12 Jahren Letzter Beitrag vor 12 Jahren 6.923 Views
M
mrbob Themenstarter:in
46 Beiträge seit 2010
vor 12 Jahren
[erledigt] Windows-Service von der Kommandozeile starten

Moin moin,

ich habe ein Problem beim Starten eines Windows Service.
Und zwar soll es nicht nur ein Windows-Service sein, sondern auch eine Konsolenapplikation die Mittels Startparameter als Service oder als Konsolen Applikation laufen soll.

Wenn die Applikation als Service Startet installiere ich den Service zuerst:


private void InstallService()
        {
            try
            {
                _logger.Info("Starting: Install Service");
                if (!IsServiceRunning(ServiceName))
                {
                    string serviceAccountString = ConfigurationManager.AppSettings["ServiceAccount"];
                    ServiceAccount serviceAccountType = ServiceAccount.User;
                    string serviceAccountUser = ConfigurationManager.AppSettings["ServiceAccountUser"];
                    string serviceAccountPassword = ConfigurationManager.AppSettings["ServiceAccountPassword"];

                    switch (serviceAccountString)
                    {
                        case "LocalService":
                            serviceAccountType = ServiceAccount.LocalService;
                            break;
                        case "LocalSystem":
                            serviceAccountType = ServiceAccount.LocalSystem;
                            break;
                        case "NetworkService":
                            serviceAccountType = ServiceAccount.NetworkService;
                            break;
                        case "User":
                            serviceAccountType = ServiceAccount.User;
                            break;
                    }

                    _logger.Debug("ServiceAccount Type: " + serviceAccountType);

                    ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller() { Account = serviceAccountType };

                    if (!string.IsNullOrEmpty(serviceAccountUser) && !string.IsNullOrEmpty(serviceAccountPassword))
                    {
                        _logger.Info(string.Format("ServiceAccount User: {0}", serviceAccountUser));
                        serviceProcessInstaller.Username = serviceAccountUser;
                        serviceProcessInstaller.Password = serviceAccountPassword;
                    }
                    else
                    {
                        serviceProcessInstaller.Username = null;
                        serviceProcessInstaller.Password = null;
                    }

                    ServiceInstaller serviceInstaller = new ServiceInstaller();

                    String path = String.Format("/assemblypath={0}", _pathToService);
                    _logger.Debug(string.Format("Assemblypath: {0}", _pathToService));
                    String[] cmdline = { path };

                    InstallContext installContext = new InstallContext("", cmdline);

                    serviceInstaller.Context = installContext;
                    serviceInstaller.DisplayName = DisplayName;
                    serviceInstaller.ServiceName = ServiceName;
                    serviceInstaller.Description = ServiceDescription;

                    serviceInstaller.StartType = ServiceStartMode.Automatic;

                    serviceInstaller.Parent = serviceProcessInstaller;

                    ListDictionary state = new ListDictionary();
                    serviceInstaller.Install(state);

                    _logger.Info("Service install success");

                }
                else
                {
                    _logger.Info("Service is always started");
                }
            }
            catch (Exception ex)
            {
                _logger.Error("Error at Install Service", ex);
            }
        }

Die Klasse die die Methode InstallService enthält, ist von System.Configuration.Install.Installer abgeleitet und hat das Attribut [RunInstallerAttribute(true)].

Der Service wird auch Installiert und in der Liste der Dienste angezeigt.

Nun habe ich ein Problem beim Starten meines Service.
Wenn ich versuche mein Service mit der einer selbst erstellen Methode versuche zustarten, kommt eine System.ComponentModel.Win32Exception: > Fehlermeldung:

Der Dienst antwortete nicht rechtzeitig auf die Start- oder Steuerungsanforderung

Hier der Code:


public void StartService()
        {
            try
            {
                _logger.Info("Start Service");
                ServiceController serviceController = new ServiceController(ServiceName, Environment.MachineName);
                if (serviceController.Status.Equals(ServiceControllerStatus.Stopped) || serviceController.Status.Equals(ServiceControllerStatus.StopPending))
                {
                    serviceController.Start();
                    serviceController.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 0, 30));
                }
            }
            catch (System.ServiceProcess.TimeoutException ex)
            {
                _logger.Error("Operation timed out", ex);
            }
            catch (UnauthorizedAccessException ex)
            {
                _logger.Error("You are not authorized to perform this action", ex);
            }
            catch (InvalidOperationException ex)
            {
                Win32Exception winEx = ex.InnerException as Win32Exception;
                if (winEx != null)
                {
                    switch (winEx.NativeErrorCode)
                    {
                        case 5: //ERROR_ACCESS_DENIED
                            _logger.Error("You are not authorized to perform this action", ex);
                            break;
                        case 1722: //RPC_S_SERVER_UNAVAILABLE
                            _logger.Error("The server is unavailable or does not exist", ex);
                            break;
                        case 1060: //ERROR_SERVICE_DOES_NOT_EXIST
                            _logger.Error("The service does not exist", ex);
                            break;
                        case 1056: //ERROR_SERVICE_ALREADY_RUNNING
                            _logger.Error("The service is already running", ex);
                            break;
                        case 1062: //ERROR_SERVICE_NOT_ACTIVE
                            _logger.Error("The service is not running", ex);
                            break;
                        default:
                            break;
                    }
                }
                _logger.Error("InvalidOperationException at Start service", ex);
            }
            catch (Exception ex)
            {
                _logger.Error("Error at start Service", ex);
            }
        }

Was hierbei komisch ist das die OnStart-Methode meiner von der System.ServiceProcess.ServiceBase abgeleiten Klasse nicht aufruft. Ich habe schon mal versucht den ServicesPipeTimeout Eintrag in der Registry zu erhöhen, dies brachte aber keine Verbesserung.

Wenn ich versuche den Service mit

System.ServiceProcess.ServiceBase.Run(program);

zu starten bekomme ich folgende Meldung:> Fehlermeldung:

Der Dienst kann nicht von der Befehlszeile oder einem Debugger gestartet werden. Ein Windows-Dienst muss zuerst (mit installutil.exe) installiert und anschließend mit dem ServerExplorer, der Windows-Diensteverwaltung oder mit dem Befehl NET START gestartet werden.

Die Variable program die Ausgeführt werden soll ist die Klasse die von System.ServiceProcess.ServiceBase abgeleitet ist.

Ich komme nun nicht mehr weiter, wer hat eine Idee woran das liegen kann.

Mit freundlichen Grüßen
Mr. Bob

2.207 Beiträge seit 2011
vor 12 Jahren

Hallo mrbob,

die Fehlermeldung ist auch heir eindeutig. Du musst einen Dienst erst installieren, damit du ihn starten kannst. Dies geschieht manuell mit "installutil.exe" oder du machst das ganze mit einem Installer.

Du kannst die InstallUtil-Datei einbinden in dein Projekt und in deiner InstallService-Methode aufrufen. Mit den geeigneten Parametern natürlich. Dann sollte sich der Service installieren lassen.

Viele liebe Grüsse

Coffeebean

M
mrbob Themenstarter:in
46 Beiträge seit 2010
vor 12 Jahren

Hallo Coffeebean,

die Methode InstallService() bzw.


ServiceInstaller serviceInstaller = new ServiceInstaller();

                    String path = String.Format("/assemblypath={0}", _pathToService);
                    _logger.Debug(string.Format("Assemblypath: {0}", _pathToService));
                    String[] cmdline = { path };

                    InstallContext installContext = new InstallContext("", cmdline);

macht dies doch?

Mfg.
Mr. Bob

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo mrbob,

siehe [Tutorial] Windows Services mit C#, dort ist beschrieben wie der Dienst installiert werden muss.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

M
mrbob Themenstarter:in
46 Beiträge seit 2010
vor 12 Jahren

Moin moin,

ich habe mal einen Workaround gefunden.

Zuerst installiere ich den Service mit ManagedInstallerClass.InstallHelper, der den Konstruktor meiner Klasse aufruft die von System.Configuration.Install.Installer abgeleitet ist und starte dann den Service mit


ServiceController serviceController = new ServiceController("ServiceName", Environment.MachineName);
                if (serviceController.Status.Equals(ServiceControllerStatus.Stopped) || serviceController.Status.Equals(ServiceControllerStatus.StopPending))
                {
                    serviceController.Start();
                    serviceController.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 0, 30));
                }

Ich danke allen die mir bei dem Problem geholfen haben.

Mfg.
Mr. Bob