Erweiterte Programmierung


In .NET kennen Sie das Prinzip der asynchroner programmierung und der Deklaration von Asynchronen Methoden mit dem async-Schlüsselwort. Leider funktioniert dies nur innerhalb der selben Anwendungsdomäne und nicht netzwerkweit. Für eine netzwerktransparente asynchrone programmierung stellt iPlus das Konzept der "Punkte für Asynchrone Methoden" zur Verfügung:

 

 

Im Kapitel Ereignisse wurde das Prinzip von Callback-Methoden im Zusammenhang mit Punkten erklärt.

Asynchrone Methoden basieren auf dem selben Entwurfsmuster und sind lediglich eine erweiterte Implementierung (blau gestrichelter Rahmen):

 

IACPointAsyncRMI<T> erbt von zwei Schnittstellen:

  1. IACPointNet<T, W> - Ein Netzwerkfähiger IACPoint<W> der in der Lage ist seine ConnectionList-Eigenschaft über der das Netzwerk übertragen zu können.
  2. IACPointNetService<T, W>, das einen "Service-Punkt" darstellt. Ein Service-Punkt stellt im abstrakten Sinne einen Dienst für seine ConnectionList-Einträge bereit. 

Die Klasse ACPointAsyncRMI implementiert IACPointAsyncRMI<T>. Mit ACPointAsyncRMI-Instanzen können Komponenten asynchrone Methoden bereitstellen, die netzwerkweit aufgerufen werden können. Die asynchrone Aufrufe werden in die ConnectionList eingetragen. Konsumenten (Komponenten aus der selben oder einer entfernten Anwendungsdomäne) können die ConnectionList nicht direkt befüllen sondern benötigen die Schnittstelle IACPointAsyncRMISubscr:

IACPointAsyncRMISubscr<T> erbt von zwei Schnittstellen:

  1. IACPointNet<T, W> - Ein Netzwerkfähiger IACPoint<W> der in der Lage ist seine ConnectionList-Eigenschaft über der das Netzwerk übertragen zu können.
  2. IACPointNetClient, das einen "Client-Punkt" darstellt. Ein Client-Punkt stellt im abstrakten Sinne einen Konsumenten dar, der Dienstleistungen von Service-Punkten in Anspruch nimmt.

Die Klasse ACPointAsyncRMISubscr implementiert IACPointAsyncRMISubscr<T>.


Zum Aufruf von Asynchronen Methoden wird das Interface IACPointAsyncRMISubscr<T> verwendet. Wie auch bei der Abonnierung von Ereignissen muss eine Callback-Methode als Delegat und zusätzlich noch eine virtuelle Methode (Parameter acMethod) übergeben werden:

ACPointAsyncRMISubscrWrap<T> InvokeAsyncMethod(IACComponent atACComponent, string asyncRMIPointName, ACMethod acMethod, ACPointNetEventDelegate AsyncCallbackDelegate);

ACPointAsyncRMISubscrWrap<T> InvokeAsyncMethod(IACComponent atACComponent, string asyncRMIPointName, ACMethod acMethod, ACPointNetEventDelegate AsyncCallbackDelegate, bool AutoRemove);

ACPointAsyncRMISubscrWrap<T> InvokeAsyncMethod(IACComponent atACComponent, string asyncRMIPointName, ACMethod acMethod, string asyncCallbackDelegateName);

ACPointAsyncRMISubscrWrap<T> InvokeAsyncMethod(IACComponent atACComponent, string asyncRMIPointName, ACMethod acMethod, string asyncCallbackDelegateName, bool AutoRemove);

 


Asynchrone Methoden müssen

haben:

[ACMethodAsync("Process", "en{'Example asynchronous method'}de{'Beispiel asynchrone Methode'}", 999, false)]
public virtual ACMethodEventArgs ExampleMethodAsync (ACMethod acMethod)

ACPointAsyncRMI-Punkte werden mit der Attributklasse ACPropertyAsyncMethodPoint und die asynchrone Methode mit der Attributklasse ACMethodAsync versehen.

Nach der Instanziierung der Klasse ACPointAsyncRMI  im Konstruktor wird dem SetMethod-Delegaten die Methode "OnSetInvocationPoint" zugewiesen. Sie wird immer dann aufgerufen, wenn ein neuer Eintrag in der ConnectionList gemacht wird bzw. ein neuer asynchroner Aufruf hinzugefügt wird. Die Implementierung des SetMethod-Delegaten kann individuell sein. Im folgenden Bespielcode wird die Methode DeQueueInvocationList() aufgerufen, die alle neuen Einträge startet (Variante A). Intern ruft sie dazu die Methode ActivateAsyncRMI() auf wie es alternativ unter Variante B programmiert ist:

 

