dokumentacja dla deweloperów skryptu języka C# (csx) Azure Functions

Ten artykuł stanowi wprowadzenie do opracowywania Azure Functions przy użyciu skryptu języka C# (csx).

Azure Functions obsługuje języki programowania skryptów C# i C#. Jeśli szukasz wskazówek dotyczących korzystania z języka C# w projekcie biblioteki klas Visual Studio, zobacz Dokumentację dla deweloperów języka C#.

W tym artykule założono, że znasz już przewodnik dla deweloperów Azure Functions.

Jak działa plik csx

Środowisko skryptu języka C# dla Azure Functions jest oparte na zestawie SDK usługi Azure WebJobs. Dane przepływają do funkcji języka C# za pośrednictwem argumentów metody. Nazwy argumentów są określane w function.json pliku i istnieją wstępnie zdefiniowane nazwy na potrzeby uzyskiwania dostępu do elementów, takich jak rejestrator funkcji i tokeny anulowania.

Format csx umożliwia pisanie mniej "standardowy" i skupienie się na pisaniu tylko funkcji języka C#. Zamiast zawijać wszystko w przestrzeni nazw i klasie, po prostu zdefiniuj metodę Run . Dołącz wszystkie odwołania do zestawów i przestrzenie nazw na początku pliku w zwykły sposób.

Pliki csx aplikacji funkcji są kompilowane po zainicjowaniu wystąpienia. Ten krok kompilacji oznacza, że działania, takie jak zimny start, mogą trwać dłużej w przypadku funkcji skryptów języka C# w porównaniu z bibliotekami klas języka C#. Ten krok kompilacji jest również przyczyną edytowania funkcji skryptów języka C# w Azure Portal, podczas gdy biblioteki klas języka C#nie są.

Struktura folderów

Struktura folderów dla projektu skryptu języka C# wygląda następująco:

FunctionsProject
 | - MyFirstFunction
 | | - run.csx
 | | - function.json
 | | - function.proj
 | - MySecondFunction
 | | - run.csx
 | | - function.json
 | | - function.proj
 | - host.json
 | - extensions.csproj
 | - bin

Istnieje udostępniony plik host.json , który może służyć do konfigurowania aplikacji funkcji. Każda funkcja ma własny plik kodu (csx) i plik konfiguracji powiązania (function.json).

Rozszerzenia powiązań wymagane w wersji 2.x i nowszych wersjach środowiska uruchomieniowego usługi Functions są definiowane w extensions.csproj pliku z rzeczywistymi plikami biblioteki w folderze bin . Podczas tworzenia aplikacji lokalnie należy zarejestrować rozszerzenia powiązań. Podczas opracowywania funkcji w Azure Portal ta rejestracja jest wykonywana za Ciebie.

Wiązanie z argumentami

Dane wejściowe lub wyjściowe są powiązane z parametrem funkcji skryptu języka C# za pośrednictwem name właściwości w pliku konfiguracji function.json . W poniższym przykładzie pokazano plik function.json i plik run.csx dla funkcji wyzwalanej przez kolejkę. Parametr odbierający dane z komunikatu kolejki ma nazwę myQueueItem , ponieważ jest to wartość name właściwości.

{
    "disabled": false,
    "bindings": [
        {
            "type": "queueTrigger",
            "direction": "in",
            "name": "myQueueItem",
            "queueName": "myqueue-items",
            "connection":"MyStorageConnectionAppSetting"
        }
    ]
}
#r "Microsoft.WindowsAzure.Storage"

using Microsoft.Extensions.Logging;
using Microsoft.WindowsAzure.Storage.Queue;
using System;

public static void Run(CloudQueueMessage myQueueItem, ILogger log)
{
    log.LogInformation($"C# Queue trigger function processed: {myQueueItem.AsString}");
}

Instrukcja #r zostanie wyjaśniona w dalszej części tego artykułu.

Obsługiwane typy powiązań

Każde powiązanie ma własne obsługiwane typy; na przykład wyzwalacz obiektu blob może być używany z parametrem ciągu, parametrem POCO, parametrem CloudBlockBlob lub dowolnym z kilku innych obsługiwanych typów. Artykuł referencyjny dotyczący powiązań obiektów blob zawiera listę wszystkich obsługiwanych typów parametrów dla wyzwalaczy obiektów blob. Aby uzyskać więcej informacji, zobacz Wyzwalacze i powiązania oraz dokumentację referencyjną powiązań dla każdego typu powiązania.

Porada

