Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs

Services über das Web managen

Geschrieben von: Christoph Wille
Kategorie: ASP.NET

This printed page brought to you by AlphaSierraPapa

Remote Administration, das ist eines der Themen im Internetzeitalter. Vom Datenbankserver über den Webserver, alles soll über das Internet gemanaged werden. Meistens bedient man sich eigener Remote Consolen (Terminal Services, etc), warum allerdings sollte man sich nicht ein maßgeschneidertes Webinterface basteln?

Im heutigen Artikel beschäftigen wir uns mit den Grundlagen des Arbeitens mit Windows Services - etwas, das definitiv wert ist, administriert zu werden. Dazu verwenden wir wieder einmal ASP.NET und das .NET Framework SDK. Apropos: ausnahmsweise gäbe es auch für ASP einen Weg, um an einer eigenen Komponente vorbeizukommen: WMI, Windows Management Instrumentation.

Voraussetzung um den Sourcecode dieses Artikels verwenden zu können ist eine Installation des Microsoft .NET Framework SDK's auf einem Webserver. Weiters setze ich voraus, daß der Leser die Programmiersprache C# zu einem gewissen Grad beherrscht - es finden sich etliche Artikel auf diesem Server, um das notwendige Wissen zu erlernen

Sicherheitshinweis: die Beispielannahme ist, daß der ASP.NET Worker Prozess unter dem SYSTEM Konto läuft (standardmäßig läuft er unter dem ASPNET Account). Bitte ändern Sie processModel in machine.config entsprechend ab, oder geben nur Administratoren Zugriff auf die Dateien (Impersonation).

Auflisten der Services

Als Aufwärmübung listen wir einmal die gesamten Services auf, die am Webserver installiert sind. Damit die Übung nicht zu leicht wird, soll auch der Status (gestartet, gestoppt, etc) des jeweiligen Services angegeben werden (listservices.aspx).

<% @Page Language="C#" %>
<% @Assembly Name="System.ServiceProcess" %>
<% @Import Namespace="System.ServiceProcess" %>
<html>
<head><title>Services @localhost</title></head>
<body>
<%
ServiceController[] arrSC = ServiceController.GetServices();

Response.Write(arrSC.Length.ToString() + " Services installed<br>");

for (int i=0; i < arrSC.Length; i++)
{
  Response.Write("<b>" + arrSC[i].ServiceName + "</b>&nbsp;-&nbsp;" 
      + arrSC[i].DisplayName);
  
  switch(arrSC[i].Status)
  {
  case ServiceControllerStatus.ContinuePending:
    Response.Write(" [<i>continue pending</i>]");
    break;
  case ServiceControllerStatus.Paused:
    Response.Write(" [<i>paused</i>]");
    break;
  case ServiceControllerStatus.PausePending:
    Response.Write(" [<i>pause pending</i>]");
    break;
  case ServiceControllerStatus.Running:
    Response.Write(" [<i>running</i>]");
    break;
  case ServiceControllerStatus.StartPending:
    Response.Write(" [<i>start pending</i>]");
    break;
  case ServiceControllerStatus.Stopped:
    Response.Write(" [<i>stopped</i>]");
    break;
  case ServiceControllerStatus.StopPending:
    Response.Write(" [<i>stop pending</i>]");
    break;
  }

  Response.Write("<br>\r\n");
}
%>
</body>
</html>

Alles, was wir an Funktionalität benötigen, findet sich im System.ServiceProcess Namespace. Um an die Liste der Services zu gelangen, verwenden wir die statische Methode GetServices der ServiceController Klasse:

ServiceController[] arrSC = ServiceController.GetServices();

Grob gesagt, war das bereits die gesamte Arbeit - wir haben ein Array der gesamten installierten Services "in die Hand" gedrückt bekommen. Nun geht es nur noch darum, die erhaltenen Informationen am Browser darzustellen. Da der Status Werte aus der ServiceControllerStatus Enumeration enthält, habe ich noch ein kleines switch Statement eingebaut.