In der Regel erledigen asynchrone Methoden Ihre Arbeit in anderen Threads. Meist wird auch ein Zustandsautomat durchlaufen, der erst beim erreichen seines End-Zustands den Aufrufer benachrichtigt, dass die asynchrone Methode abgeschlossen wurde. Dies geschieht durch den Aufruf der Methode InvokeCallbackDelegate().  Sehen wir uns dazu im folgenden Abschnitt an wie der Callback auf Verbraucher-Seite aufgerufen wird: 


Der Client-Punkt ACPointAsyncRMISubscr muss mit der Attributklasse ACPropertyAsyncMethodPointSubscr versehen werden. Als letzten Parameter kann man optional den Namen der Default-Callback-Methode angeben. Die Callback-Methode wird beim Aufruf der InvokeAsyncMethod()-Methode übergeben, um die Methode "ExampleMethodAsync" asynchron aufzurufen. Der Name der "ExampleMethodAsync"-Methode muss nicht übergeben werden, weil die virtuelle Methode "MixingTemperature" diese implizit kennt:

 

Synchroner Aufruf

Asynchrone Methoden können auch synchron aufgerufen werden wie es in der obigen Beispielmethode "InvokeVirtualMethodSync" programmiert ist. Bitte bedenken Sie dabei, dass der aufrufende Thread solange blockiert ist, bis die asynchrone Abarbeitung durchgeführt ist. Diese Vorgehensweise ist daher nicht empfehlenswert außer sie kennen das Laufzeitverhalten der asynchronen Methode und haben diesen blockierende Effekt miteinkalkuliert.

Synchrone Aufrufe sind vergleichbar mit dem await-Operator in c# - jedoch netzwerktransparent.


Workflows

Workflows, die zur Laufzeit geladen werden, leiten ihre persistierten virtuellen Methoden an die asynchrone Start-Methode von Prozessfunktionen im physikalischen Modell weiter. Der Punkt für asynchrone Methodenaufrufe ist jedoch nicht in der PAProcessFunction-Klasse deklariert, sondern in seiner Elternklasse (ParentACComponent), die von Typ PAProcessModule ist.

PAProcessModule implementiert das interface IACComponentTaskExec. Das Interface schreibt vor, dass die zu implementierende Klasse den Punkt ACPointTask TaskInvocationPoint bereitstellen muss. ACPointTask ist lediglich eine Ableitung von ACPointAsyncRMI. ACPointTask persistiert seine ConnectionList in der Tabelle ACClassTaskValuePos im Gegensatz zur Basisklasse ACPointAsyncRMI, welche die ConnectionList als XML serialisiert und in der Tabelle ACClassTaskValue speichert.

 

Implementierung der Methoden von IACComponentTaskExec:

Falls sie selbst ACPointTask verwenden möchten, sollten Sie das interface IACComponentTaskExec verwenden und folgende Methoden auf dieser Art implementieren:

public virtual bool ActivateTask(ACMethod acMethod, bool executeMethod, IACComponent executingInstance)
{
return ACPointAsyncRMIHelper.ActivateTask(this, acMethod, executeMethod, executingInstance);
}

public virtual bool CallbackTask(ACMethod acMethod, ACMethodEventArgs result, PointProcessingState state)
{
return ACPointAsyncRMIHelper.CallbackTask(this, acMethod, result, state);
}

public virtual bool CallbackTask(IACTask task, ACMethodEventArgs result, PointProcessingState state)
{
return ACPointAsyncRMIHelper.CallbackTask(this, task, result, state);
}

public IACTask GetTaskOfACMethod(ACMethod acMethod)
{
return ACPointAsyncRMIHelper.GetTaskOfACMethod(this, acMethod);
}

public virtual bool CallbackCurrentTask(ACMethodEventArgs result)
{
return ACPointAsyncRMIHelper.CallbackCurrentTask(this, result);
}

Delegieren Sie nur die Aufrufe an die Methoden der Klasse ACPointAsyncRMIHelper weiter. Diese Methoden sind nur Hilfsmethoden für einen etwas vereinfachten Umgang mit dem Aufruf der Callback-Methoden. Verwenden Sie bitte diese Methoden anstatt ACPointNetAsyncRMI<T>.InvokeCallbackDelegate().