Jeśli planujesz używać powiązań HTTP lub webhook, zaplanuj uniknięcie wyczerpania portów, które mogą być spowodowane przez niewłaściwe utworzenie wystąpienia elementu HttpClient. Aby uzyskać więcej informacji, zobacz Jak zarządzać połączeniami w Azure Functions.

Odwoływanie się do klas niestandardowych

Jeśli musisz użyć niestandardowej klasy zwykłych starych obiektów CLR (POCO), możesz dołączyć definicję klasy do tego samego pliku lub umieścić ją w osobnym pliku.

Poniższy przykład przedstawia przykład run.csx , który zawiera definicję klasy POCO.

public static void Run(string myBlob, out MyClass myQueueItem)
{
    log.Verbose($"C# Blob trigger function processed: {myBlob}");
    myQueueItem = new MyClass() { Id = "myid" };
}

public class MyClass
{
    public string Id { get; set; }
}

Klasa POCO musi mieć element pobierający i ustawiany zdefiniowany dla każdej właściwości.

Ponowne tworzenie kodu csx

W pliku run.csx można używać klas i metod zdefiniowanych w innych plikach csx. W tym celu należy użyć #load dyrektyw w pliku run.csx . W poniższym przykładzie procedura rejestrowania o nazwie MyLogger jest udostępniana w pliku myLogger.csx i ładowana do pliku run.csx przy użyciu #load dyrektywy :

Przykład run.csx:

#load "mylogger.csx"

using Microsoft.Extensions.Logging;

public static void Run(TimerInfo myTimer, ILogger log)
{
    log.LogInformation($"Log by run.csx: {DateTime.Now}");
    MyLogger(log, $"Log by MyLogger: {DateTime.Now}");
}

Przykład mylogger.csx:

public static void MyLogger(ILogger log, string logtext)
{
    log.LogInformation(logtext);
}

Użycie udostępnionego pliku csx jest typowym wzorcem, gdy chcesz silnie wpisywać dane przekazywane między funkcjami przy użyciu obiektu POCO. W poniższym uproszczonym przykładzie wyzwalacz HTTP i kolejka wyzwalacz współużytkuje obiekt POCO o nazwie Order , aby silnie wpisać dane zamówienia:

Przykład run.csx dla wyzwalacza HTTP:

#load "..\shared\order.csx"

using System.Net;
using Microsoft.Extensions.Logging;

