Sist endret: 29. okt. 2026
Preview: Dette er dokumentasjonen for Altinn Studio v9, som er en forhåndsversjon. Gjeldende versjon er v8. For å se dokumentasjonen for gjeldende versjon, velg v8 i versjonsvelgeren i menyen til venstre.

Flytkontroll

Slik styrer du hvilken vei prosessen følger med gateways, uttrykk og tilpasset kode.

Eksklusive gateways

Med en eksklusiv gateway velger du hvilken vei prosessen følger videre. Valget kan bygge på det brukeren fyller ut, på andre data eller på tilpasset kode.

Gateways som kontrollerer flyten med uttrykk

Forutsetninger

Du trenger en prosess som inneholder en eksklusiv gateway.

Slik styrer du flyten ut av en gateway med data fra brukeren

Du kan la data som brukeren leverte i en tidligere oppgave avgjøre hvilken flyt som går ut av gatewayen. Du bruker samme uttrykksspråk som når du skjuler eller viser elementer i brukergrensesnittet.

Først må du bestemme hvilke skjemadata uttrykkene skal kunne bruke.

Eksempel:

App/config/process/process.bpmn
...
<bpmn:exclusiveGateway id="Gateway_1">
    <bpmn:incoming>Flow_t1_g1</bpmn:incoming>
    <bpmn:outgoing>Flow_g1_t2</bpmn:outgoing>
    <bpmn:outgoing>Flow_g1_end</bpmn:outgoing>
    <bpmn:extensionElements>
        <altinn:gatewayExtension>
            <altinn:connectedDataTypeId>Schema</altinn:connectedDataTypeId>
        </altinn:gatewayExtension>
    </bpmn:extensionElements>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_g1_t2" sourceRef="Gateway_1" targetRef="Task_2" />
<bpmn:sequenceFlow id="Flow_g1_end" sourceRef="Gateway_1" targetRef="EndEvent" />
...

I eksempelet ovenfor bruker gatewayen skjemadata fra datatypen Schema i uttrykkene. Du definerer skjemadata og datatyper i filen applicationmetadata.json.

Når gatewayen er koblet til en datatype, kan du bruke uttrykksspråket til å avgjøre hvilke flyter ut av gatewayen som er tilgjengelige.

Nøyaktig én flyt må være gyldig når uttrykkene er regnet ut. Hvis ingen eller flere flyter er gyldige, går ikke prosessen videre, og brukeren får en feil. Systemet regner alltid en flyt uten uttrykk som gyldig.

Nå må du skrive uttrykkene i de utgående flytene fra gatewayen. Eksempelet har to utgående flyter: Flow_g1_t2 og Flow_g1_end.

Prosessen skal følge Flow_g1_t2 hvis feltet Amount i skjemadataene er større enn eller lik 1000, og Flow_g1_end hvis det er mindre enn 1000.

Du gjør dette ved å legge til betingelsesuttrykk (conditionExpression) i de utgående flytene.

App/config/process/process.bpmn
<bpmn:sequenceFlow id="Flow_g1_t2" sourceRef="Gateway_1" targetRef="Task_2">
    <bpmn:conditionExpression>["greaterThanEq", ["dataModel", "Amount"], 1000]</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_g1_end" sourceRef="Gateway_1" targetRef="EndEvent">
    <bpmn:conditionExpression>["lessThan", ["dataModel", "Amount"], 1000]</bpmn:conditionExpression>
</bpmn:sequenceFlow>

Hvis brukeren har sendt inn en Amount på 1000, blir uttrykket i sekvensflyten Flow_g1_end usant. Systemet fjerner da denne flyten fra dem det kan velge mellom. Den eneste tilgjengelige flyten er Flow_g1_t2, og derfor velger systemet den.

Du finner flere muligheter på siden om uttrykk.

Slik styrer du flyten ut av en gateway med brukerhandlingen

Du kan også la handlingen som brukeren eller systemet utførte i oppgaven før gatewayen, avgjøre hvilken flyt prosessen følger. Da skriver du et betingelsesuttrykk i prosessen, i tillegg til uttrykkene mot datamodellen.

Hvis appen har et bekreftelsessteg, kan du la sluttbrukeren avvise dataene. Prosessen sender da instansen tilbake til forrige oppgave (Task_1).

App/config/process/process.bpmn
<bpmn:task id="Task_2" name="Person">
    <bpmn:incoming>Flow_t1_t2</bpmn:incoming>
    <bpmn:outgoing>Flow_t2_g1</bpmn:outgoing>
    <bpmn:extensionElements>
        <altinn:taskExtension>
            <altinn:taskType>confirmation</altinn:taskType>
            <altinn:actions>
                <altinn:action>confirm</altinn:action>
                <altinn:action>reject</altinn:action>
            </altinn:actions>
        </altinn:taskExtension>
    </bpmn:extensionElements>
</bpmn:task>
<bpmn:exclusiveGateway id="Gateway_1">
    <bpmn:incoming>Flow_t2_g1</bpmn:incoming>
    <bpmn:outgoing>Flow_g1_t1</bpmn:outgoing>
    <bpmn:outgoing>Flow_g1_end</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_g1_t1" sourceRef="Gateway_1" targetRef="Task_1" />
<bpmn:sequenceFlow id="Flow_g1_end" sourceRef="Gateway_1" targetRef="EndEvent" />

I eksempelet ovenfor har Task_2 to handlinger: confirm og reject. Du kan lese mer om handlinger.

Prosessen skal følge Flow_g1_t1 hvis brukeren utfører handlingen reject, og Flow_g1_end hvis handlingen var confirm.

