Function Compute で C# を使用するには、まず C# で書かれた関数をハンドラとして定義する必要があります。このトピックでは、使用できる C# ハンドラとその定義について説明します。
概要
現在、C# ランタイム (.NET Core 2.1) は共通ハンドラと HTTP トリガーハンドラの 2 種類のハンドラをサポートしています。HTTP トリガーを設定したらハンドラの形式が異なります。それは HTTP リクエストを簡単に処理するためです。
共通ハンドラ
ハンドラの定義
C# 関数を作成する際に、関数と共に実行される Handler メソッドを指定する必要があります。この Handler メソッドは、static メソッドまたは instance メソッドにすることができます。このメソッドで IFcContext オブジェクトにアクセスするには、このメソッドの 2 番目のパラメーターとして IFcContext オブジェクト
を指定できます。サポートしている Handler メソッドは次のように定義されています。
ReturnType HandlerName(InputType input, IFcContext context); // IFcContext included
ReturnType HandlerName(InputType input); // IFcContext not included
Async Task<ReturnType> HandlerName(InputType input, IFcContext context);
Async Task<ReturnType> HandlerName(InputType input);
Function Compute は、C# で記述された関数で Async の使用をサポートしています。この場合、関数の実行は非同期メソッドの実行の終了を待ちます。
ReturnType
: 返されるオブジェクトです。void
、System.IO.Stream オブジェクト
、あるいは任意の JSON シリアライズオブジェクトまたはデシリアライズオブジェクト
になります。void
が返されると、Async Taskは、async Task にデグレードされます。 Stream オブジェクト
が返される場合、Stream の内容はレスポンスボディで返されます。それ以外の場合、返されるオブジェクトは JSON でシリアル化され、レスポンスボディで返されます。InputType
: 入力パラメーターです。System.IO.Stream
または任意の JSON シリアライズオブジェクトまたはデシリアライズオブジェクト
になります。IFcContext
: 関数のコンテキストオブジェクトです。以下の情報が含まれます。
パラメーター | 型 | 説明 |
---|---|---|
RequestId | String | 現在のコールリクエストの GUID。通常、障害検出または履歴コールカウント中に使用されます。 |
FunctionParam | Class | 現在呼び出されている関数に関する基本情報。 (関数名、ハンドラ、メモリ、タイムアウト期間など) |
Credentials | Class | Function Compute が、提供されたサービスロールを行うことで取得される一時的な SecurityToken。SecurityToken は 15 分ごとに更新されます。SecurityToken を使用して、OSS など他の Alibaba Cloud サービスにアクセスできます。これにより、関数コードで AccessKey のハードコーディングを防ぎます。 |
ServiceMeta | Class | 現在呼び出されている関数が属するサービスに関する情報。 Log Service のサービス名、アクセスされた Logproject や Logstore、および修飾子や version_id などのサービスのバージョンを含みます。修飾子は、関数が呼び出されるときに指定されるサービスのバージョン、またはエイリアスを示し、version_id は実際に呼び出されるサービスのバージョンを示します。 |
Region | String | cn-shanghai など、現在呼び出されている関数が配置されているリージョン。詳細については、「リージョンとゾーン」 をご参照ください。 |
AccountId | String | 現在の関数の呼び出し元の Alibaba Cloud アカウント ID。詳細については、「アカウント ID の取得」 をご参照ください。 |
詳しくは 「fc-dotnet-libs」 をご参照ください。
Handler メソッドの例
Function Compute を使用して C# で関数を記述する際、 Aliyun.Serverless.Core
パッケージは NuGet を通して導入する必要があります。
Stream Handler
次のメソッドでは、ユーザーリクエストからの入力をそのまま返します。
using System.IO;
using System.Threading.Tasks;
using Aliyun.Serverless.Core;
using Microsoft.Extensions.Logging;
namespace FC.Examples
{
public class TestHandler
{
public async Task<Stream> Echo(Stream input, IFcContext context)
{
ILogger logger = context.Logger;
logger.LogInformation("Handle request: {0}", context.RequestId);
MemoryStream copy = new MemoryStream();
await input.CopyToAsync(copy);
copy.Seek(0, SeekOrigin.Begin);
return copy;
}
}
}
POCO Handler
Stream オブジェクトに加えて、POCO (Plain Old CLR Object) も入力および出力パラメーターとして使用できます。POCO が JSON シリアル化オブジェクトを指定しない場合、Function Compute はデフォルト Json.Net を使用して、JSON 形式のオブジェクトをシリアライズおよびデシリアライズします。
using Microsoft.Extensions.Logging;
namespace FC.Examples
{
public class TestHandler
{
public class Product
{
public string Id { get; set; }
public string Description { get; set; }
}
// optional serializer class, if it’s not specified, the default serializer (based on JSON.Net) will be used.
// [FcSerializer(typeof(MySerialization))]
public Product Echo(Product product, IFcContext context)
{
string Id = product.Id;
string Description = product.Description;
context.Logger.LogInformation("Id {0}, Description {1}", Id, Description);
return product;
}
}
}
Handler の指定
ハンドラの署名
関数を作成するときは、呼び出すメソッドを見つける方法を Function Compute に指示するために、文字列形式で handler
メソッドを指定する必要があります。文字列の形式は次のとおりです。
AssemblyFileName::FullClassName::METHOD
この内、
AssemblyFileName
は関数があるAssembly
のファイル名です。 (.dll は省略されます)FullClassName
は関数が属するクラスのフルネーム、つまり、Namespace.ClassName
です。Method
は呼び出されるメソッドの名前です。
上記の Handler
の例で、Assembly
ファイルの名前が test_assembly
の場合、 handler
の文字列は以下のようになります。
test_assembly::FC.Examples.TestHandler::Echo
制限事項
Handler
パラメーターの形式は前述の定義に従います。つまり、パラメーター 1 は必須ですが、パラメーター 2 はオプションで、IFcContext
は定数です。Handler
関数は、Generic Method
をサポートしていません。入力パラメーターと出力パラメーターは
Stream
オブジェクトにするか、JSON 形式でシリアル化
する必要があります。Async
関数は Task を返します。T は Stream
オブジェクトか、あるいはJSON 形式でシリアル化
できるクラスでなければなりません。
Custom Serializer
POCO ハンドラの場合、Function Compute はデフォルトで、JSON . NET シリアライザを提供しています。デフォルトのシリアライザが要件を満たさない場合は、 Aliyun.Serverless.Core
の IFcSerializer
インターフェイスに基づいてカスタムシリアライザを実装することができます。
public interface IFcSerializer
{
T Deserialize<T>(Stream requestStream);
void Serialize<T>(T response, Stream responseStream);
}
共通ハンドラの動作例
SecurityToken は、リクエスト者の身元と許可を検証するために使用されます。OSS などの他の Alibaba Cloud サービスにアクセスするときは、SecurityToken を指定する必要があります。次の C# サンプルコードでは、SecurityToken を使用して OSS バケットから指定されたオブジェクトを取得しています。
.NET Core コンソールプロジェクトを作成します。
[songluo@~/tmp]# mkdir fcdotnetsample
[songluo@~/tmp]# cd fcdotnetsample
[songluo@~/tmp/fcdotnetsample]# dotnet new console
以下のパッケージを fcdotnetsample.csproj に追加します。
<ItemGroup>
<PackageReference Include="Aliyun.Serverless.Core" Version="1.0.1" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.9.1" />
</ItemGroup>
Program.cs
を編集します。using System;
using System.IO;
using Aliyun.OSS;
using Aliyun.Serverless.Core;
namespace fcdotnetsample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
public class OssFileHandlerRequest
{
public string Bucket;
public string Key;
public string Endpoint;
}
public class OSSFileHandler
{
public Stream GetOssFile(OssFileHandlerRequest req, IFcContext context)
{
if (req == null)
{
throw new ArgumentNullException(nameof(req));
}
if (context == null || context.Credentials == null)
{
throw new ArgumentNullException(nameof(context));
}
OssClient ossClient = new OssClient(req.Endpoint, context.Credentials.AccessKeyId, context.Credentials.AccessKeySecret, context.Credentials.SecurityToken);
OssObject obj = ossClient.GetObject(req.Bucket, req.Key);
return obj.Content;
}
}
}
プロジェクトを公開し、ターゲットファイルを .zip パッケージに圧縮します。
[songluo@~/tmp/fcdotnetsample]# dotnet publish -c Release
Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 47.9 ms for /Users/songluo/tmp/fcdotnetsample/fcdotnetsample.csproj.
fcdotnetsample -> /Users/songluo/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/fcdotnetsample.dll
fcdotnetsample -> /Users/songluo/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish/
[songluo@~/tmp/fcdotnetsample]# cd /Users/songluo/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish/
[songluo@~/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish]# zip -r fcdotnetsample.zip *
adding: Aliyun.OSS.Core.dll (deflated 60%)
adding: Aliyun.Serverless.Core.dll (deflated 59%)
adding: Microsoft.Extensions.Logging.Abstractions.dll (deflated 53%)
adding: fcdotnetsample.deps.json (deflated 73%)
adding: fcdotnetsample.dll (deflated 57%)
adding: fcdotnetsample.pdb (deflated 27%)
adding: fcdotnetsample.runtimeconfig.json (deflated 23%)
[songluo@~/tmp/fcdotnetsample/bin/Release/netcoreapp2.1/publish]# ls -ll fcdotnetsample.zip
-rw-r--r-- 1 songluo staff 130276 Mar 14 17:48 fcdotnetsample.zip
fcdotnetsample.zip
を使用して、ランタイム .NET Core 2.1 とハンドラ fcdotnetsample::fcdotnetsample.OSSFileHandler::GetOssFile
で関数を作成します。
Initializer ハンドラ
Function Compute は初期化のための Init メソッドを提供しています。バックグラウンドコンテナーが開始されると、Init メソッドが自動的に呼び出されます。各バックグラウンドコンテナーは一度だけ呼び出されます。
init メソッドの定義
public void Init(); // No context objects
public void Init(IFcContext context); // Include context objects
public static void Init(); // No context objects
public static void Init(IFcContext context); // Include context objects
Initializer 形式
MyInitializer
は Initializer 関数が追加される際に “initializer” フィールドをマッピングする必要があります。たとえば、関数が作成される際にfcdotnetsample::fcdotnetsample.TestHandler::MyInitializer
が Initializer ハンドラとして指定されている場合、初期化設定後、Function Compute は、最初にfcdotnetsample.TestHandler
で定義されたMyInitializer
関数をロードします。
Initializer 特徴
- IFcContext の FunctionParam の
FunctionInitializer
とInitializationTimeout
は、 Initializer 用に設計されており、Initializer の使用中に関数が作成されると、ユーザー定義の値に設定されます。それ以外の場合は空になり、無効になります。 - 値は返されません。関数に追加された Return 操作は無効です。
HTTP トリガーハンドラ
HTTP トリガーを持つハンドラは、他のトリガー必須ハンドラとは異なり、次のように定義されています。
C# で HTTP トリガーを使って関数を記述する場合、 Aliyun.Serverless.Core
とAliyun.Serverless.Core.Http
パッケージは NuGet を通して導入される必要があります。
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Aliyun.Serverless.Core;
using Aliyun.Serverless.Core.Http;
namespace MySpace.TestHandlers
{
public class SingleHttpHandler : FcHttpEntrypoint
{
protected override void Init(IWebHostBuilder builder)
{ }
public override async Task<HttpResponse> HandleRequest(HttpRequest request, HttpResponse response, IFcContext fcContext)
{
response.StatusCode = 200;
response.ContentType = "text/plain";
await response.WriteAsync("hello world");
return response;
}
}
}
入力パラメーター
IFcContext パラメーターは、一般的なハンドラの IFcContext パラメーターと同じです。
説明
HTTP トリガーを持つ C# で記述された関数は、 Aliyun.Serverless.Core.Http
のFcHttpEntrypoint
を継承しなければなりません。Init
関数をオーバーライドする必要があります。HandleRequest はハンドラであり、必要に応じてオーバーライドすることができます。
Single function
: HandleRequest カスタマイズを論理的に処理する HandleRequest をオーバーライドするために使用されます。Asp.net core application
: Init 関数だけがオーバーライドされます。
次の例では FcHttpEntrypoint
の使い方を示しています。
HTTP トリガーハンドラの例
Single 関数の例
次の例では、HTTP トリガーを持つハンドラの HttpRequest および HttpResponse を使用する方法を示しています。
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Aliyun.Serverless.Core;
using Aliyun.Serverless.Core.Http;
using Microsoft.Extensions.Logging;
namespace MySpace.TestHandlers
{
public class SingleHttpHandler : FcHttpEntrypoint
{
protected override void Init(IWebHostBuilder builder)
{
}
public override async Task<HttpResponse> HandleRequest(HttpRequest request, HttpResponse response, IFcContext fcContext)
{
string method = request.Method;
string relativePath = request.Path.Value;
fcContext.Logger.LogInformation("method = {0}; requestPath = {1}", method, relativePath);
StreamReader sr = new StreamReader(request.Body);
string requestBody = sr.ReadToEnd();
fcContext.Logger.LogInformation("requestBody = {}", requestBody);
// process request.Headers
response.StatusCode = 200;
response.ContentType = "text/plain";
response.Headers.Add("customheader", "v1");
await response.WriteAsync("hello world");
return response;
}
}
}
Asp.net core application の例
using System;
using Aliyun.Serverless.Core.Http;
using Microsoft.AspNetCore.Hosting;
namespace MySpace.TestWebApi
{
public class FcRemoteEntrypoint : FcHttpEntrypoint
{
protected override void Init(IWebHostBuilder builder)
{
builder
.UseStartup<Startup>();
}
}
}
操作手順
asp.net core の webapi プロジェクトを作成します。
[songluo@~/tmp]# mkdir fcaspdotnetsample
[songluo@~/tmp]# cd fcaspdotnetsample
[songluo@~/tmp/fcaspdotnetsample]# dotnet new webapi
以下のパッケージを fcaspdotnetsample.csproj に追加します。
<ItemGroup>
<PackageReference Include="Aliyun.Serverless.Core" Version="1.0.1" />
<PackageReference Include="Aliyun.Serverless.Core.Http" Version="1.0.2" />
</ItemGroup>
Asp.net core application のサンプルコードを含む
FcRemoteEntrypoint.cs
という名前のファイルを作成します。プロジェクトを公開し、ターゲットファイルを .zip パッケージに圧縮します。
[songluo@~/tmp/fcaspdotnetsample]# dotnet publish -c Release
Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 88.39 ms for /Users/songluo/tmp/fcaspdotnetsample/fcaspdotnetsample.csproj.
fcaspdotnetsample -> /Users/songluo/tmp/fcaspdotnetsample/bin/Release/netcoreapp2.1/fcaspdotnetsample.dll
fcaspdotnetsample -> /Users/songluo/tmp/fcaspdotnetsample/bin/Release/netcoreapp2.1/publish/
[songluo@~/tmp/fcaspdotnetsample]# cd /Users/songluo/tmp/fcaspdotnetsample/bin/Release/netcoreapp2.1/publish/
[songluo@~/tmp/fcaspdotnetsample/bin/Release/netcoreapp2.1/publish]# zip -r fcaspdotnetsample.zip *
adding: appsettings.Development.json (deflated 40%)
adding: appsettings.json (deflated 30%)
adding: fcaspdotnetsample.deps.json (deflated 85%)
adding: fcaspdotnetsample.dll (deflated 61%)
adding: fcaspdotnetsample.pdb (deflated 40%)
adding: fcaspdotnetsample.runtimeconfig.json (deflated 31%)
adding: web.config (deflated 40%)
[songluo@~/tmp/fcaspdotnetsample/bin/Release/netcoreapp2.1/publish]# ls -ll fcaspdotnetsample.zip
-rw-r--r-- 1 songluo staff 39101 Mar 15 09:47 fcaspdotnetsample.zip
fcaspdotnetsample.zip
を使用して、ランタイム .NET Core 2.1 とfcaspdotnetsample::MySpace.TestWebApi.FcRemoteEntrypoint::HandleRequest
ハンドラで関数を作成します。
Single 関数を使用している場合は、共通ハンドラの完了動作例の手順に従って、コンソールプロジェクトと FcRemoteEntrypoint.cs を作成し、そのコードを Single 関数のサンプルコードと置き換えてください。
HTTP トリガーハンドラの制限事項
リクエストの制限事項
HTTP トリガーを持つハンドラのリクエストが以下の制限を超えると、ステータスコード 400
とエラーコード InvalidArgument
がスローされます。
パラメーター | 制限事項 | HTTP ステータスコード | エラーコード |
---|---|---|---|
headers | ヘッダー内のすべてのキーと値のペアのサイズは 4 KB を超えることはできません。 | 400 | InvalidArgument |
path | パスとすべてのクエリパラメーターのサイズは 4 KB を超えることはできません。 | ||
body | HTTP リクエストボディのサイズは 6 MB を超えることはできません。 |
レスポンスの制限事項
HTTP トリガーを持つハンドラのレスポンスが以下の制限を超えると、 502
ステータスコードと BadResponse
エラーコードがスローされます。
パラメーター | 制限事項 | HTTP ステータスコード | エラーコード |
---|---|---|---|
headers | ヘッダー内のすべてのキーと値のペアのサイズは 4 KB を超えることはできません。 | 502 | BadResponse |
body | HTTP レスポンスボディのサイズは 6 MB を超えることはできません。 |
HTTP トリガーの詳細については、「HTTP トリガー」 をご参照ください。
参考文献
C# ランタイムの詳細については、「C# ランタイム」 をご参照ください。