Das Ergebnis sieht dann wie folgt aus (und das ist eine Maschine mit kaum Services installiert!):

Der "Vollständigkeit" halber möchte ich auf noch zeigen, daß man dieses ServiceController Array einem DataGrid zuweisen kann. Das Beispiel listservices2.aspx demonstriert dies, allerdings ohne bells and whistles.

<% @Page Language="C#" %>
<% @Assembly Name="System.ServiceProcess" %>
<% @Import Namespace="System.ServiceProcess" %>
<html>
<head><title>Services @localhost</title></head>
<body>
<script language="C#" runat="server">
void Page_Load(Object sender, EventArgs e) 
{
  ServiceController[] arrSC = ServiceController.GetServices();
  
  ServiceGrid.DataSource = arrSC;
  ServiceGrid.DataBind();
}
</script>

<h3>Services</h3>

<form runat="server">
<asp:DataGrid id="ServiceGrid" runat="server"
    BorderColor="black"
    BorderWidth="1"
    GridLines="Both"
    CellPadding="3"
    CellSpacing="0"
    Font-Name="Verdana"
    Font-Size="8pt"
    HeaderStyle-BackColor="#aaaadd"
    AutoGenerateColumns="false">
    <Columns>
      <asp:BoundColumn HeaderText="Service name" DataField="ServiceName" />
      <asp:BoundColumn HeaderText="Display name" DataField="DisplayName" />
      <asp:BoundColumn HeaderText="Status" DataField="Status"/>
    </Columns>
</asp:DataGrid>
</form>

</body>
</html>

Und am Browser erhält man dann folgendes DataGrid:

Stoppen von Services

Das Auflisten von Services war ja nicht weiter schwierig, also darf man annehmen, daß das Stoppen eines Services ebenso leicht sein sollte (ist es auch). Der folgende Code (stopservice.aspx) zeigt wie's geht:

<% @Page Language="C#" %>
<% @Assembly Name="System.ServiceProcess" %>
<% @Import Namespace="System.ServiceProcess" %>
<%
ServiceController myService = new ServiceController("MSFTPSVC");
if (myService.CanStop)
{
  myService.Stop();
}
%>
</body>
</html>

Eigentlich wäre nur die Stop Methode aufzurufen, allerdings würde man eine unschöne Exception erhalten, wenn der Service bereits gestoppt ist - deshalb checke ich zuerst die CanStop Eigenschaft, ob der Service überhaupt gestoppt werden kann.

Apropos Falle: natürlich darf nicht jedermann Services stoppen - dieses Recht haben nur einige Benutzergruppen, deshalb muß man für die korrekten Zugriffsrechte (NTFS) auf den ASP.NET Dateien sorgen!

Starten eines Services

Eigentlich führe ich das nur noch zur Vervollständigung an, da alle Befehle (stoppen, starten, pausieren) nach dem gleichen Muster funktionieren - der Aufruf einer Methode reicht. Hier eben der Aufruf, um den FTP Service zu starten:

ServiceController myService = new ServiceController("MSFTPSVC");
myService.Start();

Auf diese Art und Weise könnte man den FTP Service einschalten, wenn man ihn benötigt - ohne eine potentielle Sicherheitslücke allzulange offenzulassen.

Schlußbemerkung

Visuell sieht das noch nicht nach einem zusammenhängenden Administrationsinterface für Services aus - allerdings ist dies nur noch ein kleiner Schritt. In weiteren Artikeln werde ich das Portfolio an Administrationstools dann vervollständigen.

This printed page brought to you by AlphaSierraPapa

Download des Codes

Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20000925.zip

Verwandte Artikel

Ausgabe der Event Log Einträge a la ASP.NET
http:/www.aspheute.com/artikel/20000811.htm
Performance Monitoring a la .NET
http:/www.aspheute.com/artikel/20000809.htm

 

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.