WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

HttpClient で ASP.NET Web API にアクセス

by WebSurfer 29. September 2019 12:44

Web API に HttpClient を使ってアクセスし、認証トークンを取得して、JSON 形式のデータを POST 送信するサンプルを書きます。

HttpClient で ASP.NET Web API にアクセス

アクセス先の Web API は先の記事「ASP.NET MVC に Web API 追加」に書いたもので、具体的には、Visual Studio 2015 のテンプレートで生成した既存の MVC5 プロジェクトに、別途 Web API プロジェクトを作って必要なパッケージ、コードを追加したものです。

既存の MVC5 プロジェクトは ASP.NET Identity を利用してクッキーベースのユーザー認証を行っています。

追加した Web API のユーザー認証はクッキーベースとするのではなく、Web API で推奨されているトークンベースとしています。

MVC5 側はクッキーベースで、Web API 側はトークンベースで独立して認証が働きます。なお、ユーザ情報はどちらも ASP.NET Identity から得ています。

その他、運用上は SSL の実装は必須ということで、SSL 通信を強制するためのフィルターを追加しています。

HttpClient を使ったアプリから Web API にアクセスするには Microsoft のドキュメント Call a Web API From a .NET Client (C#) で紹介されている Microsoft.AspNet.WebApi.Client を使うのが便利だそうですが、ここではそれは使わないで実装してみました。

基本的には先の記事「HttpClient で WCF サービスを呼出」の実装例とほぼ同じです。

ただし、認証トークンを取得するには、ユーザー情報を application/x-www-form-urlencoded 形式で POST しなければなりませんが、そこのところが上の記事とは異なります。

認証トークンを得るためには、先の記事「ASP.NET Web API の認証」で書きましたように、grant_type, username, password 情報をトークンエンドポイント /Token に POST します。

認証に成功すると access_token, token_type, expires_in, userName, .issued, .expires という情報が JSON 文字列として返ってきます。その中の access_token が認証トークンです。

Web API にアクセスする際は要求ヘッダに Authorization: Bearer に続けて空白一文字+有効な認証トークンを設定してやれば認証が通ります。

認証トークンの取得と JSON 形式のデータを POST 送信する Windows Forms アプリのサンプルコードは以下の通りです。説明はコードの中にコメントで入れましたので、それを見てください。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Net.Http;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

namespace WindowsFormsApplication2
{
    public partial class Form5 : Form
    {
        // socket 浪費防止のため static のして使い回す
        private static HttpClient client;

        private string loginUrl = "トークン要求先 URL";
        private string apiUrl = "Web API の URL";
        private string email = "ユーザー ID";
        private string passsword = "パスワード";
        private int id = 6;
        private string name = "ガッチャマンの息子";

        // 認証トークン
        private string token = "";

        public Form5()
        {
            InitializeComponent();

            if (client == null)
            {
                client = new HttpClient();
            }

            this.textBox1.Text = email;
            this.textBox2.Text = passsword;
            this.textBox3.Text = id.ToString();
            this.textBox4.Text = name;
        }

        // 認証トークンの取得
        private async void button1_Click(object sender, 
                                                EventArgs e)
        {
            if (!string.IsNullOrEmpty(this.token)) return;

            // 認証に必要なユーザー情報は
            // application/x-www-form-urlencoded 形式で POST
            // 送信する。
            // そのために送信するユーザー情報から以下のように
            // Dictionary<string, string> オブジェクトを生成し、
            var param = new Dictionary<string, string>
            {
                { "grant_type", "password"},
                { "username", this.textBox1.Text },
                { "password", this.textBox2.Text }
            };

            // それを引数に FormUrlEncodedContent オブジェクト
            // を生成・初期化して PostAsync で送信する。
            // Content-Type: application/x-www-form-urlencoded
            // は自動的に設定されるとのこと
            var content = new FormUrlEncodedContent(param);
            var response = 
                 await client.PostAsync(this.loginUrl, content);

            // 応答コンテンツを Stream として取得
            using (Stream responseStream = 
                await response.Content.ReadAsStreamAsync())
            {
                // JSON シリアライザの初期化
                var ser = 
                  new DataContractJsonSerializer(typeof(Token));

                // 応答コンテンツを逆シリアル化して C# のオブジ
                // ェクトを取得
                Token auth = 
                         (Token)ser.ReadObject(responseStream);

                // 認証トークンを token フィールドに設定
                this.token = auth.access_token;
            }
        }

        // JSON 形式のデータを POST 送信
        private async void button2_Click(object sender, 
                                                EventArgs e)
        {
            if (string.IsNullOrEmpty(this.token)) return;

            // POST 送信を指定
            var request = 
                new HttpRequestMessage(HttpMethod.Post, apiUrl);

            // POST 送信する JSON 文字列
            string postData = "";

            // Hero オブジェクトを生成しそれを JSON 文字列に
            // シリアライズする
            Hero postHero = new Hero
            {
                Id = int.Parse(this.textBox3.Text),
                Name = this.textBox4.Text
            };

            // シリアライズは DataContractJsonSerializer を使う
            using (MemoryStream stream = new MemoryStream())
            {
                var ser = 
                  new DataContractJsonSerializer(typeof(Hero));
                ser.WriteObject(stream, postHero);
                stream.Position = 0;
                using (var reader = new StreamReader(stream))
                {
                    postData = reader.ReadToEnd();
                }
            }

            // Content-Type: application/json; charset=utf-8 が
            // 要求ヘッダに必要。それを POST 送信する JSON 文字
            // 列と共にここで設定
            request.Content = new StringContent(postData, 
                                            Encoding.UTF8, 
                                            "application/json");

            // 認証トークンを要求ヘッダに設定
            request.Headers.Add("Authorization", 
                                "Bearer " + this.token);

            // JSON 文字列を SendAsync で POST 送信する
            var response = await client.SendAsync(request);

            // 応答コンテンツを Stream として取得
            using (Stream responseStream = 
                await response.Content.ReadAsStreamAsync())
            {
                // JSON シリアライザの初期化
                var ser = new DataContractJsonSerializer(
                                           typeof(List<Hero>));

                // 応答コンテンツを逆シリアル化して C# のオブジ
                // ェクトを取得
                List<Hero> heros = 
                    (List<Hero>)ser.ReadObject(responseStream);

                string result = "";
                foreach (Hero hero in heros)
                {
                    result += string.Format("{0}: {1}\r\n", 
                                            hero.Id, hero.Name);
                }
                this.textBox5.Text = result;
            }
        }
    }

    // 以下のクラス定義を public partial class Form5 : Form の
    // 上に持ってくるとデザイン画面が開かないので注意

    // トークン要求に対し応答として返ってくるデータ
    // access_token, token_type, expires_in は OAuth2 で定めら
    // れているもの。userName は informational。他に .issued,
    // .expires というデータも返ってくるが . がプロパティの識
    // 別子として使えないので以下には設定しない
    [DataContract]
    public class Token
    {
        [DataMember]
        public string access_token { get; set; }

        [DataMember]
        public string token_type { get; set; }

        [DataMember]
        public int expires_in { get; set; }

        [DataMember]
        public string userName { get; set; }
    }

    // Web API に POST 送信するデータ
    [DataContract]
    public class Hero
    {
        [DataMember]
        public int Id { get; set; }

        [DataMember]
        public string Name { get; set; }
    }
}

上記のコードの実行結果がこの記事の上にある画像です。認証トークンを取得した後、Id と Name から作成した JSON 文字列を Web API に POST 送信し、返ってきた JSON 文字列を一番下のテキストボックスに表示したところです。

Tags: ,

Web API

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  December 2019  >>
MoTuWeThFrSaSu
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

View posts in large calendar