AWS Lambda(C#)からS3へファイル作成して保存してみた

初めてLambdaを使っていた時に、いろいろはまりましたので、その経験をメモにしました。

#開発環境
[.Net Core](https://www.microsoft.com/net/core#windowsvs2017)
[AWS Toolkit for Visual Studio](https://aws.amazon.com/jp/visualstudio/)

#S3と連携

``` C#
using Amazon.S3;
using Amazon.S3.Model;
```
だけでは使えないようです。
![s3_using_error.png](https://qiita-image-store.s3.amazonaws.com/0/191079/7389b734-9441-6ea1-de33-0274df6d6180.png)
Nugetで必要なパッケージをインストールする必要があります。

![s3_nuget_import.png](https://qiita-image-store.s3.amazonaws.com/0/191079/21738aa0-2a32-907b-0eab-66340a648d76.png)

![install.png](https://qiita-image-store.s3.amazonaws.com/0/191079/bc7b83aa-0702-c70a-e9b8-a6604b320381.png)
これでエラーが消えました。
![installed.png](https://qiita-image-store.s3.amazonaws.com/0/191079/ae5f8ee1-93a8-f31c-e2bc-532dd2c91652.png)

###S3にファイルを作成するコード
早速AWSのサンプルコードを参考し実装してみました。
[AWS SDK for .NET を使用したオブジェクトのアップロード](http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/UploadObjSingleOpNET.html)

``` C#
using System;
using System.Threading.Tasks;

using Amazon.Lambda.Core;
using Amazon.S3;
using Amazon.S3.Model;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

namespace AWSLambdaSample
{
    public class Function
    {
        /// <summary>
        /// A simple function that takes a string and does a ToUpper
        /// </summary>
        /// <param name="input"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public string FunctionHandler(string input, ILambdaContext context)
        {
            AmazonS3Client client = new AmazonS3Client(Amazon.RegionEndpoint.APNortheast1);

            PutObjectRequest request = new PutObjectRequest()
            {

                BucketName = "databucket-rest-datasource",
                Key = "hello.txt",
                ContentType = "text/plain",
                ContentBody = "Hello World!"
            };
            try {
                client.PutObjectAsync(request);
                return "OK";
                
            } catch (Exception e) {
                return e.ToString();
            }
        }
    }
}
```
###LambdaにPublish
Publish to AWS
![publishtoaws.png](https://qiita-image-store.s3.amazonaws.com/0/191079/e03cf1a6-b1af-ec13-9682-eac0d62b027f.png)

![uploadlambdafunction.png](https://qiita-image-store.s3.amazonaws.com/0/191079/cede3908-629f-b446-aa22-cf83075d0fbe.png)

ロールを選択し、Upload
![roleset.png](https://qiita-image-store.s3.amazonaws.com/0/191079/e071580d-ef92-7ae8-4578-fbe4110c2795.png)

###Lambdaで実行
Input（特に利用してないので、ただのダミー）を入れて、Invokeしてみると
![invoke.png](https://qiita-image-store.s3.amazonaws.com/0/191079/0e84f534-4019-e809-faeb-41f1fc42a4fb.png)
正常に通ったので、簡単だなと思いきや、S3のバケットに何も作成されませんでした。

![s3bucket.png](https://qiita-image-store.s3.amazonaws.com/0/191079/33c572ef-2736-61f4-7093-640423a7ed3b.png)

###うまくいかない理由
よくよく見ますと、参考したサンプルコードは「AWS SDK for .NET を使用したオブジェクトのアップロード」とのことで、Lambdaについて一言も言っていない。。。
使っているメソッドも

``` C#
PutObjectResponse response2 = client.PutObject(request); 
```
なので、PutObjectAsyncではないです。そもそもAWSSDK.S3パッケージのAmazonS3ClientクラスにPutObjectメソッドが存在しませんでした。
なぜそうなのか調べてみたが、どこにも書いていないため、
非同期前提で設計されていると勝手に解釈しています。

#もう一度S3と連携
``` C#
using System;
using System.Threading.Tasks;

using Amazon.Lambda.Core;
using Amazon.S3;
using Amazon.S3.Model;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

namespace AWSLambdaSample
{
    public class Function
    {
        /// <summary>
        /// A simple function that takes a string and does a ToUpper
        /// </summary>
        /// <param name="input"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task<string> FunctionHandler(string input, ILambdaContext context)
        {
            AmazonS3Client client = new AmazonS3Client(Amazon.RegionEndpoint.APNortheast1);

            PutObjectRequest request = new PutObjectRequest()
            {

                BucketName = "databucket-rest-datasource",
                Key = "hello.txt",
                ContentType = "text/plain",
                ContentBody = "Hello World!"
            };
            try {
                await client.PutObjectAsync(request);
                return "OK";
                
            } catch (Exception e) {
                return e.ToString();
            }
        }
    }
}
```
ハンドラーを非同期にして、もう一度Publish
同じ手順でLambdaを実行しますと、今度はファイルが作成されました。
![okimage.png](https://qiita-image-store.s3.amazonaws.com/0/191079/666883b8-81b0-8e44-b0c5-1cfa43560310.png)