Du gjør dette med uttrykksfunksjonen gatewayAction:

App/config/process/process.bpmn
<bpmn:sequenceFlow id="Flow_g1_t1" sourceRef="Gateway_1" targetRef="Task_1">
    <bpmn:conditionExpression>["equals", ["gatewayAction"], "reject"]</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_g1_end" sourceRef="Gateway_1" targetRef="EndEvent">
    <bpmn:conditionExpression>["equals", ["gatewayAction"], "confirm"]</bpmn:conditionExpression>
</bpmn:sequenceFlow>

Uttrykksfunksjonen gatewayAction gir deg handlingen som ble utført i oppgaven prosessen nettopp forlot. I eksempelet ovenfor er det Task_2.

Du kan kombinere gatewayAction med alle de andre funksjonene i uttrykksspråket.

Komplekse gateways som krever tilpasset kode

Hvis uttrykk ikke er nok til å styre gatewayen din, kan du skrive tilpasset kode som tar valget om hvilken flyt prosessen skal følge.

Forutsetninger

Du trenger en prosess som inneholder en eksklusiv gateway.

Eksempelprosess med eksklusive gateways

App/config/process/process.bpmn
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:altinn="http://altinn.no/process" id="Altinn_SingleDataTask_Process_Definition" targetNamespace="http://bpmn.io/schema/bpmn" exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="10.2.0">
  <bpmn:process id="SingleDataTask" isExecutable="false">
    <bpmn:startEvent id="StartEvent_1">
      <bpmn:outgoing>Flow_s_t1</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:sequenceFlow id="Flow_s_t1" sourceRef="StartEvent_1" targetRef="Task_1" />
    <bpmn:task id="Task_1" name="Utfylling">
      <bpmn:incoming>Flow_s_t1</bpmn:incoming>
      <bpmn:outgoing>Flow_t1_g1</bpmn:outgoing>
      <bpmn:extensionElements>
        <altinn:taskExtension>
            <altinn:taskType>data</altinn:taskType>
        </altinn:taskExtension>
      </bpmn:extensionElements>
    </bpmn:task>
    <bpmn:sequenceFlow id="Flow_t1_g1" sourceRef="Task_1" targetRef="Gateway_1" />
    <bpmn:exclusiveGateway id="Gateway_1">
      <bpmn:incoming>Flow_t1_g1</bpmn:incoming>
      <bpmn:outgoing>Flow_g1_g2</bpmn:outgoing>
      <bpmn:outgoing>Flow_g1_t2</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:sequenceFlow id="Flow_g1_g2" sourceRef="Gateway_1" targetRef="Gateway_2" />
    <bpmn:sequenceFlow id="Flow_g1_t2" sourceRef="Gateway_1" targetRef="Task_2" />
    <bpmn:task id="Task_2" name="Bekreftelse">
      <bpmn:incoming>Flow_g1_t2</bpmn:incoming>
      <bpmn:outgoing>Flow_t2_g2</bpmn:outgoing>
      <bpmn:extensionElements>
        <altinn:taskExtension>
            <altinn:taskType>confirmation</altinn:taskType>
            <altinn:actions>
              <altinn:action>confirm</altinn:action>
            </altinn:actions>
        </altinn:taskExtension>
      </bpmn:extensionElements>
    </bpmn:task>
    <bpmn:sequenceFlow id="Flow_t2_g2" sourceRef="Task_2" targetRef="Gateway_2" />
    <bpmn:exclusiveGateway id="Gateway_2">
      <bpmn:incoming>Flow_g1_g2</bpmn:incoming>
      <bpmn:incoming>Flow_t2_g2</bpmn:incoming>
      <bpmn:outgoing>Flow_g2_end</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:sequenceFlow id="Flow_g2_end" sourceRef="Gateway_2" targetRef="EndEvent_1" />
    <bpmn:endEvent id="EndEvent_1">
      <bpmn:incoming>Flow_g2_end</bpmn:incoming>
    </bpmn:endEvent>
  </bpmn:process>
  <!-- BPMN Diagram part is omitted for brevity -->
</bpmn:definitions>

Diagrammet viser BPMN-definisjonen:

Diagram over BPMN-definisjonen med to eksklusive gateways
Diagram over BPMN-definisjonen

Skrive og registrere tilpasset kode for gatewayen

For at systemet skal velge riktig sekvensflyt ut av den eksklusive gatewayen basert på instansdata, må du opprette en klasse som implementerer Altinn.App.Core.Features.IProcessExclusiveGateway. Du må også registrere klassen som en tjeneste i avhengighetsinjeksjonen.

Grensesnittet har en strengegenskap GatewayId og en metode FilterAsync.

Du bruker GatewayId til å identifisere gatewayen i prosessdefinisjonen den er tilknyttet.

I eksempelet setter du GatewayId til Gateway_1 for den første gatewayen, fordi det er verdien i attributtet id på den eksklusive gatewayen i prosessdefinisjonen.

I metoden FilterAsync skriver du den tilpassede logikken som filtrerer sekvensflytene ut av gatewayen, basert på instansdataene.

Du finner mer om grensesnittet i XML-dokumentasjonen:

https://github.com/Altinn/app-lib-dotnet/blob/main/src/Altinn.App.Core/Features/IProcessExclusiveGateway.cs

Når du har skrevet den tilpassede koden, registrerer du den i Program.cs, i metoden RegisterCustomAppServices.

Eksempel:

App/Program.cs
void RegisterCustomAppServices(
    IServiceCollection services, 
    IConfiguration config, 
    IWebHostEnvironment env)
{
    services.AddTransient<IProcessExclusiveGateway, GatewayOne>();
}