Przejdź do treści

Komendy

Komendy to komunikaty, które wykorzystywane są do zgłoszenia żądania wykonania konkretnej operacji w systemie.

Tworzenie komendy

Do tworzenia komend została dodana akcja w menu edytora kodu, która tworzy bazową komendę z szablonu.

Nowa komenda

Definiowanie komendy

Note

Zalecane jest stosowanie języka imperatywnego do nadawania nazw komend, np.: CreateOrder, SendEmail, itp.

Nazwa komendy powinna być konkretnie wskazywać jaką operację ma wywoływać.

Własności komendy należy traktować jak parametry potrzebne do sterowania handlerem tej komendy.

Przykład komendy

public class InvoiceOCRCommand : NeosCommand
{
  public string FilePath
  {
    get; set;
  }
}

W przykładowej komendzie jej nazwa wskazuje na wywołanie operacji OCRu faktury, a za pomocą parametru przykazujemy ścieżkę pliku, który ma być poddany procesowi OCR.

Wysłanie komendy

Do wysyłania komend służą metody klasy EDA:

EDA.SendCommand<TCommand>(string target, TCommand commandMessage)

Podstawowa metoda wysyłania komendy. Przyjmuje adres, na który należy wysłać komendę oraz obiekt komendy. Wykorzystanie tej metody tworzy nowy kontekst komunikacyjny.

Adres (target) jest ciągiem znaków. Może przyjąć następujące wartości:

  • {Projekt}.{Obiekt}.{MetodaObsługująca}, np. EDA.SendCommand("WORKFLOW.GQS.GQSDeleteIndexCommandHandler", command) - komenda wysyłana jest do konkretnej metody (handlera), określonego obiektu biznesowego w konkretnym projekcie. Handler musi być widoczny w tej samej instancji serwera Neos, z którego odbywa się wysłanie komendy.
  • {Projekt}.{Obiekt}.{NazwaKolejkiFizycznej}, np. EDA.SendCommand("ECOM.ECOMADAPTERIAI.UpdateOrder", command) - komenda wysyłana jest na konkretną kolejkę fizyczną, która może obsługiwać wiele różnych komend. Więcej o kolejkach fizycznych napisano tutaj.
  • {GrupaKonektorów}.{SymbolKonektora} - komenda wysyłana jest na określony konektor EDA w danej grupie konektorów. To z definicji konektora wynika na jaki obiekt i handler jest wysyłana komenda, przy czym może to być handler domyślny dla komendy. Nazwa handlera domyślnego jest budowana automatycznie w oparciu o nazwę klasy komendy. Przykładowo, jeśli wyślemy komendę IndexCommand to handlerem domyślnym jest metoda o nazwie IndexCommandHandler. W definicji konektora można także określić identyfikator serwera Neos, do którego ma być skierowana komenda. Użycie konektorów jest jedynym sposobem przesyłania komend między różnymi serwerami Neos. Więcej na temat konektorów napisano tutaj.
  • {GrupaKonektorów}.{SymbolKonektora}:{MetodaObsługująca} - jak wyżej, przy czym komenda jest przekazywana do konkretnej metody (handlera)
  • {GrupaKonektorów}.{SymbolKonektora}:{NazwaKolejkiFizycznej} - jak wyżej, przy czym komenda jest kierowana do konkretnej kolejki fizycznej
  • {GrupaKonektorów} - komenda wysyłana jest na domyślny konektor z danej grupy konektórów.

EDA.SendCommand<TCommand>(string target, TCommand commandMessage, ConsumeContext context)

Metoda pozwalająca na zachowanie kontekstu przetwarzania komunikatu, w ramach którego następuje wysłanie nowej komendy. Jeśli w handlerze jednego komunikatu, chcemy wysłać na szynę kolejny komunikat z jednoczesnym przekazaniem, że są to komunikaty w ramach jednej konwersacji, to parametr context otrzymany w parametrze handlera przekazujemy do kolejnego wywołania EDA.SendCommand(target, commandMessage, context).

Przykład:

public HandlerResult Command1Handler(ConsumeContext<TestProject.Command1> context)
{
  // ...
  EDA.SendCommand("TESTPROJECT.TESTOBJECT", new TestProject.Command2(), context);
  return HandlerResult.Handled;
}