public static async Task<HttpResponseMessage> Run(Order req, IAsyncCollector<Order> outputQueueItem, ILogger log)
{
    log.LogInformation("C# HTTP trigger function received an order.");
    log.LogInformation(req.ToString());
    log.LogInformation("Submitting to processing queue.");

    if (req.orderId == null)
    {
        return new HttpResponseMessage(HttpStatusCode.BadRequest);
    }
    else
    {
        await outputQueueItem.AddAsync(req);
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
}

Przykładowy wyzwalacz run.csx dla kolejki:

#load "..\shared\order.csx"

using System;
using Microsoft.Extensions.Logging;

public static void Run(Order myQueueItem, out Order outputQueueItem, ILogger log)
{
    log.LogInformation($"C# Queue trigger function processed order...");
    log.LogInformation(myQueueItem.ToString());

    outputQueueItem = myQueueItem;
}

Przykład order.csx:

public class Order
{
    public string orderId {get; set; }
    public string custName {get; set;}
    public string custAddress {get; set;}
    public string custEmail {get; set;}
    public string cartId {get; set; }

    public override String ToString()
    {
        return "\n{\n\torderId : " + orderId +
                  "\n\tcustName : " + custName +
                  "\n\tcustAddress : " + custAddress +
                  "\n\tcustEmail : " + custEmail +
                  "\n\tcartId : " + cartId + "\n}";
    }
}

Możesz użyć ścieżki względnej z dyrektywą #load :

  • #load "mylogger.csx" ładuje plik znajdujący się w folderze funkcji.
  • #load "loadedfiles\mylogger.csx" ładuje plik znajdujący się w folderze funkcji.
  • #load "..\shared\mylogger.csx" ładuje plik znajdujący się w folderze na tym samym poziomie co folder funkcji, czyli bezpośrednio pod katalogiem wwwroot.

Dyrektywa #load działa tylko z plikami csx , a nie plikami cs .

Powiązanie z wartością zwracaną przez metodę

Możesz użyć wartości zwracanej metody dla powiązania wyjściowego, używając nazwy $return w pliku function.json. Aby zapoznać się z przykładami, zobacz Wyzwalacze i powiązania.

Użyj wartości zwracanej tylko wtedy, gdy pomyślne wykonanie funkcji zawsze powoduje zwrócenie wartości do przekazania do powiązania wyjściowego. W przeciwnym razie użyj polecenia ICollector lub IAsyncCollector, jak pokazano w poniższej sekcji.

Pisanie wielu wartości wyjściowych

Aby zapisać wiele wartości do powiązania wyjściowego lub jeśli pomyślne wywołanie funkcji może nie spowodować przekazania niczego do powiązania wyjściowego, użyj ICollector typów lub IAsyncCollector . Te typy to kolekcje tylko do zapisu, które są zapisywane w powiązaniu wyjściowym po zakończeniu działania metody.

W tym przykładzie wiele komunikatów w kolejce jest zapisywanych w tej samej kolejce przy użyciu polecenia ICollector:

public static void Run(ICollector<string> myQueue, ILogger log)
{
    myQueue.Add("Hello");
    myQueue.Add("World!");
}

Rejestrowanie

Aby zarejestrować dane wyjściowe w dziennikach przesyłania strumieniowego w języku C#, dołącz argument typu ILogger. Zalecamy nadanie mu lognazwy . Unikaj używania Console.Write w Azure Functions.

public static void Run(string myBlob, ILogger log)
{
    log.LogInformation($"C# Blob trigger function processed: {myBlob}");
}

Uwaga

Aby uzyskać informacje na temat nowszej struktury rejestrowania, której można użyć zamiast TraceWriterprogramu , zobacz dokumentację ILogger w przewodniku dewelopera biblioteki klas platformy .NET.

Rejestrowanie metryk niestandardowych

Możesz użyć LogMetric metody rozszerzenia , ILogger aby utworzyć metryki niestandardowe w usłudze Application Szczegółowe informacje. Oto przykładowe wywołanie metody:

logger.LogMetric("TestMetric", 1234);

Ten kod jest alternatywą dla wywoływania TrackMetric przy użyciu interfejsu API Szczegółowe informacje aplikacji dla platformy .NET.

Async

Aby utworzyć funkcję asynchroniczną, użyj słowa kluczowego async i zwróć Task obiekt.

public async static Task ProcessQueueMessageAsync(
        string blobName,
        Stream blobInput,
        Stream blobOutput)
{
    await blobInput.CopyToAsync(blobOutput, 4096);
}

Nie można używać out parametrów w funkcjach asynchronicznych. W przypadku powiązań wyjściowych należy zamiast tego użyć wartości zwracanej przez funkcję lub obiektu modułu zbierającego .

Tokeny anulowania

Funkcja może akceptować parametr CancellationToken , który umożliwia systemowi operacyjnemu powiadamianie kodu o zakończeniu działania funkcji. Możesz użyć tego powiadomienia, aby upewnić się, że funkcja nie zostanie nieoczekiwanie zakończona w sposób, który pozostawia dane w stanie niespójnym.

W poniższym przykładzie pokazano, jak sprawdzić zbliżające się zakończenie funkcji.

using System;
using System.IO;
using System.Threading;

public static void Run(
    string inputText,
    TextWriter logger,
    CancellationToken token)
{
    for (int i = 0; i < 100; i++)
    {
        if (token.IsCancellationRequested)
        {
            logger.WriteLine("Function was cancelled at iteration {0}", i);
            break;
        }
        Thread.Sleep(5000);
        logger.WriteLine("Normal processing for queue message={0}", inputText);
    }
}

Importowanie przestrzeni nazw

Jeśli musisz zaimportować przestrzenie nazw, możesz to zrobić w zwykły sposób, z klauzulą using .

using System.Net;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

public static Task<HttpResponseMessage> Run(HttpRequestMessage req, ILogger log)

Następujące przestrzenie nazw są importowane automatycznie i dlatego są opcjonalne:

  • System
  • System.Collections.Generic
  • System.IO
  • System.Linq
  • System.Net.Http
  • System.Threading.Tasks
  • Microsoft.Azure.WebJobs
  • Microsoft.Azure.WebJobs.Host

Odwoływanie się do zestawów zewnętrznych

W przypadku zestawów struktury dodaj odwołania przy użyciu #r "AssemblyName" dyrektywy .

#r "System.Web.Http"

using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

public static Task<HttpResponseMessage> Run(HttpRequestMessage req, ILogger log)

Następujące zestawy są automatycznie dodawane przez środowisko hostingu Azure Functions:

  • mscorlib
  • System
  • System.Core
  • System.Xml
  • System.Net.Http
  • Microsoft.Azure.WebJobs
  • Microsoft.Azure.WebJobs.Host
  • Microsoft.Azure.WebJobs.Extensions
  • System.Web.Http
  • System.Net.Http.Formatting

Następujące zestawy mogą odwoływać się do prostych nazw (na przykład #r "AssemblyName"):

  • Newtonsoft.Json
  • Microsoft.WindowsAzure.Storage
  • Microsoft.ServiceBus
  • Microsoft.AspNet.WebHooks.Receivers
  • Microsoft.AspNet.WebHooks.Common
  • Microsoft.Azure.NotificationHubs

Odwoływanie się do zestawów niestandardowych

Aby odwołać się do zestawu niestandardowego, można użyć zestawu udostępnionego lub zestawu prywatnego :

  • Współużytkowane zestawy są współużytkowane we wszystkich funkcjach w aplikacji funkcji. Aby odwołać się do zestawu niestandardowego, przekaż zestaw do folderu o nazwie bin w folderze głównym aplikacji funkcji (wwwroot).

  • Zestawy prywatne są częścią kontekstu danej funkcji i obsługują ładowanie bezpośrednie różnych wersji. Zestawy prywatne powinny zostać przekazane w bin folderze w katalogu funkcji. Odwoływanie się do zestawów przy użyciu nazwy pliku, na przykład #r "MyAssembly.dll".

Aby uzyskać informacje na temat przekazywania plików do folderu funkcji, zobacz sekcję dotyczącą zarządzania pakietami.

Obserwowane katalogi

Katalog zawierający plik skryptu funkcji jest automatycznie obserwowany pod kątem zmian w zestawach. Aby obserwować zmiany zestawu w innych katalogach, dodaj je do watchDirectories listy w pliku host.json.

Korzystanie z pakietów NuGet

Sposób dodawania pakietów rozszerzeń powiązania i innych pakietów NuGet do aplikacji funkcji zależy od docelowej wersji środowiska uruchomieniowego usługi Functions.

Domyślnie obsługiwany zestaw rozszerzeń usługi Functions NuGet pakiety są udostępniane aplikacji funkcji skryptu języka C# przy użyciu pakietów rozszerzeń. Aby dowiedzieć się więcej, zobacz Pakiety rozszerzeń.

Jeśli z jakiegoś powodu nie możesz używać pakietów rozszerzeń w projekcie, możesz również użyć narzędzia Azure Functions Core Tools do instalowania rozszerzeń na podstawie powiązań zdefiniowanych w plikach function.json w aplikacji. W przypadku używania narzędzi Core Tools do rejestrowania rozszerzeń upewnij się, że używasz --csx opcji . Aby dowiedzieć się więcej, zobacz Instalowanie rozszerzeń.

Domyślnie narzędzia Core Tools odczytują pliki function.json i dodają wymagane pakiety do pliku projektu biblioteki klas extensions.csproj c# w katalogu głównym systemu plików aplikacji funkcji (wwwroot). Ponieważ narzędzia Core Tools używają dotnet.exe, można użyć jej do dodania dowolnego odwołania do pakietu NuGet do tego pliku rozszerzeń. Podczas instalacji narzędzia Core Tools kompilują rozszerzenies.csproj w celu zainstalowania wymaganych bibliotek. Oto przykładowy plik extensions.csproj , który dodaje odwołanie do pliku Microsoft.ProjectOxford.Facew wersji 1.1.0:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.ProjectOxford.Face" Version="1.1.0" />
    </ItemGroup>
</Project>

Aby użyć niestandardowego kanału informacyjnego NuGet, określ źródło danych w pliku Nuget.Config w folderze głównym aplikacji funkcji. Aby uzyskać więcej informacji, zobacz Konfigurowanie zachowania NuGet.

Jeśli pracujesz tylko nad projektem w portalu, musisz ręcznie utworzyć plik extensions.csproj lub plik Nuget.Config bezpośrednio w witrynie. Aby dowiedzieć się więcej, zobacz Ręczne instalowanie rozszerzeń.

Zmienne środowiskowe

Aby uzyskać zmienną środowiskową lub wartość ustawienia aplikacji, użyj polecenia System.Environment.GetEnvironmentVariable, jak pokazano w poniższym przykładzie kodu:

public static void Run(TimerInfo myTimer, ILogger log)
{
    log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
    log.LogInformation(GetEnvironmentVariable("AzureWebJobsStorage"));
    log.LogInformation(GetEnvironmentVariable("WEBSITE_SITE_NAME"));
}

public static string GetEnvironmentVariable(string name)
{
    return name + ": " +
        System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
}

Wiązanie w czasie wykonywania

W języku C# i innych językach platformy .NET można użyć wzorca powiązania imperatywnego , w przeciwieństwie do powiązań deklaratywnych w pliku function.json. Powiązanie imperatywne jest przydatne, gdy parametry powiązania muszą być obliczane w czasie wykonywania, a nie w czasie projektowania. Za pomocą tego wzorca można powiązać z obsługiwanymi powiązaniami wejściowymi i wyjściowymi na bieżąco w kodzie funkcji.

Zdefiniuj powiązanie imperatywne w następujący sposób:

  • Nie dołączaj wpisu w pliku function.json dla żądanych powiązań imperatywnych.
  • Przekaż parametr Binder binder wejściowy lub IBinder binder.
  • Użyj następującego wzorca języka C#, aby wykonać powiązanie danych.
using (var output = await binder.BindAsync<T>(new BindingTypeAttribute(...)))
{
    ...
}

BindingTypeAttribute to atrybut .NET, który definiuje powiązanie i T jest typem wejściowym lub wyjściowym obsługiwanym przez ten typ powiązania. T nie może być typem parametru out (takim jak out JObject). Na przykład powiązanie danych wyjściowych tabeli Mobile Apps obsługuje sześć typów danych wyjściowych, ale można użyć tylko funkcji ICollectorT<> lub IAsyncCollector<T> .T

Przykład pojedynczego atrybutu

Poniższy przykładowy kod tworzy powiązanie wyjściowe obiektu blob Storage ze ścieżką obiektu blob zdefiniowaną w czasie wykonywania, a następnie zapisuje ciąg w obiekcie blob.

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host.Bindings.Runtime;

public static async Task Run(string input, Binder binder)
{
    using (var writer = await binder.BindAsync<TextWriter>(new BlobAttribute("samples-output/path")))
    {
        writer.Write("Hello World!!");
    }
}

Atrybut BlobAttribute definiuje Storage powiązanie wejściowe lub wyjściowe obiektu blob, a TextWriter jest obsługiwanym typem powiązania wyjściowego.

Przykład wielu atrybutów

Powyższy przykład pobiera ustawienie aplikacji dla głównych parametrów połączenia konta aplikacji funkcji Storage (czyli AzureWebJobsStorage). Dla konta Storage można określić niestandardowe ustawienie aplikacji, dodając atrybut StorageAccountAttribute i przekazując tablicę atrybutów do BindAsync<T>()elementu . Użyj parametru Binder , a nie IBinder. Na przykład:

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host.Bindings.Runtime;

public static async Task Run(string input, Binder binder)
{
    var attributes = new Attribute[]
    {
        new BlobAttribute("samples-output/path"),
        new StorageAccountAttribute("MyStorageAccount")
    };

    using (var writer = await binder.BindAsync<TextWriter>(attributes))
    {
        writer.Write("Hello World!");
    }
}

W poniższej tabeli wymieniono atrybuty platformy .NET dla każdego typu powiązania oraz pakiety, w których są zdefiniowane.

Wiązanie Atrybut Dodawanie odwołania
Cosmos DB Microsoft.Azure.WebJobs.DocumentDBAttribute #r "Microsoft.Azure.WebJobs.Extensions.CosmosDB"
Event Hubs Microsoft.Azure.WebJobs.ServiceBus.EventHubAttribute, Microsoft.Azure.WebJobs.ServiceBusAccountAttribute #r "Microsoft.Azure.Jobs.ServiceBus"
Mobile Apps Microsoft.Azure.WebJobs.MobileTableAttribute #r "Microsoft.Azure.WebJobs.Extensions.MobileApps"
Notification Hubs Microsoft.Azure.WebJobs.NotificationHubAttribute #r "Microsoft.Azure.WebJobs.Extensions.NotificationHubs"
Service Bus Microsoft.Azure.WebJobs.ServiceBusAttribute, Microsoft.Azure.WebJobs.ServiceBusAccountAttribute #r "Microsoft.Azure.WebJobs.ServiceBus"
Kolejka magazynu Microsoft.Azure.WebJobs.QueueAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute
Magazyn obiektów blob Microsoft.Azure.WebJobs.BlobAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute
tabela Storage Microsoft.Azure.WebJobs.TableAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute
Twilio Microsoft.Azure.WebJobs.TwilioSmsAttribute #r "Microsoft.Azure.WebJobs.Extensions.Twilio"

Następne kroki