本文假定你已阅读
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
将方法返回值用于输出绑定。 有关示例,请参阅触发器和绑定。
仅当成功的函数执行始终将返回值传递给输出绑定时,才使用返回值。 否则,请使用 ICollector
或 IAsyncCollector
,如以下部分所示。
写入多个输出值
若要将多个值写入输出绑定,或者如果成功的函数调用可能无法将任何内容传递给输出绑定,请使用 ICollector
或 IAsyncCollector
类型。 这些类型是只写集合,当方法完成时写入输出绑定。
此示例使用 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 binder
或 IBinder 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"