Heim > Artikel > Backend-Entwicklung > C# Message Queuing-Anwendung-2
Innerhalb dieses Arrays erstellt die CWorker-Klasse eine Implementierung
der CWorkerThread-Klasse. CWorkerThread
Eine Klasse (siehe unten) ist eine abstrakte Klasse, die vererbt werden muss. Die exportierte Klasse
definiert, wie Nachrichten verarbeitet werden:
aThreads = new ArrayList();
(int idx=0; idx〈sfWorker.NumberThreads; idx++)
{
WorkerThreadFormatter
wfThread = new WorkerThreadFormatter();
wfThread.PRocessName = sfWorker.ProcessName;
wfThread.ProcessDesc = sfWorker.ProcessDesc;
wfThread.ThreadNumber = idx;
wfThread.InputQueue = sfWorker.InputQueue;
wfThread.ErrorQueue =
sfWorker.ErrorQueue;
wfThread.OutputName = sfWorker.OutputName;
Definieren Sie den Hilfstyp und fügen Sie ihn in die Hilfs-Thread-Struktur
CWorkerThread wtBase;
(sfWorker.ProcessType)
{
case
WorkerFormatter.SFProcessType.ProcessRoundRobin:
wtBase = new
CWorkerThreadRoundRobin(this, wfThread);
break;
WorkerFormatter.SFProcessType.ProcessAppSpecific:
wtBase = new
CWorkerThreadAppSpecific(this, wfThread);
break;
WorkerFormatter.SFProcessType.ProcessAssembly:
wtBase = new
CWorkerThreadAssembly(this, wfThread);
break;
throw new Exception("Unknown Processing Type");
}
// Einen Aufruf zum Array hinzufügen
aThreads.Insert(idx, wtBase);
}
Sobald alle Objekte erstellt wurden, können Sie sie starten, indem Sie die Start-Methode jedes Thread-Objekts aufrufen:
foreach (CWorkerThread
cThread in aThreads)
cThread.Start();
Die Methoden Stop, Pause und Continue führen ähnliche Vorgänge in der foreach-Schleife aus.
Stop-Methode verfügt über die folgenden Garbage-Collection-Vorgänge:
GC.SuppressFinalize(this);
Die Stop-Methode wird im Klassendestruktor aufgerufen, sodass das Objekt korrekt beendet werden kann, ohne die Stop-Methode explizit aufzurufen
. Wenn Stop aufgerufen wird
-Methode besteht keine Notwendigkeit, den
-Konstruktor zu analysieren. Die SuppressFinalize-Methode verhindert den Aufruf der Finalize-Methode des Objekts (Analyse der tatsächlichen Implementierung des
-Konstruktors).
CWorkerThread abstrakte Klasse
CWorkerThread ist eine Klasse bestehend aus CWorkerThreadAppSpecifc, CWorkerThread
RoundRobin und
Von CWorkerThreadAssembly geerbte abstrakte Klasse. Unabhängig davon, wie Sie die Nachricht verarbeiten, ist die Verarbeitung der Warteschlange zum größten Teil gleich, sodass die Klasse CWorkerThread diese Funktionalität bereitstellt.
Diese Klasse stellt abstrakte Methoden bereit (die durch tatsächliche Methoden ersetzt werden müssen), um Ressourcen zu verwalten und Nachrichten zu verarbeiten.
Die Eingabe- und Fehlerwarteschlangen werden in der Start-Methode referenziert. existieren Im .NET Framework werden Nachrichten vom System
Messaging-Namespace verarbeitet:// Versuchen Sie, die Warteschlange zu öffnen und die Standard-Lese- und Schreibeigenschaften festzulegen
MessageQueue mqInput = new MessageQueue(sInputQueue);mqInput.MessageReadPropertyFilter.Body = true;
mqInput.MessageReadPropertyFilter.AppSpecific = true;
mqError = new MessageQueue(sErrorQueue);
// Wenn Sie MSMQ COM verwenden, setzen Sie den Formatierer auf ActiveX
mqInput.Formatter = new ActiveXMessageFormatter();
Sobald die Nachrichtenwarteschlangenreferenz definiert ist, wird ein Thread für die eigentliche Verarbeitungsfunktion
(genannt ProcessMessages) erstellt. Verwenden Sie im .NET Framework
Der Namespace System.Threading
erleichtert die Implementierung von Threading:
procMessage = new Thread(new
ThreadStart(ProcessMessages));
procMessage.Start();
Die ProcessMessages-Funktion ist eine Verarbeitungsschleife, die auf booleschen Werten basiert. Wenn der Wert auf
False gesetzt ist, wird die Verarbeitungsschleife beendet. Daher ist der Stop des Thread-Objekts
Die Methode legt nur diesen booleschen
-Wert fest, schließt dann die offene Nachrichtenwarteschlange und verbindet den Thread mit dem Hauptthread:
// Treten Sie dem Service-Thread und dem Verarbeitungsthread bei
procMessage.Join();
//Schließen Sie die offene Nachrichtenwarteschlange
mqInput.Close();
mqError.Close();
if (bPause)
Thread.Sleep (500) ;
Schließlich ruft jede Start-, Stop-, Pause- und Continue-Methode die Zusammenfassung
OnStart, OnStop, OnPause und auf
OnContinue-Methode. Diese abstrakten Methoden stellen Hooks für Klassen bereit, die
implementieren, um erforderliche Ressourcen zu erfassen und freizugeben.
Die ProcessMessages-Schleife hat die folgende Grundstruktur:
●Wenn die Nachricht erfolgreich empfangen wurde, wird die abstrakte ProcessMessage-Methode aufgerufen.
●Wenn der Empfang oder die Verarbeitung einer Nachricht fehlschlägt, senden Sie die Nachricht an die Fehlerwarteschlange.Message mInput;
try
{
// Aus der Warteschlange lesen und 1 Sekunde warten
mInput =
mqInput.Receive(new TimeSpan(0,0,0,1));
}
catch (MessageQueueException
mqe)
{
// Setze die Nachricht auf null
mInput = null;
// Überprüfen Sie den Fehlercode, um festzustellen, ob eine Zeitüberschreitung aufgetreten ist
if (mqe.ErrorCode != (-1072824293) ) //0xC00E001B
{
//
Wenn es nicht zu einer Zeitüberschreitung kommt, geben Sie einen Fehler aus und protokollieren Sie die Fehlernummer
LogError("Error: " + mqe.Message);
}
}
if (mInput != null)
{
// Eine zu verarbeitende Nachricht abrufen und die abstrakte Methode zur Nachrichtenverarbeitung aufrufen
try
{
ProcessMessage(mInput);
}
// Fehler mit bekanntem abnormalen Status erfassen
Catch (CWorkerThreadException ex)
{
ProcessError(mInput,
ex.Terminate);
}
// Die unbekannte Ausnahme abfangen und Terminate aufrufen
{
ProcessError(mInput, true);
}
}
Die ProcessError-Methode sendet die Fehlermeldung an die Fehlerwarteschlange. Darüber hinaus kann es auch dazu führen
ThreadException auslöst.
CworkerThread exportierte Klasse
Jede Klasse, die von CWorkerThread erbt, muss OnStart, OnStop, On
Pause, OnContinue und bereitstellen ProcessMessage-Methode. Die Methoden OnStart und OnStop erfassen und geben Verarbeitungsressourcen frei. OnPause und OnContinue Methoden ermöglichen die vorübergehende Freigabe undWiedergewinnung dieser Ressourcen. Die ProcessMessage-Methode sollte die Nachricht verarbeiten und
auslösen, wenn ein Fehlerereignis auftritt
CWorkerThreadException-Ausnahme.
Da der CWorkerThread-Konstruktor Laufzeitparameter definiert, muss die abgeleitete Klasse den Basisklassen-
-Konstruktor aufrufen:
Formatter v_wfThread)
: base (v_cParent, v_wfThread) {}
Die exportierte Klasse bietet zwei Arten der Verarbeitung: Senden der Nachricht an eine andere Warteschlange oder Aufrufen der Komponentenmethode
. Beide Implementierungen des Empfangens und Sendens von Nachrichten verwenden Schleifentechniken oder Anwendungsoffsets (Keeping).
sollte eine Liste von Warteschlangenpfaden enthalten. OnStart implementiert und
Die OnStop-Methode
sollte Verweise auf diese Warteschlangen öffnen und schließen:
iQueues = wfThread.OutputName.Length;
mqOutput = new MessageQueue[iQueues];
for (int idx=0; idx〈iQueues;
idx++)
{
mqOutput[idx] = new MessageQueue(wfThread.OutputName[idx]);
mqOutput[idx].Formatter = new ActiveXMessageFormatter();
}
In diesen Szenarien ist die Nachrichtenverarbeitung einfach: Senden Sie die Nachricht an die erforderliche Ausgabewarteschlange. Im Fall einer
-Schleife ist dieser Vorgang:
{
mqOutput[iNextQueue].Send(v_mInput);
}
catch (Ausnahme ex)
{
// Erzwungene Beendigungsausnahme bei Fehler
throw new CWorkerThreadException(ex.Message, true);
// Berechnen Sie die nächste Warteschlangennummer
iNextQueue++;
iNextQueue %= iQueues;
Die letztere Methode zum Aufrufen einer Komponente mit Nachrichtenparametern ist interessanter. Prozessnachricht
Die
-Methode verwendet die IWebMessage-Schnittstelle, um eine .NET-Komponente aufzurufen. Die Methoden OnStart und OnStop
rufen die Referenz dieser Komponente ab und geben sie frei.
Die Konfigurationsdatei in diesem Szenario sollte zwei Elemente enthalten: den vollständigen Klassennamen und den
Speicherort der Datei, in der sich die Klasse befindet. Rufen Sie es gemäß der Definition in der IWebMessage-Schnittstelle für die Komponente auf
Prozessmethode.
Die Nummer erfordert einen Montagetyp. Hier wird der Pfad und der Klassenname der Assemblydatei exportiert.
Sobald die Objektreferenz erhalten wurde, wird sie in die entsprechende Schnittstelle eingefügt:
private string sFilePath, sTypeName;
Assembly-Pfad und Typnamen speichern
sFilePath = wfThread.OutputName[0];
wfThread.OutputName[1];
// Einen Verweis auf das erforderliche Objekt abrufen
Assembly asmSample =
Assembly.LoadFrom(sFilePath);
Type typSample = asmSample.GetType(sTypeName);
objSample = Activator.CreateInstance(typSample);
// Definieren Sie die erforderliche Schnittstelle für das Objekt
iwmSample = (IWebMessage)objSample;
Nachdem die ProcessMessage-Methode die Objektreferenz erhalten hat, ruft sie die
Process-Methode auf der IWebMessage-Schnittstelle auf:
WebMessageReturn wbrSample;
try
{
// Parameter für Methodenaufruf definieren
string
sLabel = v_mInput.Label;
string sBody = (string)v_mInput.Body;
iAppSpecific = v_mInput.AppSpecific;
// Rufen Sie die Methode auf und erfassen Sie den Rückgabecode
wbrSample =
iwmSample.Process(sLabel, sBody, iAppSpecific);
}
catch
(InvalidCastException ex)
{
// Wenn ein Fehler im Nachrichteninhalt auftritt, erzwingen Sie eine nicht terminierende Ausnahme
new CWorkerThreadException(ex.Message, false);
}
catch (Exception ex)
{
// Wenn die Assembly falsch aufgerufen wird, erzwingen Sie eine Beendigungsausnahme
werfen Sie neu
CWorkerThreadException(ex.Message, true);
}
//Wenn kein Fehler vorliegt, überprüfen Sie den Rückgabestatus des Objektaufrufs
switch (wbrSample)
{
case WebMessageReturn.ReturnBad:
throw
new CWorkerThreadException
(„Nachricht konnte nicht verarbeitet werden: Nachricht markiert
bad", false);
case WebMessageReturn.ReturnAbort:
throw new
CWorkerThreadException
(„Nachricht konnte nicht verarbeitet werden: Process
terminating", true);
Standard:
break;
}
Fehler, vielleicht möchten Sie den Vorgang abbrechen, aber hier markieren Sie die Nachricht einfach als Fehlermeldung
.
verwenden Sie die Methoden OnPause und OnContinue, um Objektverweise freizugeben und erneut abzurufen.
Status der Anwendung zu überwachen. . NET Framework vereinfacht die Integration von Ereignisprotokollen, Leistungsindikatoren und Windows-Verwaltungsinstrumentierungsgeräten (WMI) erheblich
) in den Bewerbungsprozess einbinden. Die Messaging-Anwendung verwendet Zeitprotokolle und Leistungsindikatoren, beide aus der System.Diagnostics-Assembly.
In der ServiceBase-Klasse können Sie die Ereignisprotokollierung automatisch aktivieren. Darüber hinaus unterstützt das ServiceBase
EventLog-Mitglied das Schreiben in das Anwendungsereignisprotokoll:
Für Anwendungen, die in das Ereignisprotokoll statt in das Anwendungsprotokoll schreiben, ist es möglich, einfach
einen Verweis auf das Ereignisprotokoll zu erstellen und abzurufen Ressource ( wie in
Dasselbe wie in der CWorker-Klasse gemacht),
private EventLog cLog;
string sSource = ServiceControl.ServiceControlName;
string sLog = "application"//
Überprüfen Sie, ob die Quelle vorhanden ist. Wenn nicht, erstellen Sie die Quelle
if (!EventLog.SourceExists(sSource))
EventLog.CreateEventSource(sSource, sLog);
// Erstellen Sie ein Protokollobjekt und verweisen Sie auf die aktuell definierte Quelle
cLog =
new EventLog();
cLog.Source = sSource;// Schreiben Sie einen Eintrag in das Protokoll, um die erfolgreiche Erstellung anzuzeigen
cLog.WriteEntry("Erfolgreich erstellt", EventLogEntryType.Information);
Das .NET Framework vereinfacht Leistungsindikatoren erheblich. Die Messaging-Anwendung stellt Zähler für jeden Verarbeitungsthread, jeden Thread-exportierten Benutzer
und die gesamte Anwendung bereit, um Nachrichten zu verfolgen.
Die Anzahl der Nachrichten und die Anzahl der pro Sekunde verarbeiteten Nachrichten. Um diese Funktionalität bereitzustellen, müssen Sie eine Klasse von Leistungsindikatoren
definieren und dann die entsprechende Zählerinstanz erhöhen.
Die Kategorie der Leistungsindikatoren wird in der OnStart-Methode des Dienstes definiert. Diese Kategorien stellen zwei Zähler dar – die Gesamtzahl der Nachrichten und die Anzahl der pro Sekunde verarbeiteten Nachrichten:
CounterCreationData[] cdMessage = new CounterCreationData[2];
cdMessage[0] = new CounterCreationData("Messages/Total", "Total
Messages
Verarbeitet",
cdMessage[1] = neu
CounterCreationData("Nachrichten/Sekunde",
"Eine Sekunde verarbeitete Nachrichten",
PerformanceCounterType.RateOfChangePerSecond32);
PerformanceCounterCategory.Create("MSDN Message Service", "MSDN
Message
Service Counters", cdMessage);
Sobald die Leistungsindikatorkategorie definiert ist, wird ein PerformanceCounter-Objekt für den Zugriff erstellt
Fragen Sie nach der Funktion der Zählerinstanz. Ein PerformanceCounter-Objekt erfordert eine Kategorie, einen Zählernamen und einen
optionalen Instanznamen. Für den Hilfsprozess wird der Prozessname aus der XML-Datei verwendet, der Code lautet wie folgt:
pcMsgTotWorker = new PerformanceCounter("MSDN Message Service",
"Nachrichten/Gesamt", sProcessName);
"Messages/Second", sProcessName);
pcMsgTotWorker.RawValue = 0;
pcMsgSecWorker.RawValue = 0;
Um den Zähler zu erhöhen, rufen Sie einfach die entsprechende Methode auf:
pcMsgTotWorker.IncrementBy(1);
pcMsgSecWorker.IncrementBy(1);
Abschließend sollte die installierte Leistungsindikatorkategorie aus dem System gelöscht werden, wenn der Dienst beendet wird:
PerformanceCounterCategory.Delete("MSDN Message Service");
Da Leistungsindikatoren im .NET Framework funktionieren, muss ein spezieller Dienst ausgeführt werden.
Dieser Dienst (PerfCounterService) stellt gemeinsam genutzten Speicher bereit. Zählerinformationen werden in den gemeinsam genutzten
Speicher geschrieben und vom Leistungsindikatorsystem gelesen.
Installation
Bevor wir zum Schluss kommen, stellen wir kurz die Installation und das
Installationstool namens installutil.exe vor. Da diese Anwendung ist
Windows-Dienst, er muss mit installutil.exe
installiert werden. Daher muss man eines von System.Configuration.Install verwenden
In Assembly geerbte Installer-Klasse
:
öffentliche Klasse ServiceRegister: Installer
{
privater ServiceInstaller serviceInstaller;
privater ServiceProcessInstaller
ProcessInstaller;
public ServiceRegister()
{
// Einen Dienst-Installer erstellen
serviceInstaller = new ServiceInstaller();
serviceInstaller.StartType = ServiceStart.Manual;
serviceInstaller.ServiceName = ServiceControl.ServiceControl
Name;
serviceInstaller.DisplayName = ServiceControl.ServiceControl
Desc;
Installers.Add(serviceInstaller);
// Ein Prozessinstallationsprogramm erstellen
ProcessInstaller = new ServiceProcessInstaller();
ProcessInstaller.RunUnderSystemAccount = true;
Installers.Add(processInstaller);
}
}
Wie in dieser Beispielklasse gezeigt, erfordern der Dienst und der Dienstprozess jeweils ein
Installationsprogramm Definieren Sie das Konto, unter dem der Dienst ausgeführt wird. Andere Installationsprogramme ermöglichen die Registrierung von Ereignisprotokollen und
Ressourcen wie Leistungsindikatoren.
Zusammenfassung
Wie aus diesem .NET Framework-Anwendungsbeispiel hervorgeht, können Anwendungen, die in der Vergangenheit nur von Visual C++
Programmierern geschrieben werden konnten, jetzt einfach objektorientiert geschrieben werden Programme durchführen. Auspuff
Obwohl unser Fokus auf C# liegt, gelten die in diesem Artikel beschriebenen Inhalte auch für Visual Basic und
Managed C++
Das Framework ermöglicht Entwicklern die Erstellung leistungsstarker, skalierbarer Windows-Anwendungen und -Dienste mit jeder Programmiersprache.
häufig vergessene Anwendungsinstrumentierungsgeräte (wie Leistungsüberwachungszähler und Ereignisprotokollbenachrichtigungen).
In die App integriert. Obwohl die Anwendung hier keine Windows Management Detection Devices
(WMI) verwendet, kann sie auch vom .NET Framework angewendet werden.