您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

Azure Functions F# 开发人员参考Azure Functions F# Developer Reference

Azure Functions F# 是用于在云中轻松运行小段代码或“函数”的一个解决方案。F# for Azure Functions is a solution for easily running small pieces of code, or "functions," in the cloud. 数据通过函数参数流入 F # 函数。Data flows into your F# function via function arguments. function.json指定参数名称,没有访问函数记录器和取消令牌等的预定义的名称。Argument names are specified in function.json, and there are predefined names for accessing things like the function logger and cancellation tokens.

重要

仅 Azure Functions 运行时的版本 1.x 支持 F# 脚本 (.fsx)。F# script (.fsx) is only supported by version 1.x of the Azure Functions runtime. 如果要将 F# 与版本 2.x 运行时结合使用,必须使用预编译的 F# 类库项目 (.fs)。If you want to use F# with the version 2.x runtime, you must use a precompiled F# class library project (.fs). 就像 C# 类库项目那样,使用 Visual Studio 创建、管理和发布 F# 类库项目。You create, manage, and publish an F# class library project using Visual Studio as you would a C# class library project. 有关 Functions 版本的详细信息,请参阅 Azure Functions 运行时版本概述For more information about Functions versions, see Azure Functions runtime versions overview.

本文假定已阅读 Azure Functions 开发人员参考This article assumes that you've already read the Azure Functions developer reference.

.Fsx 的工作原理How .fsx works

.fsx 文件是 F # 脚本。An .fsx file is an F# script. 它可以被视为包含单个文件的 F # 项目。It can be thought of as an F# project that's contained in a single file. 该文件包含程序(在此情况下,Azure 函数)和管理依赖关系的指令的代码。The file contains both the code for your program (in this case, your Azure Function) and directives for managing dependencies.

如果使用 Azure 函数的 .fsx,通常需要自动包含程序集,以便可以专注于函数而不是“样本”代码。When you use an .fsx for an Azure Function, commonly required assemblies are automatically included for you, allowing you to focus on the function rather than "boilerplate" code.

文件夹结构Folder structure

F# 脚本项目的文件夹结构如下所示:The folder structure for an F# script project looks like the following:

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

存在共享的 host.json 文件,可用于配置函数应用。There's a shared host.json file that can be used to configure the function app. 每个函数都有自己的代码文件 (.fsx) 和绑定配置文件 (function.json)。Each function has its own code file (.fsx) and binding configuration file (function.json).

2.x 版 Functions 运行时中所需的绑定扩展在 extensions.csproj 文件中定义,实际库文件位于 bin 文件夹中。The binding extensions required in version 2.x of the Functions runtime are defined in the extensions.csproj file, with the actual library files in the bin folder. 本地开发时,必须注册绑定扩展When developing locally, you must register binding extensions. 在 Azure 门户中开发函数时,系统将为你完成此注册。When developing functions in the Azure portal, this registration is done for you.

绑定到参数Binding to arguments

对于每个绑定支持某些参数,请参阅 Azure 函数触发器和绑定开发人员参考Each binding supports some set of arguments, as detailed in the Azure Functions triggers and bindings developer reference. 例如,blob 触发器支持的其中一个参数绑定是 POCO,可以使用 F # 记录来表示。For example, one of the argument bindings a blob trigger supports is a POCO, which can be expressed using an F# record. 例如:For example:

type Item = { Id: string }

let Run(blob: string, output: byref<Item>) =
    let item = { Id = "Some ID" }
    output <- item

F # Azure 函数采用一个或多个参数。Your F# Azure Function will take one or more arguments. 所谓 Azure 函数参数时,指的是 输入 参数和 输出 参数。When we talk about Azure Functions arguments, we refer to input arguments and output arguments. 顾名思义,输入参数就是输入到 F # Azure 函数的参数。An input argument is exactly what it sounds like: input to your F# Azure Function. 输出 参数是可变的数据或 byref<> 参数就是返回数据的参数。An output argument is mutable data or a byref<> argument that serves as a way to pass data back out of your function.

在以上示例中,blob 是输入参数,output 是输出参数。In the example above, blob is an input argument, and output is an output argument. 注意,针对 output,请使用 byref<> (无需添加 [<Out>] 批注)。Notice that we used byref<> for output (there's no need to add the [<Out>] annotation). 使用 byref<> 类型允许函数更改参数所引用的记录或对象。Using a byref<> type allows your function to change which record or object the argument refers to.

作为输入类型使用 F # 记录时,必须使用 [<CLIMutable>]标记的记录定义,以便在记录传递给函数之前让 Azure 功能框架设置相应字段。When an F# record is used as an input type, the record definition must be marked with [<CLIMutable>] in order to allow the Azure Functions framework to set the fields appropriately before passing the record to your function. 实质上, [<CLIMutable>] 生成记录属性的 setter。Under the hood, [<CLIMutable>] generates setters for the record properties. 例如:For example:

[<CLIMutable>]
type TestObject =
    { SenderName : string
      Greeting : string }

let Run(req: TestObject, log: ILogger) =
    { req with Greeting = sprintf "Hello, %s" req.SenderName }

F # 类还可用于输入和输出参数。An F# class can also be used for both in and out arguments. 对于类,属性通常需要 getter 和 setter。For a class, properties will usually need getters and setters. 例如:For example:

type Item() =
    member val Id = "" with get,set
    member val Text = "" with get,set

let Run(input: string, item: byref<Item>) =
    let result = Item(Id = input, Text = "Hello from F#!")
    item <- result

日志记录Logging

若要使用 F# 将输出记录到流式处理日志中,函数应带有 ILogger 类型的参数。To log output to your streaming logs in F#, your function should take an argument of type ILogger. 为了保持一致,我们建议参数名为 logFor consistency, we recommend this argument is named log. 例如:For example:

let Run(blob: string, output: byref<string>, log: ILogger) =
    log.LogInformation(sprintf "F# Azure Function processed a blob: %s" blob)
    output <- input

异步Async

可使用 async 工作流,但结果需要返回 TaskThe async workflow can be used, but the result needs to return a Task. 使用 Async.StartAsTask 可实现此目的,例如:This can be done with Async.StartAsTask, for example:

let Run(req: HttpRequestMessage) =
    async {
        return new HttpResponseMessage(HttpStatusCode.OK)
    } |> Async.StartAsTask

取消令牌Cancellation Token

如果函数需要正常地处理关闭,可指定 CancellationToken 参数。If your function needs to handle shutdown gracefully, you can give it a CancellationToken argument. 联合 async 可实现此目的,例如:This can be combined with async, for example:

let Run(req: HttpRequestMessage, token: CancellationToken)
    let f = async {
        do! Async.Sleep(10)
        return new HttpResponseMessage(HttpStatusCode.OK)
    }
    Async.StartAsTask(f, token)

导入命名空间Importing namespaces

可按照通常的处理方式打开命名空间:Namespaces can be opened in the usual way:

open System.Net
open System.Threading.Tasks
open Microsoft.Extensions.Logging

let Run(req: HttpRequestMessage, log: ILogger) =
    ...

自动打开以下命名空间:The following namespaces are automatically opened:

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

引用外部程序集Referencing External Assemblies

与此类似,可以使用 #r "AssemblyName" 指令添加框架程序集引用。Similarly, framework assembly references can be added with the #r "AssemblyName" directive.

#r "System.Web.Http"

open System.Net
open System.Net.Http
open System.Threading.Tasks
open Microsoft.Extensions.Logging

let Run(req: HttpRequestMessage, log: ILogger) =
    ...

由 Azure 函数主机环境自动添加以下程序集:The following assemblies are automatically added by the Azure Functions hosting environment:

  • mscorlib,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.FormattingSystem.Net.Http.Formatting.

此外,以下程序集比较特殊,可能由 simplename 引用 (例如 #r "AssemblyName"):In addition, the following assemblies are special cased and may be referenced by simplename (e.g. #r "AssemblyName"):

  • Newtonsoft.Json
  • Microsoft.WindowsAzure.Storage
  • Microsoft.ServiceBus
  • Microsoft.AspNet.WebHooks.Receivers
  • Microsoft.AspNEt.WebHooks.CommonMicrosoft.AspNEt.WebHooks.Common.

如果需要引用私有程序集,可以将程序集文件上传到 bin 与功能相关的文件,并通过使用文件名(例如#r "MyAssembly.dll")来引用它.If you need to reference a private assembly, you can upload the assembly file into a bin folder relative to your function and reference it by using the file name (e.g. #r "MyAssembly.dll"). 有关如何将文件上传到函数文件夹的信息,请参阅下一部分中有关程序包管理的信息。For information on how to upload files to your function folder, see the following section on package management.

Editor PreludeEditor Prelude

支持 F # 编译器服务的编辑器检测不到命名空间和 Azure 函数会自动包括在内的程序集。An editor that supports F# Compiler Services will not be aware of the namespaces and assemblies that Azure Functions automatically includes. 在这种情况下,包含可帮助找到使用的程序集并显式地打开命名空间的 prelude,这会很有帮助。As such, it can be useful to include a prelude that helps the editor find the assemblies you are using, and to explicitly open namespaces. 例如:For example:

#if !COMPILED
#I "../../bin/Binaries/WebJobs.Script.Host"
#r "Microsoft.Azure.WebJobs.Host.dll"
#endif

open System
open Microsoft.Azure.WebJobs.Host
open Microsoft.Extensions.Logging

let Run(blob: string, output: byref<string>, log: ILogger) =
    ...

Azure 函数执行代码时,它可以处理带有 COMPILED 定义的源,因此将忽略编辑器 prelude。When Azure Functions executes your code, it processes the source with COMPILED defined, so the editor prelude will be ignored.

包管理Package management

若要在 F# 函数中使用 NuGet 包,可将 project.json 文件添加到函数应用的文件系统中函数的文件夹。To use NuGet packages in an F# function, add a project.json file to the function's folder in the function app's file system. 下面是一个示例 project.json 文件,其中将 NuGet 包引用添加到 Microsoft.ProjectOxford.Face 1.1.0 版:Here is an example project.json file that adds a NuGet package reference to Microsoft.ProjectOxford.Face version 1.1.0:

{
  "frameworks": {
    "net46":{
      "dependencies": {
        "Microsoft.ProjectOxford.Face": "1.1.0"
      }
    }
   }
}

只支持.NET Framework 4.6,因此请确保 project.json 文件指定 net46如下所示。Only the .NET Framework 4.6 is supported, so make sure that your project.json file specifies net46 as shown here.

上传 project.json 文件时,运行时获取包,并自动将引用添加到包程序集。When you upload a project.json file, the runtime gets the packages and automatically adds references to the package assemblies. 无需添加 #r "AssemblyName" 指令。You don't need to add #r "AssemblyName" directives. 只需添加所需 open 语句到 .fsx 文件。Just add the required open statements to your .fsx file.

可能希望会自动引用程序集放入编辑器 prelude,以提高编辑器与 F # 编译服务的交互。You may wish to put automatically references assemblies in your editor prelude, to improve your editor's interaction with F# Compile Services.

如何添加 project.json 文件到 Azure 函数How to add a project.json file to your Azure Function

  1. 首先,确保函数应用程序正在运行,可以通过在 Azure 门户中打开函数来执行此操作。Begin by making sure your function app is running, which you can do by opening your function in the Azure portal. 通过此操作,还可以访问将要显示程序包安装输出位置的流式传输日志。This also gives access to the streaming logs where package installation output will be displayed.
  2. 若要上传 project.json 文件,请使用如何更新函数应用程序文件 中描述的其中一种方法To upload a project.json file, use one of the methods described in how to update function app files. 如果使用 Azure 函数的连续部署 ,可以添加 project.json 文件到临时分支,以便添加到部署的分支文件对其进行测试。If you are using Continuous Deployment for Azure Functions, you can add a project.json file to your staging branch in order to experiment with it before adding it to your deployment branch.
  3. 添加 project.json 文件后,将看到类似于函数流式日志中的实例的输出:After the project.json file is added, you will see output similar to the following example in your function's streaming log:
2016-04-04T19:02:48.745 Restoring packages.
2016-04-04T19:02:48.745 Starting NuGet restore
2016-04-04T19:02:50.183 MSBuild auto-detection: using msbuild version '14.0' from 'D:\Program Files (x86)\MSBuild\14.0\bin'.
2016-04-04T19:02:50.261 Feeds used:
2016-04-04T19:02:50.261 C:\DWASFiles\Sites\facavalfunctest\LocalAppData\NuGet\Cache
2016-04-04T19:02:50.261 https://api.nuget.org/v3/index.json
2016-04-04T19:02:50.261
2016-04-04T19:02:50.511 Restoring packages for D:\home\site\wwwroot\HttpTriggerCSharp1\Project.json...
2016-04-04T19:02:52.800 Installing Newtonsoft.Json 6.0.8.
2016-04-04T19:02:52.800 Installing Microsoft.ProjectOxford.Face 1.1.0.
2016-04-04T19:02:57.095 All packages are compatible with .NETFramework,Version=v4.6.
2016-04-04T19:02:57.189
2016-04-04T19:02:57.189
2016-04-04T19:02:57.455 Packages restored.

环境变量Environment variables

若要获取环境变量或某个应用程序设置值,请使用 System.Environment.GetEnvironmentVariable,例如:To get an environment variable or an app setting value, use System.Environment.GetEnvironmentVariable, for example:

open System.Environment
open Microsoft.Extensions.Logging

let Run(timer: TimerInfo, log: ILogger) =
    log.LogInformation("Storage = " + GetEnvironmentVariable("AzureWebJobsStorage"))
    log.LogInformation("Site = " + GetEnvironmentVariable("WEBSITE_SITE_NAME"))

重用.fsx 代码Reusing .fsx code

可以通过 #load 指令使用其他 .fsx 文件中的代码。You can use code from other .fsx files by using a #load directive. 例如:For example:

run.fsx

#load "logger.fsx"

let Run(timer: TimerInfo, log: ILogger) =
    mylog log (sprintf "Timer: %s" DateTime.Now.ToString())

logger.fsx

let mylog(log: ILogger, text: string) =
    log.LogInformation(text);

提供给 #load 指令的路径与.fsx 文件位置相关。Paths provides to the #load directive are relative to the location of your .fsx file.

  • #load "logger.fsx" 加载函数文件夹中的文件。#load "logger.fsx" loads a file located in the function folder.
  • #load "package\logger.fsx" 加载文件 package 函数文件夹中的文件夹。#load "package\logger.fsx" loads a file located in the package folder in the function folder.
  • #load "..\shared\mylogger.fsx" 在同一级别(即 wwwroot 的正下方)加载 shared 文件夹中的文件,使其成为函数文件夹。#load "..\shared\mylogger.fsx" loads a file located in the shared folder at the same level as the function folder, that is, directly under wwwroot.

#load 指令只适用于 .fsx(F # 脚本)文件,而不适用于 .fs 文件。The #load directive only works with .fsx (F# script) files, and not with .fs files.

后续步骤Next steps

有关详细信息,请参阅以下资源:For more information, see the following resources: