tech.guitarrapc.cóm

Technical updates

.NET Core on AWS Lambda がリリースされました

今年は非常にうれしいことが Azure と AWS 両方でありました。Azure Functions と .NET Core on AWS Lambda です。

これまで多くの AWS Lambda関数 (Node.js) と Azure Functions (C#) を書いてきましたがこれでようやく AWS Lambda に完全に寄せることができます。

早速 AWS Lambda で C# (.NET Core) を触ってみましょう。

目次

Lambda 上は Java と同じく dll をアップロード

Node と違い、Java 同様のdll を zip で固めてアップロードとなります。そのため、Lambda の画面でコードを直接触ることはできません。

ここは Azure Functions と違い直接コード修正にはなりませんね。ただし大事なのは、.NET Core をビルドした結果を挙げるという点です。Azure Functions ですぐに出会って今でも困るのが、「共通コードを参照した場合にローカルビルドを通せなくなるケース」や「.csx のためインテリセンスが非常に貧弱」という問題があります。*1

DLLをビルドしてアップロードということは、ローカル挙動が安定して、コンパイル、ビルドも安定するので個人的には十分に許容、嬉しいポインとのです。*2

C# (.NET Core) でコードを書いてみる

記事作成の現時点では AWS Document がないので、手探りで見てみましょう。ドキュメントが公開されたので参考にどうぞ。

環境は Windows 10 Pro + Visual Studio 2015 Enterprise です。

.NET Core 環境を用意する

まずは .NET Core の最新版をインストールします。手順通りにやっていきましょう。

Download .NET (Linux, macOS, and Windows)

インストール中...。

5分未満で完了すると思います。

Visual Studio Integration

AWS は Visual Studio Integration がかなり進んでいます。リソース管理にとどまらず、Node.js の Lambda 関数も書いています。

Lambda を C# (.NET Core) でVisual Studio で書くため、最新版の AWS SDK for .NET をダウンロード、インストールしましょう。インストール後に新規プロジェクト > Templates > Visual C# > AWS Lambda というのが新しくできています。

4つプロジェクトがありますが、今回はシンプルに関数を作ってローカルビルド > アップロードという流れでやるため「AWS Lambda Project (.NET Core)」 を使ってみましょう。

プロジェクト種別 説明
AWS Lambda Project (.NET Core) A project for creating a AWS Lambda Functions using .NET Core
AWS Lambda Project with Tests (.NET Core) A project for creating a AWS Lambda Functions using .NET Core
AWS Serverless Project (.NET Core) An AWS Serverless application uses the power of AWS Lmabda and AWS CloudFormation to build a cloud-enabled serverless application
AWS Serverless Project with Tests (.NET Core) An AWS Serverless application uses the power of AWS Lmabda and AWS CloudFormation to build a cloud-enabled serverless application

BluePrint の選択

4つのひな形が提示されています。今回は単純な Empty Function を作ってみます。

余談ですが、もし.NET Core のセットアップを忘れて、AWS Lambda Project を作ろうとすると次のエラーが出て作れないので注意です。この場合、前述した.NET Core の最新をインストールしてから、再度 Lambda プロジェクトを作ってみましょう。

もしも project.json のパッケージ復元でエラーが生じる場合

AWS Lambda (.NET Core) のプロジェクトを作って project.json でエラーが出る場合があるようです。*3

この場合、Amazon* とつくパッケージが解決できていない場合は、直接 nuget パッケージをインストールすればok です。例えば次のproject.json なら dotnet restore でパッケージを復元しましょう。*4

{
  "version": "1.0.0-*",
  "buildOptions": {
  },

  "dependencies": {
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.0.1"
    },
    "Amazon.Lambda.Core": "1.0.0",
    "Amazon.Lambda.Serialization.Json": "1.0.0",
    "Amazon.Lambda.Tools": "1.0.0-preview1"
  },

  "tools": {
    "Amazon.Lambda.Tools": "1.0.0-preview1"
  },

  "frameworks": {
    "netcoreapp1.0": {
      "imports": "dnxcore50"
    }
  }
}

このコマンドを Package Management Console で実行でもパッケージは復元できます。*5

Install-Package Amazon.Lambda.Tools -Pre
Install-Package Amazon.Lambda.Core
Install-Package Amazon.Lambda.Serialization.Json

解決されれば、project.json のエラーが消えて、Function.cs もエラーが出ていないはずです。

この状態で何も編集せずビルドが通れば準備完了です。

サンプルコードの記述

雑に Console.WriteLine だけ追加してちょっとだけいじってみます。


[https://gist.github.com/guitarrapc/e21578a8c777993e97dae62e7f03ac8e:embed:cite]

アップロード

残念ながら今日発表された CodeBuild はC#をサポートしていません。

Build Environment – Language / runtime environment (Android, Java, Python, Ruby, Go, Node.js, or Docker).

AWS CodeBuild – Fully Managed Build Service | AWS News Blog

CI のことは次回以降にして、ローカルでビルドしてアップロードしてみましょう。

Node.js と同様に、「アップロードする対象のプロジェクトを右クリック -> Publish to AWS Lambda」 します。

資格情報などをいい感じにして

IAM Role に 必要な権限のロールを割り当てます。今回はただの実行なので lambda_exec_role でok です。

メモリは、いったんデフォルトのままで行きますが、Java と似た傾向と予想されます。性能に関しても後日確認してみましょう。

acro-engineer.hatenablog.com

ではUploadしてみてください。うまくいくと、Lambdaの画面を AWS Console を開かずに VS でFunction画面が開いてくれます。Event Source などもここにあるので、事実上のローカルからの直接実行です。

実行

そのまま Visula Studio から Invoke するか、AWS Console で実行してみましょう。

このとき、Node.js の時のように json でイベントを記述すると自動的にデシリアライズされてしまいエラーが発生してしまいます。

{
  "errorType": "JsonReaderException",
  "errorMessage": "Unexpected character encountered while parsing value: {. Path '', line 1, position 1.",
  "stackTrace": [
    "at Newtonsoft.Json.JsonTextReader.ReadStringValue(ReadType readType)",
    "at Newtonsoft.Json.JsonTextReader.ReadAsString()",
    "at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter)",
    "at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)",
    "at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)",
    "at Newtonsoft.Json.JsonSerializer.Deserialize[T](JsonReader reader)",
    "at lambda_method(Closure , Stream , Stream , ContextInfo )"
  ]
}

今回は、受ける引数を string としているので、"hogemoge" というストリングを送るようにします。うまく Response にかえって来ましたね。

任意のクラスを受けて実行する

次は string ではなく任意のクラスを用意して、外部から来た JSON を受けられるようにします。

想定する JSON は次のフォーマットです。

{"Str":"hogehoge","StrArray":["hoge","huga","foo"]}

対応するクラスは次の通りです。

public class SampleClass
{
    public string Str { get; set; }
    public string[] StrArray { get; set; }
}

ということで全体

gist.github.com

実行してみるとうまく取れていますね。

まとめ

まずは Hello World でした。次は Azure Functions で書いた処理をサクサク Lambda にもってきて紹介します。

今回の実装を含めて、AWS Lambda .NET Core (C#) の実装サンプルはリポジトリにあげていくのでよろしければどうぞ。

github.com

*1:個人的に C# を好んでいるのがインテリセンス強さなので、かなり嬉しくない副作用です。

*2:もちろん直接編集できる方がうれしいですが、副作用大きすぎるしむしろこれでいいです。

*3:わたしとか

*4:Private NuGet リポジトリを登録していたりすると dotnet restore に失敗するようです

*5:こちらなら Private NuGet リポジトリを登録していても影響ありません