Uitvoerbindingen van Azure Data Explorer voor Azure Functions (preview)

Wanneer een functie wordt uitgevoerd, neemt de Uitvoerbinding van Azure Data Explorer gegevens op in Azure Data Explorer.

Zie het overzicht voor informatie over het instellen en configureren van details.

Voorbeelden

U kunt een C#-functie maken met behulp van een van de volgende C#-modi:

  • Geïsoleerd werkrolmodel: gecompileerde C#-functie die wordt uitgevoerd in een werkproces dat is geïsoleerd van de runtime. Geïsoleerd werkproces is vereist voor de ondersteuning van C#-functies die worden uitgevoerd op LTS- en niet-LTS-versies .NET en .NET Framework.
  • In-process model: gecompileerde C#-functie die wordt uitgevoerd in hetzelfde proces als de Functions-runtime.
  • C#-script: wordt voornamelijk gebruikt wanneer u C#-functies maakt in Azure Portal.

Meer voorbeelden voor de Azure Data Explorer-uitvoerbinding zijn beschikbaar in de GitHub-opslagplaats.

Deze sectie bevat de volgende voorbeelden:

De voorbeelden verwijzen naar Product klasse en een bijbehorende databasetabel:

public class Product
{
    [JsonProperty(nameof(ProductID))]
    public long ProductID { get; set; }

    [JsonProperty(nameof(Name))]
    public string Name { get; set; }

    [JsonProperty(nameof(Cost))]
    public double Cost { get; set; }
}
.create-merge table Products (ProductID:long, Name:string, Cost:double)

HTTP-trigger, één record schrijven

In het volgende voorbeeld ziet u een C#-functie waarmee een record aan een database wordt toegevoegd. De functie gebruikt gegevens in een HTTP POST-aanvraag als een JSON-hoofdtekst.

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Extensions.Kusto;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Azure.WebJobs.Extensions.Kusto.SamplesOutOfProc.OutputBindingSamples.Common;

namespace Microsoft.Azure.WebJobs.Extensions.Kusto.SamplesOutOfProc.OutputBindingSamples
{
    public static class AddProduct
    {
        [Function("AddProduct")]
        [KustoOutput(Database: "productsdb", Connection = "KustoConnectionString", TableName = "Products")]
        public static async Task<Product> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "addproductuni")]
            HttpRequestData req)
        {
            Product? prod = await req.ReadFromJsonAsync<Product>();
            return prod ?? new Product { };
        }
    }
}

HTTP-trigger, records schrijven met toewijzing

In het volgende voorbeeld ziet u een C#-functie waarmee een verzameling records aan een database wordt toegevoegd. De functie maakt gebruik van toewijzing waarmee een Product naar Item.

Als u gegevens van Product naar wilt Itemtransformeren, gebruikt de functie een toewijzingsreferentie:

.create-merge table Item (ItemID:long, ItemName:string, ItemCost:float)


-- Create a mapping that transforms an Item to a Product

.create-or-alter table Product ingestion json mapping "item_to_product_json" '[{"column":"ProductID","path":"$.ItemID"},{"column":"Name","path":"$.ItemName"},{"column":"Cost","path":"$.ItemCost"}]'
namespace Microsoft.Azure.WebJobs.Extensions.Kusto.SamplesOutOfProc.OutputBindingSamples.Common
{
    public class Item
    {
        public long ItemID { get; set; }

        public string? ItemName { get; set; }

        public double ItemCost { get; set; }
    }
}
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Extensions.Kusto;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Azure.WebJobs.Extensions.Kusto.SamplesOutOfProc.OutputBindingSamples.Common;

namespace Microsoft.Azure.WebJobs.Extensions.Kusto.SamplesOutOfProc.OutputBindingSamples
{
    public static class AddProductsWithMapping
    {
        [Function("AddProductsWithMapping")]
        [KustoOutput(Database: "productsdb", Connection = "KustoConnectionString", TableName = "Products", MappingRef = "item_to_product_json")]
        public static async Task<Item> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "addproductswithmapping")]
            HttpRequestData req)
        {
            Item? item = await req.ReadFromJsonAsync<Item>();
            return item ?? new Item { };
        }
    }
}

Meer voorbeelden voor de Java Azure Data Explorer-invoerbinding zijn beschikbaar in de GitHub-opslagplaats.

Deze sectie bevat de volgende voorbeelden:

De voorbeelden verwijzen naar een Products klasse (in een afzonderlijk bestand Product.java) en een bijbehorende databasetabel Products (eerder gedefinieerd):

package com.microsoft.azure.kusto.common;

import com.fasterxml.jackson.annotation.JsonProperty;

public class Product {
    @JsonProperty("ProductID")
    public long ProductID;
    @JsonProperty("Name")
    public String Name;
    @JsonProperty("Cost")
    public double Cost;

    public Product() {
    }

    public Product(long ProductID, String name, double Cost) {
        this.ProductID = ProductID;
        this.Name = name;
        this.Cost = Cost;
    }
}

HTTP-trigger, een record naar een tabel schrijven

In het volgende voorbeeld ziet u een Azure Data Explorer-uitvoerbinding in een Java-functie waarmee een productrecord aan een tabel wordt toegevoegd. De functie gebruikt gegevens in een HTTP POST-aanvraag als een JSON-hoofdtekst. De functie heeft een andere afhankelijkheid van de com.fasterxml.jackson.core-bibliotheek om de JSON-hoofdtekst te parseren.

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.4.1</version>
</dependency>
package com.microsoft.azure.kusto.outputbindings;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.OutputBinding;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;
import com.microsoft.azure.functions.kusto.annotation.KustoOutput;
import com.microsoft.azure.kusto.common.Product;

import java.io.IOException;
import java.util.Optional;

import static com.microsoft.azure.kusto.common.Constants.*;

public class AddProduct {
    @FunctionName("AddProduct")
    public HttpResponseMessage run(@HttpTrigger(name = "req", methods = {
            HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS, route = "addproductuni") HttpRequestMessage<Optional<String>> request,
            @KustoOutput(name = "product", database = "productsdb", tableName = "Products", connection = KUSTOCONNSTR) OutputBinding<Product> product)
            throws IOException {

        if (request.getBody().isPresent()) {
            String json = request.getBody().get();
            ObjectMapper mapper = new ObjectMapper();
            Product p = mapper.readValue(json, Product.class);
            product.setValue(p);
            return request.createResponseBuilder(HttpStatus.OK).header("Content-Type", "application/json").body(product)
                    .build();
        } else {
            return request.createResponseBuilder(HttpStatus.NO_CONTENT).header("Content-Type", "application/json")
                    .build();
        }
    }
}

HTTP-trigger, schrijven naar twee tabellen

In het volgende voorbeeld ziet u een Azure Data Explorer-uitvoerbinding in een Java-functie die records toevoegt aan een database in twee verschillende tabellen (Product en ProductChangeLog). De functie gebruikt gegevens in een HTTP POST-aanvraag als een JSON-hoofdtekst en meerdere uitvoerbindingen. De functie heeft een andere afhankelijkheid van de com.fasterxml.jackson.core-bibliotheek om de JSON-hoofdtekst te parseren.

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.4.1</version>
</dependency>

De tweede tabel, ProductsChangeLogkomt overeen met de volgende definitie:

.create-merge table ProductsChangeLog (ProductID:long, CreatedAt:datetime)

en Java-klasse in ProductsChangeLog.java:

package com.microsoft.azure.kusto.common;

import com.fasterxml.jackson.annotation.JsonProperty;

public class ProductsChangeLog {
    @JsonProperty("ProductID")
    public long ProductID;
    @JsonProperty("CreatedAt")
    public String CreatedAt;

    public ProductsChangeLog() {
    }

    public ProductsChangeLog(long ProductID, String CreatedAt) {
        this.ProductID = ProductID;
        this.CreatedAt = CreatedAt;
    }
}
package com.microsoft.azure.kusto.outputbindings;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.OutputBinding;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;
import com.microsoft.azure.functions.kusto.annotation.KustoOutput;
import com.microsoft.azure.kusto.common.Product;
import com.microsoft.azure.kusto.common.ProductsChangeLog;

import static com.microsoft.azure.kusto.common.Constants.*;

import java.io.IOException;
import java.time.Clock;
import java.time.Instant;
import java.util.Optional;

public class AddMultiTable {
    @FunctionName("AddMultiTable")
    public HttpResponseMessage run(@HttpTrigger(name = "req", methods = {
            HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS, route = "addmultitable") HttpRequestMessage<Optional<String>> request,
            @KustoOutput(name = "product", database = "productsdb", tableName = "Products", connection = KUSTOCONNSTR) OutputBinding<Product> product,
            @KustoOutput(name = "productChangeLog", database = "productsdb", tableName = "ProductsChangeLog",
                    connection = KUSTOCONNSTR) OutputBinding<ProductsChangeLog> productChangeLog)
            throws IOException {

        if (request.getBody().isPresent()) {
            String json = request.getBody().get();
            ObjectMapper mapper = new ObjectMapper();
            Product p = mapper.readValue(json, Product.class);
            product.setValue(p);
            productChangeLog.setValue(new ProductsChangeLog(p.ProductID, Instant.now(Clock.systemUTC()).toString()));
            return request.createResponseBuilder(HttpStatus.OK).header("Content-Type", "application/json").body(product)
                    .build();
        } else {
            return request.createResponseBuilder(HttpStatus.NO_CONTENT).header("Content-Type", "application/json")
                    .build();
        }
    }
}

Meer voorbeelden voor de Azure Data Explorer-uitvoerbinding zijn beschikbaar in de GitHub-opslagplaats.

Deze sectie bevat de volgende voorbeelden:

De voorbeelden verwijzen naar een databasetabel.

De voorbeelden verwijzen naar de tabellen Products en ProductsChangeLog (eerder gedefinieerd).

HTTP-trigger, records schrijven naar een tabel

In het volgende voorbeeld ziet u een Azure Data Explorer-uitvoerbinding in een function.json-bestand en een JavaScript-functie waarmee records aan een tabel worden toegevoegd. De functie gebruikt gegevens in een HTTP POST-aanvraag als een JSON-hoofdtekst.

Het volgende voorbeeld bestaat uit bindingsgegevens in het function.json-bestand :

{
  "bindings": [
    {
      "authLevel": "function",
      "name": "req",
      "direction": "in",
      "type": "httpTrigger",
      "methods": [
        "post"
      ],
      "route": "addproduct"
    },
    {
      "name": "$return",
      "type": "http",
      "direction": "out"
    },
    {
      "name": "product",
      "type": "kusto",
      "database": "productsdb",
      "direction": "out",
      "tableName": "Products",
      "connection": "KustoConnectionString"
    }
  ],
  "disabled": false
}

In de configuratiesectie worden deze eigenschappen uitgelegd.

Het volgende codefragment is een voorbeeld van JavaScript-code:

// Insert the product, which will insert it into the Products table.
module.exports = async function (context, req) {
    // Note that this expects the body to be a JSON object or array of objects which have a property
    // matching each of the columns in the table to insert to.
    context.bindings.product = req.body;
    return {
        status: 201,
        body: req.body
    };
}

HTTP-trigger, schrijven naar twee tabellen

In het volgende voorbeeld ziet u een Azure Data Explorer-uitvoerbinding in een function.json-bestand en een JavaScript-functie waarmee records worden toegevoegd aan een database in twee verschillende tabellen (Products en ProductsChangeLog). De functie gebruikt gegevens in een HTTP POST-aanvraag als een JSON-hoofdtekst en meerdere uitvoerbindingen.

De tweede tabel, ProductsChangeLogkomt overeen met de volgende definitie:

.create-merge table ProductsChangeLog (ProductID:long, CreatedAt:datetime)

Het volgende codefragment bevat bindingsgegevens in het bestand function.json :

{
  "bindings": [
    {
      "authLevel": "function",
      "name": "req",
      "direction": "in",
      "type": "httpTrigger",
      "methods": [
        "post"
      ],
      "route": "addmultitable"
    },
    {
      "name": "res",
      "type": "http",
      "direction": "out"
    },
    {
      "name": "product",
      "type": "kusto",
      "database": "productsdb",
      "direction": "out",
      "tableName": "Products",
      "connection": "KustoConnectionString"
    },
    {
      "name": "productchangelog",
      "type": "kusto",
      "database": "productsdb",
      "direction": "out",
      "tableName": "ProductsChangeLog",
      "connection": "KustoConnectionString"
    }
  ],
  "disabled": false
}

In de configuratiesectie worden deze eigenschappen uitgelegd.

Het volgende codefragment is een voorbeeld van JavaScript-code:

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger and Kusto output binding function processed a request.');
    context.log(req.body);

    if (req.body) {
        var changeLog = {ProductID:req.body.ProductID, CreatedAt: new Date().toISOString()};
        context.bindings.product = req.body;
        context.bindings.productchangelog = changeLog;
        context.res = {
            body: req.body,
            mimetype: "application/json",
            status: 201
        }
    } else {
        context.res = {
            status: 400,
            body: "Error reading request body"
        }
    }
}

Meer voorbeelden voor de Azure Data Explorer-uitvoerbinding zijn beschikbaar in de GitHub-opslagplaats.

Deze sectie bevat de volgende voorbeelden:

De voorbeelden verwijzen naar de tabellen Products en ProductsChangeLog (eerder gedefinieerd).

HTTP-trigger, records schrijven naar een tabel

In het volgende voorbeeld ziet u een Azure Data Explorer-uitvoerbinding in een function.json-bestand en een Python-functie waarmee records aan een tabel worden toegevoegd. De functie gebruikt gegevens in een HTTP POST-aanvraag als een JSON-hoofdtekst.

Het volgende codefragment bevat bindingsgegevens in het bestand function.json :

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "Anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "post"
      ],
      "route": "addproductuni"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    },
    {
      "name": "product",
      "type": "kusto",
      "database": "sdktestsdb",
      "direction": "out",
      "tableName": "Products",
      "connection": "KustoConnectionString"
    }
  ]
}

In de configuratiesectie worden deze eigenschappen uitgelegd.

Het volgende codefragment is python-voorbeeldcode:

import azure.functions as func
from Common.product import Product


def main(req: func.HttpRequest, product: func.Out[str]) -> func.HttpResponse:
    body = str(req.get_body(),'UTF-8')
    product.set(body)
    return func.HttpResponse(
        body=body,
        status_code=201,
        mimetype="application/json"
    )

HTTP-trigger, schrijven naar twee tabellen

In het volgende voorbeeld ziet u een Azure Data Explorer-uitvoerbinding in een function.json-bestand en een JavaScript-functie waarmee records worden toegevoegd aan een database in twee verschillende tabellen (Products en ProductsChangeLog). De functie gebruikt gegevens in een HTTP POST-aanvraag als een JSON-hoofdtekst en meerdere uitvoerbindingen. De tweede tabel, ProductsChangeLogkomt overeen met de volgende definitie:

.create-merge table ProductsChangeLog (ProductID:long, CreatedAt:datetime)

Het volgende codefragment bevat bindingsgegevens in het bestand function.json :

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "Anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "post"
      ],
      "route": "addmultitable"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    },
    {
      "name": "product",
      "type": "kusto",
      "database": "sdktestsdb",
      "direction": "out",
      "tableName": "Products",
      "connection": "KustoConnectionString"
    },
    {
      "name": "productchangelog",
      "type": "kusto",
      "database": "sdktestsdb",
      "direction": "out",
      "tableName": "ProductsChangeLog",
      "connection": "KustoConnectionString"
    }
  ]
}

In de configuratiesectie worden deze eigenschappen uitgelegd.

Het volgende codefragment is python-voorbeeldcode:

import json
from datetime import datetime

import azure.functions as func
from Common.product import Product


def main(req: func.HttpRequest, product: func.Out[str],productchangelog: func.Out[str]) -> func.HttpResponse:
    body = str(req.get_body(),'UTF-8')
    # parse x:
    product.set(body)
    id = json.loads(body)["ProductID"]

    changelog = {
        "ProductID": id,
        "CreatedAt": datetime.now().isoformat(),
    }
    productchangelog.set(json.dumps(changelog))
    return func.HttpResponse(
        body=body,
        status_code=201,
        mimetype="application/json"
    )

Kenmerken

De C#-bibliotheek maakt gebruik van het KustoAttribute-kenmerk om de Azure Data Explorer-bindingen op de functie te declareren, die de volgende eigenschappen heeft.

Kenmerkeigenschap Beschrijving
Database Vereist. De database waarmee de query moet worden uitgevoerd.
Connection Vereist. De naam van de variabele die de verbindingsreeks bevat, die wordt omgezet via omgevingsvariabelen of via de instellingen van de functie-app. Standaard wordt gezocht naar de variabele KustoConnectionString. Tijdens runtime wordt deze variabele opgezoekd op basis van de omgeving. Documentatie over het verbindingsreeks vindt u in Kusto verbindingsreeks s. Voorbeeld: "KustoConnectionString": "Data Source=https://your_cluster.kusto.windows.net;Database=your_Database;Fed=True;AppClientId=your_AppId;AppKey=your_AppKey;Authority Id=your_TenantId.
TableName Vereist. De tabel waarin de gegevens moeten worden opgenomen.
MappingRef Optioneel. Kenmerk om een toewijzingsverwijzing door te geven die al is gedefinieerd in het cluster.
ManagedServiceIdentity Optioneel. Een beheerde identiteit kan worden gebruikt om verbinding te maken met Azure Data Explorer. Als u een door het systeem beheerde identiteit wilt gebruiken, gebruikt u 'systeem'. Alle andere identiteitsnamen worden geïnterpreteerd als een door de gebruiker beheerde identiteit.
DataFormat Optioneel. De standaardgegevensindeling is multijson/json. Deze kan worden ingesteld op tekstindelingen die worden ondersteund in de opsomming van de datasource indeling. Voorbeelden worden gevalideerd en verstrekt voor CSV- en JSON-indelingen.

Aantekeningen

De Runtime-bibliotheek van Java-functies maakt gebruik van de @KustoInput aantekening (com.microsoft.azure.functions.kusto.annotation.KustoOutput).

