C# で Googleスプレッドシートにデータを書き出す (Google Sheets API v4)

Google Sheets API v4 と.Net用のライブラリを使ってGoogleスプレッドシートにC#コンソールアプリケーションからデータを書き出します。
営業がExcelでデータを記録していて、だったらアプリ側がGoogleスプレッドシートに書き出せば使いやすいよね、というようなことをやりたかったので。
とりあえず導入メモです。

# 事前準備
[.NET Quickstart | Sheets API | Google Developers](https://developers.google.com/sheets/api/quickstart/dotnet?hl=ja) に書いてある通りの手順でサンプルコードがきちんと動作するところまで進めます。
以下は実際にやった記録。すでに終わっているならスキップ可。
おおよそ上の手順の和訳。操作や画面は変わり得るので参考程度に。

## Google Sheets API を有効化
1. https://console.developers.google.com/start/api?id=sheets.googleapis.com&hl=ja を開いてプロジェクトを作るか選択します。すでに開発で触っていると以下みたいな画面が出ますが初めてだとまた違う内容が出ます。
![Screen Shot 2018-07-02 at 19.34.42-fullpage.png](https://qiita-image-store.s3.amazonaws.com/0/155627/a229ebfd-fa3c-ece0-db4e-d7d5313521a4.png)
2. 無事プロジェクトを選択or作成すると次の画面になります。関係ないのでここはキャンセルで。
![Screen Shot 2018-07-02 at 19.38.04-fullpage.png](https://qiita-image-store.s3.amazonaws.com/0/155627/9e88d84c-affc-f2e3-e436-869971519bcc.png)
3. キャンセルした画面から「OAuth同意画面」を選んでメールアドレスを選んでプロジェクト名は適宜に入力して保存。
![Screen Shot 2018-07-02 at 19.38.16-fullpage.png](https://qiita-image-store.s3.amazonaws.com/0/155627/9f5c3853-1c70-9ef2-b977-d3d77f795195.png)
4. 「認証情報」から「OAuth クライアント ID」を選択
![Screen Shot 2018-07-02 at 19.38.53-fullpage.png](https://qiita-image-store.s3.amazonaws.com/0/155627/2b75dd5e-9114-1aaa-c5fb-f15cd91a4de2.png)
5. 「その他」を選択。名前は何でもいいので入力して作成。
![Screen Shot 2018-07-02 at 19.39.24-fullpage.png](https://qiita-image-store.s3.amazonaws.com/0/155627/a9bbc633-b046-1e9c-be13-ba0e28db2edf.png)
6. 「OAuthクライアント」とモーダルが出てきますがここは関係ないので「OK」で閉じる。
7. 右端のアイコンをクリックしてファイルをDL。「client_secret.json」に名前を変更しておきます。
![Screen Shot 2018-07-02 at 19.48.20-fullpage.png](https://qiita-image-store.s3.amazonaws.com/0/155627/603deba9-436c-2fbd-396b-50353d0df881.png)

## プロジェクトにライブラリを追加
nuget.orgからライブラリを追加します。
VSだったら「表示」->「その他のウィンドウ」->「パッケージマネジャーコンソール」で以下の通りに入力。

```powershell
Install-Package Google.Apis.Sheets.v4
```

## サンプルコードを動かす
1. DLしてきた「client_secret.json」をプロジェクトに追加します。
2. プロパティの「出力ディレクトリにコピー」は「常にコピーする」に変更。
3. [.NET Quickstart](https://developers.google.com/sheets/api/quickstart/dotnet?hl=ja) のサンプルコードをコピペ。

あとは実行すれば動きます。初回はブラウザが立ち上がって、ログインと許可の操作が必要です。
コード中で指定されている通り、credential（認証情報）が個人フォルダの中に「.credentials/sheets.googleapis.com-dotnet-quickstart.json」という形で保存されるのですが不要なので消しておきましょう。


# Googleスプレッドシートにデータを書き出す
## ようやく本題
上のサンプルコードはデータの読み出ししかしません。こちらとしては末尾の行にデータを書き加えたいです。

以下サンプルをちょっといじっただけのコード。データを書き加えたいスプレッドシートのIDを中に入力してください。
事前手順として、
1. 新しいスプレッドシートを作成。ファイル名は何でもいいです、スプレッドシートIDでアクセスするので。
2. スプレッドシートを開いてスプレッドシートIDをコピー。IDはURL内に入っています。
https\://docs.google.com/spreadsheets/d/**ここの文字列**/edit
3. シート名はここでは「Sheet1」に変更
しておきます。

```csharp
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Sheets.v4;
using Google.Apis.Sheets.v4.Data;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;

namespace PlayGround
{
    class Program
    {
        // もしスコープを変えた時は事前にあるcredential（~/.credentials/sheets.googleapis.com-dotnet-quickstart.json）を消すこと
        static string[] Scopes = { SheetsService.Scope.Spreadsheets };
        static string ApplicationName = "Hoge App";

        static void Main(string[] args)
        {
            UserCredential credential;

            // credentialを取得
            using (var stream =
                new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
            {
                string credPath = AppDomain.CurrentDomain.BaseDirectory;
                credPath = Path.Combine(credPath, ".credentials/sheets.googleapis.com-dotnet-quickstart.json");

                credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    Scopes,
                    "user",
                    CancellationToken.None,
                    new FileDataStore(credPath, true)).Result;
                Console.WriteLine("Credentialの保存先: " + credPath);
            }

            // Google Sheets API サービスを作る
            var service = new SheetsService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = ApplicationName,
            });

            // スプレッドシートID
            String spreadsheetId = "コピーしたスプレッドシートID";

            // データを新しい行に書き込む
            var wv = new List<IList<object>>()
            {
                new List<object>{"=ROW()","Bです","日付：", DateTime.Now.ToString()}
            };
            var body = new ValueRange() { Values = wv };
            var req = service.Spreadsheets.Values.Append(body, spreadsheetId, "Sheet1!A1");
            req.ValueInputOption = SpreadsheetsResource.ValuesResource.AppendRequest.ValueInputOptionEnum.USERENTERED;
            var result = req.Execute();

            // 終わり
            Console.WriteLine("書き込み完了");

            Console.Read();
        }
    }
}
```

## 動作結果
![Screen Shot 2018-07-02 at 20.15.16-fullpage.png](https://qiita-image-store.s3.amazonaws.com/0/155627/7ce237a8-997d-2f18-04fc-3587429a3d84.png)


- セルの書き込み先は"Sheet1!A1"です。Appendの場合は宛先セルが埋まっている場合は自動的に下に（末尾に）追加してくれます。
- ValueInputOptionをUSERENTEREDにすると関数を書き込み可。RAWだとそのまま入ります。
- credentialは期限つきですが、アクセス毎に自動で更新してくれるようです。
- サンプルコードと違ってScopeをReadonlyから変えています。Scopeが合っていないcredentialファイルが残ったままコードを変更してもこけるので注意。