Garoon REST API 在席情報更新

背景・実現したいこと

在席情報更新 REST APIを使用して、在席情報の更新を行うプログラムを.NETで作成しているのですが、“415 unsupported media type” が返されてしまいます。

.NETのライブラリが不要なヘッダを追加しているのかと思い、下記curlコマンドで試しても同じ結果でした。どこが問題なのか分かりますでしょうか。

ちなみに、Garoonの動作環境はWindows Server 2019 + IISという構成です。

エラー情報 (開発者ツールのコンソール)

 メディアの種類がサポートされていないため、サーバーが要求を処理できません。

利用したソースコード

curl https://・・・/grn.exe/api/v1/presence/users/code/XXXX -X PATCH
-H 'X-Cybozu-Authorization: X・・・'
-H 'Authorization: Basic X・・・'
-d '{"status": { "code" : "absence" }, "notes" : "From Curl" }'

自己レスです。

curl -vで詳細を表示させると、Content-Typeに’application/x-www-form-urlencoded’が自動で設定されていました。明示的に’Content-Type: application/json’を設定したところ、APIが正常に実行され、在席状態が変更されているのを確認しました。

.NETプログラムはContent-Typeとしてapplication/jsonを指定しているのに、415 unsupported media typeになるのが解せませんが、こちらもトレースして変なヘッダが追加されていないか確認してみます。

またまた、自己レスです。

.NETプログラムでは、Content-Typeに必ず、;charset=… が付いてしまい。これが原因のようです。送信前に、Content-Typeから;charset=… の部分を除くと、キチンと動作しました。

ただ、APIの説明には、ヘッダにContent-Typeは必要無いと書かれているので、Content-Typeがあっても無視して欲しいものです。

ちなみに、.NETのコードはこんな感じです。

string url = $"{RestUrl}api/v1/presence/users/code/{LoginName}";
var _cli = new HttpClient();
_cli.DefaultRequestHeaders.Clear();
_cli.DefaultRequestHeaders.Add("X-Cybozu-Authorization",AuthInfo);
_cli.DefaultRequestHeaders.Add("Authorization",$"Basic {AuthInfo}");
presenceParam prm = new presenceParam() {
    status = new Status() {
        code = Ispresence ? "attend" : "absence"
    },
    notes = Ispresence ? "出社" : "退社"
};
string json = JsonSerializer.Serialize(prm);
var content = new StringContent(json,Encoding.UTF8,"application/json");
// なぜか、Content-Typeにcharset=が付いていると、受け入れられないので、charset無しに変更する。
content.Headers.Clear();
content.Headers.Add("Content-Type","application/json");
var resp = await _cli.PatchAsync(url,content);
if (!resp.IsSuccessStatusCode) {
    throw new HttpRequestException($"at SetPresenceInfo : {resp.StatusCode}{await resp.Content.ReadAsStringAsync()}");
}
・・・
/// <summary>
/// 在席情報更新パラメータ
/// </summary>
public class presenceParam {
    public Status status { get; set; } = null!;
    public string notes { get; set; } = null!;
}
/// <summary>
/// 在席ステータス
/// </summary>
public class Status {
    public string code {get; set; } = null!;
}