C#でRestSharpを利用する

HttpClientはいろいろあるらしい

外部のRestAPIを実行しようとしたときにC#であればHttpClientを利用するのがいいかと漠然と思っていたのですが、意外と罠が多いことを知りました。

.NETのHttpClientの取り扱いには要注意という話 - Qiita

確かにMSのサイトを見てもそのようにstaticで利用しています。

Create a REST client using .NET Core | Microsoft Docs

First you need an object that is capable to retrieve data from the web; you can use a HttpClient to do that. This object handles the request and the responses. Instantiate a single instance of that type in the Program class inside the Program.cs file.

もちろんDI側でSingletonにして渡せばいいのですが、WebClientを利用するためだけにそうするのもなぁと思いRestSharpを利用することにしました。

RestSharp - Simple REST and HTTP Client for .NET

最初はJavaでも利用していたUnirestを利用しようと思ったのですが、C#ではこちらのほうが人気なようでこちらにしました。

ちょっと引っかかった

このRestSharpはいい感じに利用できるのですが、少し困ったこともありました。RestAPIを実行するときにPostなどのメソッドではJsonをリクエストボディに設定すると思います。

このRestSharpはJsonにしたいオブジェクトを渡せばいい感じにJson文字列にして送信してくれるのですが、この時に利用しているSerealizer/DesirealizerがNewtonsoft.Json.JsonSerializerではないのです。

RestSharp/JsonDeserializer.cs at develop · restsharp/RestSharp

 private object FindRoot(string content)
 {
            object json = SimpleJson.SimpleJson.DeserializeObject(content);

            if (!RootElement.HasValue()) return json;

            if (!(json is IDictionary<string, object> dictionary)) return json;

            return dictionary.TryGetValue(RootElement, out var result) ? result : json;
}

その結果、プロパティ名が変換されず送信先で400エラーとなるという状況になりました。ただ、このJsonSerializerは変更可能なのでNewtonsoft.Json.JsonSerializerに変更してうまく利用できるようになりました。

このJsonSeralizerを変更する方法は下記の説明が分かりやすかったです。

Custom JSON Serializer and JSON Deserializer for RestSharp

おわりに

JavaでもC#でもデフォルトで提供されているライブラリをそのまま利用したいとは思うのですが、痒いところに手が届かないというかちょっとそのままでは大変なことがおおくて同じ機能を実現しているライブラリを探して利用するようにしています。

ただ、最初はどうしてもつまずくことが多くドキュメントに向き合いつつStackOverflowで同じような事象を探しつつすすめることでうまく行ってます。

速習ASP.NET Core 速習シリーズ

速習ASP.NET Core 速習シリーズ

ASP.NET Core2でSQSを利用してみる

AWS SQSをdotnetから利用するためのサンプルを作成しました。

github.com

基本的にはAmazon SQS 例 - AWS SDK for .NETを参照して作成したものです。時間の関係からデッドレターキューについては実装していません。

認証について

認証についてどうしているんだろうと気になったのですが、開発者であれば通常はユーザーディレクトリに.aws/credentialsを作成していると思います。それをAmazonSQSClientを生成するときにFallbackCredentialsFactoryあたりで取得してくれます。

github.com

この辺はJavaのときはwithCredentialsのように認証チェーンを自分で定義したのですが、SQSではよしなに対応してくれるようです。

なお、AWS SDK for .NETでの認証に関するドキュメントはこちらになります。

docs.aws.amazon.com

認証周りは基本的に設定ファイルに記述しないことが前提になるので、ここは重要なところですよね。

SQSへの各処理について

SQSへの各処理については特に困るようなこともなく、普通に実装すればOKでした。Queueメッセージの登録はこんな感じでサクッとできますね。

SQSへのQueueメッセージの登録

        [HttpPost("create")]
        public async Task<string> CreateMessage([FromBody] string message)
        {
            var queue = await QueueUrl.Build(_client,QueueName, _sqsConfigParam.QueueAttributes);
            var request = new SendMessageRequest
            {
                QueueUrl = queue.Value,
                MessageBody = message
            };

            var response = await _client.SendMessageAsync(request);

            if (response.HttpStatusCode == HttpStatusCode.OK)
            {
                var result = new
                {
                    StatusCode = "正常終了",
                    Message = "SQSへメッセージの登録に成功しました。"
                };
                return JsonConvert.SerializeObject(result);
            }
            else
            {
                var result = new
                {
                    StatusCode = "エラー",
                    Message = "SQSへメッセージの登録に失敗しました。"
                };
                return JsonConvert.SerializeObject(result);
            }
        }

終わりに

これまで主にJavaではAWSをよく利用したのですが、dotnetからも同じ感じで利用できそうなので色々と利用していみたいと思います。

ASP.NET Core MVC 2.0でFromBodyに引数が設定されない

以下のようにコントローラーでAPIを作成したときにcurlから引数のmessageへ値を設定することができずハマったのでまとめます。

namespace WebApplication1.Controllers
{
    [Route("api/[controller]")]
    public class SampleController : Controller
    {
         [HttpPost("create")]
        public async Task<string> CreateMessage([FromBody]string message)
        {
            ...
        }
}

最初はJSONで{"message": "hogehoge"}のような記述をしていたが、これだとmessageに値が設定されなかった。

$ curl -d '{"message": "hogehoge"}' -H "Content-type: application/json"  -XPOST localhost:5000/api/sample/create 

結局以下の通りmessageに設定する値を指定すれば良いことがわかったのでめでたしめでたし。

$ curl -d '"value1"' -H "Content-type: application/json"  -XPOST localhost:5000/api/sample/create 

なお、{"code":"xxxxx", "value":"dummy"}のような複数のフィールドに対応させる場合には対象のPOCOを作成してバインドする必要があります。むしろこの方が直感的で分かりやすかったりしますね。