相关文章推荐

本文假定你已阅读 Azure Functions 开发人员指南

.csx 的工作原理

数据通过方法参数流入 C # 函数。 参数名称在 function.json 文件中指定,而预定义的名称则用于访问函数记录器和取消令牌等内容。

.csx 格式允许编写更少的“样本”,因此你可以集中编写 C# 函数。 只需定义 Run 方法即可,无需将所有内容都包装在命名空间和类中。 像往常一样,在文件开头包含任何程序集引用和命名空间。

初始化实例时,会编译函数应用的 .csx 文件。 此编译步骤意味着,与 C# 类库相比,冷启动之类的操作对于 C# 脚本函数来说可能需要更长的时间。 此编译步骤也说明了为何 C# 脚本函数在 Azure 门户中可以编辑,而 C# 类库则不可以编辑。

文件夹结构

C# 脚本项目的文件夹结构如下例所示:

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

存在共享的 host.json 文件,可用于配置函数应用。 每个函数都具有自己的代码文件 (.csx) 和绑定配置文件 (function.json)。

2.x 及更高版本的 Functions 运行时中所需的绑定扩展在 extensions.csproj 文件中定义,实际库文件位于 bin 文件夹中。 本地开发时,必须注册绑定扩展。 在 Azure 门户中开发函数时,系统将为你完成此注册。

绑定到参数

输入或输出数据通过 function.json 配置文件中的 name 属性绑定到 C# 脚本函数参数。 以下示例显示了一个 function.json 文件以及适用于队列触发函数的 run.csx 文件。 从队列消息接收数据的参数名为 myQueueItem,因为这是 name 属性的值。

"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}");

本文后面#r 语句做了解释。

绑定支持的类型

每个绑定都具有其自己支持的类型;例如,Blob 触发器可以与字符串参数、POCO 参数、CloudBlockBlob 参数或任何其他几种受支持类型之一配合使用。 适用于 Blob 绑定的绑定参考文章列出了适用于 Blob 触发器的所有受支持参数类型。 有关详细信息,请参阅触发器和绑定每个绑定类型的绑定参考文档

如果计划使用 HTTP 或 WebHook 绑定,请制定计划来避免因实例化 HttpClient 不当导致的端口耗尽现象。 有关详细信息,请参阅如何在 Azure Functions 中管理连接

引用自定义类

如需使用自定义的普通旧 CLR 对象 (POCO) 类,可以将类定义包括在同一文件中,也可以将其置于单独的文件中。

以下示例显示了一个 run.csx 示例,后者包括一个 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; }

POCO 类必须为每个属性定义 getter 和 setter。

重用.csx 代码

可以在 run.csx 文件中使用其他 run.csx 文件中定义的类和方法。 为此,需使用 run.csx 文件中的 #load 指令。 在下面的实例中,在 myLogger.csx 中共享了名为 MyLogger 的日志记录例程,并使用 #load 指令将其加载到 run.csx:

示例 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}");

示例 mylogger.csx

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

若要使用 POCO 对象强类型化在函数间传递的数据,常见模式是使用共享的 .csx 文件。 在下面的简化示例中,一个 HTTP 触发器和队列触发器共享名为 Order 的 POCO 对象以强类型化顺序数据:

HTTP 触发器的示例 run.csx:

#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);
        await outputQueueItem.AddAsync(req);
        return new HttpResponseMessage(HttpStatusCode.OK);

队列触发器的示例 run.csx:

#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;

示例 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}";

可以使用相对路径与 #load 指令:

  • #load "mylogger.csx" 加载函数文件夹中的文件。
  • #load "loadedfiles\mylogger.csx" 加载文件函数文件夹中的文件夹。
  • #load "..\shared\mylogger.csx" 在同一级别(即 wwwroot 的正下方)加载文件夹中的文件,使其成为函数文件夹。
  • #load 指令仅适用于 .csx 文件,不适用于 .cs 文件。

    绑定到方法返回值

    可通过在 function.json 中使用名称 $return 将方法返回值用于输出绑定。 有关示例,请参阅触发器和绑定

    仅当成功的函数执行始终将返回值传递给输出绑定时,才使用返回值。 否则,请使用 ICollectorIAsyncCollector,如以下部分所示。

    写入多个输出值

    若要将多个值写入输出绑定,或者如果成功的函数调用可能无法将任何内容传递给输出绑定,请使用 ICollectorIAsyncCollector 类型。 这些类型是只写集合,当方法完成时写入输出绑定。

    此示例使用 ICollector 将多个队列消息写入到同一队列:

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

    若要使用 C# 将输出记录到流式传输日志中,请包括 ILogger 类型的参数。 建议将其命名为 log。 避免在 Azure Functions 中使用 Console.Write

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

    有关可以代替 TraceWriter 使用的更新日志框架的信息,请参阅 .NET 类库开发人员指南中的 ILogger 文档。

    自定义指标日志记录

    可以使用 ILogger 上的 LogMetric 扩展方法来在 Application Insights 中创建自定义指标。 下面是示例方法调用:

    logger.LogMetric("TestMetric", 1234);
    

    此代码是一种替代方法,使用适用于 .NET 的 Application Insights API 调用 TrackMetric

    要使函数异步,请使用 async 关键字并返回 Task 对象。

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

    不能在异步函数中使用 out 参数。 对于输出绑定,请改用函数返回值收集器对象

    函数可以接受 CancellationToken 参数,以使操作系统能够在函数即将终止时通知代码。 可以使用此通知来确保该函数不会意外终止,导致数据处于不一致状态。

    下面的示例演示了如何检查即将发生的函数终止。

    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);
    

    导入命名空间

    如果需要导入命名空间,则可使用 using 子句,按正常情况处理。

    using System.Net;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Logging;
    public static Task<HttpResponseMessage> Run(HttpRequestMessage req, ILogger log)
    

    会自动导入以下命名空间,而且是可选的:

  • System
  • System.Collections.Generic
  • System.IO
  • System.Linq
  • System.Net.Http
  • System.Threading.Tasks
  • Microsoft.Azure.WebJobs
  • Microsoft.Azure.WebJobs.Host
  • 引用外部程序集

    对于框架程序集,通过使用 #r "AssemblyName" 指令添加引用。

    #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)
    

    由 Azure 函数主机环境自动添加以下程序集:

  • 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
  • 可按运行时版本通过简单名称引用以下程序集:

    v2.x+

    若要引用自定义程序集,可使用共享程序集或私有程序集 :

  • 共享程序集在函数应用内的所有函数中共享。 若要引用自定义程序集,请将程序集上传到函数应用根文件夹bin (wwwroot) 中名为 的文件夹。

  • 私有程序集是给定函数上下文的一部分,支持不同版本的旁加载。 私有程序集应上传到函数目录中的 bin 文件夹。 使用文件名(例如 #r "MyAssembly.dll")引用程序集。

    有关如何将文件上传到函数文件夹的信息,请参阅有关程序包管理的部分。

    监视的目录

    自动监视包含函数脚本文件的目录的程序集更改。 若要监视其他目录中的程序集更改,请将其添加到 host.json 中的 watchDirectories 列表中。

    使用 NuGet 包

    将绑定扩展包和其他 NuGet 包添加到函数应用的方式取决于 Functions 运行时的目标版本

    v2.x+

    默认情况下,通过使用扩展捆绑包将支持的一组 Functions 扩展 NuGet 包提供给 C# 脚本函数应用。 若要了解详细信息,请参阅扩展捆绑包

    如果你出于某种原因而无法在项目中使用扩展捆绑包,则还可以使用 Azure Functions Core Tools 根据应用的 function.json 文件中定义的绑定来安装扩展。 使用 Core Tools 注册扩展时,请确保使用 --csx 选项。 若要了解详细信息,请参阅安装扩展

    默认情况下,Core Tools 会读取 function.json 文件,并将所需的包添加到函数应用的文件系统根目录 (wwwroot) 中的 extensions.csproj C# 类库项目文件。 由于 Core Tools 使用 dotnet.exe,因此你可以使用它添加对此扩展文件的任何 NuGet 包引用。 在安装期间,Core Tools 会生成 extensions.csproj 以安装所需的库。 下面是 extensions.csproj 文件示例,它添加了对 Microsoft.ProjectOxford.Face 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>
    

    对于 C# 脚本 (.csx),必须将 TargetFramework 设置为值 netstandard2.0。 不支持 net6.0 等其他目标框架。

    若要使用自定义 NuGet 源,请在函数应用根文件夹中指定 Nuget.Config 文件中的源。 有关详细信息,请参阅配置 NuGet 行为

    如果仅在门户中处理项目,则需要直接在站点中手动创建 extensions.csproj 文件或 Nuget.Config 文件。 若要了解详细信息,请参阅手动安装扩展

    若要获取环境变量或应用设置值,请使用 System.Environment.GetEnvironmentVariable,如以下代码示例所示:

    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);
    

    在运行时绑定

    在 C# 和其他 .NET 语言中,可以使用命令性绑定模式,而不是 function.json 中的声明式绑定。 当绑定参数需要在运行时(而非在设计时)计算时,命令性绑定很有用。 通过此模式,可以在函数代码中动态绑定到受支持的输入和输出绑定。

    如下所示定义命令性绑定:

  • 对于所需的命令性绑定,不要包含 function.json 中的条目。
  • 传递输入参数 Binder binderIBinder binder
  • 使用下面的 C# 模式执行数据绑定。
  • using (var output = await binder.BindAsync<T>(new BindingTypeAttribute(...)))
    

    BindingTypeAttribute 是定义了绑定的 .NET 属性,T 是该绑定类型所支持的输入或输出类型。 T 不能是 out 参数类型(例如 out JObject)。 例如,移动应用表输出绑定支持 6 种输出类型,但对于 T,只能使用 ICollector<T>IAsyncCollector<T>

    单属性示例

    下面的示例代码使用在运行时定义的 blob 路径创建存储 blob 输出绑定,然后将字符串写入此 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!!");
    

    BlobAttribute 定义存储 blob 输入或输出绑定,TextWriter 是支持的输出绑定类型。

    多属性示例

    上一个示例获取函数应用的主存储帐户连接字符串(即 AzureWebJobsStorage)的应用设置。 通过添加 StorageAccountAttribute 和将属性数组传入 BindAsync<T>(),可指定要用于存储帐户的自定义应用设置。 使用一个 Binder 参数而非 IBinder。 例如:

    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!");
    

    下表列出了每种绑定类型的 .NET 属性及其定义所在的包。

    Azure Cosmos DB Microsoft.Azure.WebJobs.DocumentDBAttribute #r "Microsoft.Azure.WebJobs.Extensions.CosmosDB" Microsoft.Azure.WebJobs.ServiceBus.EventHubAttribute, Microsoft.Azure.WebJobs.ServiceBusAccountAttribute #r "Microsoft.Azure.Jobs.ServiceBus" Microsoft.Azure.WebJobs.MobileTableAttribute #r "Microsoft.Azure.WebJobs.Extensions.MobileApps" Microsoft.Azure.WebJobs.NotificationHubAttribute #r "Microsoft.Azure.WebJobs.Extensions.NotificationHubs" Microsoft.Azure.WebJobs.ServiceBusAttribute, Microsoft.Azure.WebJobs.ServiceBusAccountAttribute #r "Microsoft.Azure.WebJobs.ServiceBus" Microsoft.Azure.WebJobs.QueueAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute 存储 blob Microsoft.Azure.WebJobs.BlobAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute Microsoft.Azure.WebJobs.TableAttribute, Microsoft.Azure.WebJobs.StorageAccountAttribute Twilio Microsoft.Azure.WebJobs.TwilioSmsAttribute #r "Microsoft.Azure.WebJobs.Extensions.Twilio"
  •  
    推荐文章