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.

重要

只有 1.x 版 Azure Functions 執行階段才支援 F# 指令碼 (.fsx)。F# script (.fsx) is only supported by version 1.x of the Azure Functions runtime. 如果您想要搭配 2.x 版執行階段使用 F#,則必須使用已預先編譯的 F# 類別庫專案 (.fs)。If you want to use F# with the version 2.x runtime, you must use a precompiled F# class library project (.fs). 您需使用 Visual Studio 來建立、管理及發佈 F# 類別庫專案,就像對 C# 類別庫專案一樣。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).

Functions 執行階段 版本 2.x 中所需的繫結延伸模組,是以 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 Functions 觸發程序和繫結開發人員參考所述,每個繫結都支援某幾組引數。Each binding supports some set of arguments, as detailed in the Azure Functions triggers and bindings developer reference. 例如,Blob 觸發程序支援的其中一個引數繫結是可使用 F# 記錄來表示的 POCO。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 Functions 引數時,我們指的是輸入引數和輸出引數。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. 請注意,我們使用 byref<> 做為 output (不必加上 [<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 Functions 架構先適當地設定欄位,再將記錄傳遞給您的函式。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 Functions 裝載環境會自動加入下列組件︰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.

此外,下列組件為特殊案例,可以使用簡單名稱來參考 (例如 #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 Prelude

支援 F# 編譯器服務的編輯器不會知道 Azure Functions 自動包含的命名空間和組件。An editor that supports F# Compiler Services will not be aware of the namespaces and assemblies that Azure Functions automatically includes. 因此,最好在其中包含序言以協助編輯器找到您使用的組件,並明確開啟命名空間。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 Functions 執行程式碼時,它會在定義了 COMPILED 的情況下處理來源,所以編輯器序言會遭到忽略。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 範例檔案會對 Microsoft.ProjectOxford.Face 1.1.0 版新增 NuGet 封裝參考︰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 檔案會如這裡所示指定 net46Only 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.

您可能會想在編輯器序言中自動放入參考組件,來改善您的編輯器與 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 Functions 的持續部署,您可以將 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

您可以使用 .fsx 指示詞以使用其他 #load 檔案中的程式碼。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" 會載入位於與函式資料夾相同層級的 shared資料夾中的檔案 (也就是在 wwwroot 的正下方)。#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: