C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

NET6用にWebClientをHttpClientに変更

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■100426 / inTopicNo.1)  NET6用にWebClientをHttpClientに変更
  
□投稿者/ latitude (1回)-(2022/08/09(Tue) 10:15:37)

分類:[C#] 

開発環境:Visual Studio Community 2022 / Windows10
使用言語:C# フォームアプリ

はじめまして、こんにちはlatitudeといいます。

プログラムの内容は、
1.WebClient()を使って
2.JSON形式でデータをWebサーバーにGETで投げ
3.結果をJSON形式で受け取る
というもので下記コードで実際に動作しています。


しかし「WebClientは旧形式」と注意がでるのでHttpClientに変更したいです。
これをどう書き換えたら良いのか。
もとのコードの1行の情報量が私には多くて理解できずにいます。
(シンプルなHttpClientの基本的な使い方は理解できたのですが…)

助言いただけると助かります。
よろしくお願いします。



------------------------------------------------------------------------------------
//ソースコード
System.Collections.Generic.Dictionary<string, string> GetToken(System.IO.FileInfo prvKEY, string svACCOUNT, string cID, string cSECRET)
{
    using (var rsa = System.Security.Cryptography.RSA.Create())
    {
        rsa.ImportFromPem(System.IO.File.ReadAllText(prvKEY.FullName));

        var descriptor = new Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor
        {
            Issuer = cID,
            Claims = new System.Collections.Generic.Dictionary<string, object>() { ["sub"] = svACCOUNT},
            SigningCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(new Microsoft.IdentityModel.Tokens.RsaSecurityKey(rsa), "RS256"),
            IssuedAt = System.DateTime.UtcNow,
            Expires = System.DateTime.UtcNow.AddMinutes(60),
        };

        var handler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();
        var pv = new System.Collections.Specialized.NameValueCollection()
        {
            ["assertion"] = handler.WriteToken(handler.CreateJwtSecurityToken(descriptor)),
            ["cID"] = cID,
            ["cSECRET"] = cSECRET,
        };

        //★↓ここの部分を HttpClientを使用したコードに変えたいです
        using (var wc = new System.Net.WebClient())
        {
            var resText = System.Text.Encoding.ASCII.GetString(wc.UploadValues(@"https://xxxxx.xxx/oauth2", pv));
            return System.Text.Json.JsonSerializer.Deserialize<System.Collections.Generic.Dictionary<string, string>>(resText);
        }
    }
}
-----------------------------------------------------------------

引用返信 編集キー/
■100427 / inTopicNo.2)  Re[1]: NET6用にWebClientをHttpClientに変更
□投稿者/ 伝説のカレー (35回)-(2022/08/09(Tue) 11:16:11)
No100426 (latitude さん) に返信
> var resText = System.Text.Encoding.ASCII.GetString(wc.UploadValues(@"https://xxxxx.xxx/oauth2", pv));
> return System.Text.Json.JsonSerializer.Deserialize<System.Collections.Generic.Dictionary<string, string>>(resText);

application/x-www-form-urlencodedでデータをPOST
> wc.UploadValues(@"https://xxxxx.xxx/oauth2", pv)

byte[]をStringに変換
> System.Text.Encoding.ASCII.GetString(...)

JSONをデシリアライズ
> System.Text.Json.JsonSerializer.Deserialize<System.Collections.Generic.Dictionary<string, string>>(resText)


POSTしてレスポンスを取得するだけなのでHttpClientの基本的な使い方の通りで良いと思います
引用返信 編集キー/
■100428 / inTopicNo.3)  Re[1]: NET6用にWebClientをHttpClientに変更
□投稿者/ radian (91回)-(2022/08/09(Tue) 11:34:24)
2022/08/09(Tue) 11:42:00 編集(投稿者)

こちらのページが参考になるのではないでしょうか。

https://qiita.com/rawr/items/f78a3830d894042f891b#%E3%82%AF%E3%82%A8%E3%83%AA%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%82%92%E9%80%81%E3%82%8B

NameValueCollection の部分をDictionary<string, string>にして、
FormUrlEncodedContentでURLエンコードすればいいみたいです。

また、HttpClientクラスはusingで解放せずに、作成したインスタンスを使い回すのが正しい使い方のようです。

https://qiita.com/superriver/items/91781bca04a76aec7dc0
引用返信 編集キー/
■100429 / inTopicNo.4)  Re[1]: NET6用にWebClientをHttpClientに変更
□投稿者/ WebSurfer (2543回)-(2022/08/09(Tue) 12:56:39)
No100426 (latitude さん) に返信

> 2.JSON形式でデータをWebサーバーにGETで投げ

質問のコードでは GET ではなく POST になって、データは assertion=xxx&cID=xxx&cSECRET=xxx というように
application/x-www-form-urlencoded 形式でフォームデータに含まれて送信されるはずです。

その理解で正しければ、以下の記事のコードの「認証トークンの取得」あたりが参考になると思います。

HttpClient で ASP.NET Web API にアクセス
http://surferonwww.info/BlogEngine/post/2019/09/29/call-aspnet-web-api-from-httpclien.aspx

上の記事のコードではデシリアライザに古い DataContractJsonSerializer を使っていますが、そこは質問者さんの
コードのように System.Text.Json 名前空間の JsonSerializer クラスを使ってください。


HttpClient の生成・廃棄を繰り返すと socket の浪費になるという問題がありますので、質問のコードのように
using 句で囲うのは NG ですので注意してください。

上に紹介したコードのように static として使い回すことを考えてください。

または、IHttpClientFactory を利用して HTTP 接続プールを作り、それから HttpClient インスタンスを取得し
てアクセスする方法もあります。WinForms アプリでそこまでやる必要はないかもしれませんが、興味がありまし
たら以下の記事を見てください。

Windows Forms で IHttpClientFactory 利用 (CORE)
http://surferonwww.info/BlogEngine/post/2021/03/12/how-to-use-ihttpclientfactory-in-windows-forms-application.aspx

引用返信 編集キー/
■100430 / inTopicNo.5)  Re[2]: NET6用にWebClientをHttpClientに変更
□投稿者/ latitude (2回)-(2022/08/09(Tue) 16:10:20)
伝説のカレーさん、radianさん、WebSurferさん
皆さま、ありがとうございました。

知識不足すぎて、
アドバイスを理解することと答えを見つけることにかなり時間を要しましたが、
ようやく正常に動くようにできました。
ありがとうございました。

//----------------
public partial class Form1 : Form
{
  public Form1()
  {
    InitializeComponent();
  }
↓↓↓
public partial class Form1 : Form
{
  // socket 浪費防止のため static として使い回す
  private static HttpClient client;
  public Form1()
  {
    InitializeComponent();
    if (client == null)
    {
        client = new HttpClient();
    }
  }
//----------------
GetToken関数をやめてButtonClickに直接書く
//----------------
var pv = new System.Collections.Specialized.NameValueCollection()
↓↓↓
var pv = new System.Collections.Generic.Dictionary<string, string>()
//----------------
using (var wc = new System.Net.WebClient())
{
    var resText = System.Text.Encoding.ASCII.GetString(wc.UploadValues(@"https://xxxxx.xxx/oauth2", pv));
    return System.Text.Json.JsonSerializer.Deserialize<System.Collections.Generic.Dictionary<string, string>>(resText);
}
↓↓↓
var uri = new System.Uri("https://xxxxx.xxx/oauth2");
var context = new System.Net.Http.FormUrlEncodedContent(pv);
var postAsyncResult = await client.PostAsync(uri, context);
var resText = await postAsyncResult.Content.ReadAsStringAsync();
token = System.Text.Json.JsonSerializer.Deserialize<System.Collections.Generic.Dictionary<string, string>>(resText);
//----------------



解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