Element Description
naam Vereist. De naam van de variabele die de query vertegenwoordigt, resulteert in functiecode.
database Vereist. De database waarmee de query moet worden uitgevoerd.
verbinding Vereist. De naam van de variabele die de verbindingsreeks bevat, die wordt omgezet via omgevingsvariabelen of via de instellingen van de functie-app. Standaard wordt gezocht naar de variabele KustoConnectionString. Tijdens runtime wordt deze variabele opgezoekd op basis van de omgeving. Documentatie over het verbindingsreeks vindt u in Kusto verbindingsreeks s. Voorbeeld: "KustoConnectionString": "Data Source=https://your_cluster.kusto.windows.net;Database=your_Database;Fed=True;AppClientId=your_AppId;AppKey=your_AppKey;Authority Id=your_TenantId.
tableName Vereist. De tabel waarin de gegevens moeten worden opgenomen.
mappingRef Optioneel. Kenmerk om een toewijzingsverwijzing door te geven die al is gedefinieerd in het cluster.
dataFormat Optioneel. De standaardgegevensindeling is multijson/json. Deze kan worden ingesteld op tekstindelingen die worden ondersteund in de opsomming van de datasource indeling. Voorbeelden worden gevalideerd en verstrekt voor CSV- en JSON-indelingen.
managedServiceIdentity Een beheerde identiteit kan worden gebruikt om verbinding te maken met Azure Data Explorer. Als u een door het systeem beheerde identiteit wilt gebruiken, gebruikt u 'systeem'. Alle andere identiteitsnamen worden geïnterpreteerd als een door de gebruiker beheerde identiteit.

Configuratie

In de volgende tabel worden de bindingsconfiguratie-eigenschappen uitgelegd die u in het function.json-bestand hebt ingesteld.

function.json-eigenschap Beschrijving
type Vereist. Moet worden ingesteld op kusto.
richting Vereist. Moet worden ingesteld op out.
naam Vereist. De naam van de variabele die de query vertegenwoordigt, resulteert in functiecode.
database Vereist. De database waarmee de query moet worden uitgevoerd.
verbinding Vereist. De naam van de variabele met de verbindingsreeks, omgezet via omgevingsvariabelen of via instellingen van de functie-app. Standaard wordt gezocht naar de variabele KustoConnectionString. Tijdens runtime wordt deze variabele opgezoekd op basis van de omgeving. Documentatie over het verbindingsreeks vindt u in Kusto verbindingsreeks s. Voorbeeld: "KustoConnectionString": "Data Source=https://your_cluster.kusto.windows.net;Database=your_Database;Fed=True;AppClientId=your_AppId;AppKey=your_AppKey;Authority Id=your_TenantId.
tableName Vereist. De tabel waarin de gegevens moeten worden opgenomen.
mappingRef Optioneel. Kenmerk om een toewijzingsverwijzing door te geven die al is gedefinieerd in het cluster.
dataFormat Optioneel. De standaardgegevensindeling is multijson/json. Deze kan worden ingesteld op tekstindelingen die worden ondersteund in de opsomming van de datasource indeling. Voorbeelden worden gevalideerd en verstrekt voor CSV- en JSON-indelingen.
managedServiceIdentity Een beheerde identiteit kan worden gebruikt om verbinding te maken met Azure Data Explorer. Als u een door het systeem beheerde identiteit wilt gebruiken, gebruikt u 'systeem'. Alle andere identiteitsnamen worden geïnterpreteerd als een door de gebruiker beheerde identiteit.

Wanneer u lokaal ontwikkelt, voegt u uw toepassingsinstellingen toe aan het local.settings.json-bestand in de Values verzameling.

Gebruik

De constructor van het kenmerk neemt de database en de kenmerken TableName, MappingRefen DataFormat de naam van de verbindingsinstelling. De KQL-opdracht kan een KQL-instructie of een KQL-functie zijn. De naam van de verbindingsreeks-instelling komt overeen met de toepassingsinstelling (voor local.settings.json lokale ontwikkeling) die de Kusto-verbindingsreeks s bevat. Bijvoorbeeld:"KustoConnectionString": "Data Source=https://your_cluster.kusto.windows.net;Database=your_Database;Fed=True;AppClientId=your_AppId;AppKey=your_AppKey;Authority Id=your_TenantId Query's die door de invoerbinding worden uitgevoerd, worden geparameteriseerd. De waarden die in de KQL-parameters worden opgegeven, worden tijdens runtime gebruikt.

Volgende stappen

Gegevens uit een tabel lezen (invoerbinding)