EDA.SendCommand<TCommand>(string target, TCommand commandMessage, Action OnSuccess, Action<NeosFailed> OnFailure)

Specjalna wersja metody wysyłania komendy, która może być użyta tylko jako inicjująca procesy w efekcie akcji użytkownika. Pozwala na wywołanie metod interfejsowych po zakończeniu działania procesu wywołanego przez wysłaną komendę.

Przykład:

    ...
    EDA.SendCommand(connector, command, () =>
    {
        RefreshData();
        ShowBalloonHint(string.Format("Zakończono OCR dokumentu '{0}'.", symbol));
    }, failedEvent =>
    {
        ShowBalloonHint(string.Format("OCR dokumentu '{0}' zakończył się błędem: {1}.", symbol, failedEvent.Exceptions[0].Message), "Błąd!", IconType.STOP);
        RefreshData();
    });     

Ważne!

Aby mechanizm zadziałał w wywołanym procesie musi być zwrócony musi być zwrócony stan przetwarzania HandleResult.PipeSuccess przynajmniej raz.

Uwaga!

Zdefiniowane w metodzie akcje wykonają się tylko raz, niezależnie od liczby zwróconych w procesie stanów HandleResult.PipeSuccess.

Obsługa komendy

Obsługa komunikatów

Synchroniczne wykonywanie metod handlera

Zamiast wysyłać komendę na szynę komunikatów, handler można wywołać jeszcze synchronicznie. Służy do tego metoda ExecuteCommand.

ExecuteCommand<TCommand>(string, TCommand)

Działa ona analogicznie jak SendCommand, z tym że wykonanie metody ExecuteCommand nie zakończy się dopóki nie zakończy się metoda handlera. Wyjątek rzucony przez metodę handlera zostanie rzucony również przez ExecuteCommand. Tak wywołany handler będzie widoczny w monitorze EDA i zostanie oznaczony jako wywołanie synchroniczne. Dodatkowo ExecuteCommand umożliwia zwrócenie dowolnych wartości z metody handlera, tak jak pokazano w poniższym przykładzie.

public HandlerResult CommandHandler(ConsumeContext<TestProject.Command> context)
{
  // ...
  context.SetResult("Description", "Wartość zwracana");
  context.SetResult("REF", 123);
  return HandlerResult.Handled;
}
public void ExecCmd()
{
  var result = EDA.ExecuteCommand("TestProject.EXECUTECOMMAND.CommandHandler", new Command());
  string description = (string)result["Description"]; // "Wartość zwracana"
  int REF = (int)result["REF"]; // 123
  var handlerResult = result.HandlerResult; // Handled
}

!!! Danger Uwaga! Metoda context.SetResult() dostępna jest tylko i wyłącznie przy wywołaniu handlera przez ExecuteCommand()! Jeżeli zostanie ona wywołana w kontekście asynchronicznym, czyli wywołanym przez SendCommand() to zostanie rzucony wyjątek System.InvalidOperationException. Jeżeli chcemy, aby nasz handler działał także dla wywołań asynchronicznych, należy wykorzystać context.IsExecuteCommandContext() np.:

```csharp

public HandlerResult CommandHandler(ConsumeContext<TestProject.Command> context)
{
  // ...
  if (context.IsExecuteCommandContext())
  {
    context.SetResult("Description", "Wartość zwracana");
    context.SetResult("REF", 123);
  }
  return HandlerResult.Handled;
}
```

Gdy wywołujemy ExecuteCommand wewenątrz metody handlera, to podobnie jak to ma miejsce w przypadku metody SendCommand, możemy dodatkowo połączyć to wywołanie w jeden potok przetwarzania przekazując kontekst.

public HandlerResult CommandHandler(ConsumeContext<TestProject.Command> context)
{
  // ...
  var result = EDA.ExecuteCommand("TestProject.EXECUTECOMMAND.CommandHandler", new Command(), context);
  // ...
}

Uwaga!

Handlery wykonane przez ExecuteCommand nie będą dobrze działać z innymi mechanizmami EDA takimi jak deduplikacja, ponawianie, ponowne przetwarzanie itp.