C# Programming

ImageHTML POST (同期と非同期パターン)

開発環境: Visual Studio 2003 

1.目次

  1. 目次
  2. 目的
  3. 参考書
  4. 同期 HTML POST アクセスパターン
  5. 非同期 HTML POST アクセスパターン
  6. ソースコード

2.目的

Web アクセス時の POSTの方法を同期、非同期でそれぞれまとめました。
非同期は、マニュアルもタコだし、いいページもないしで、備忘録が必要なのでメモっています。

3.参考書

  1. GotDotNet サンプル: ”タスクの例 : POST 要求を作成する”

4.同期 HTML POST アクセスパターン

郵政公社の郵便番号検索ページは POST で作られています。
次のサンプルは、郵便番号から住所を検索する POST 処理を同期で行う場合のサンプルコードです。

同期で POST する場合のパターン
using System;
,,,,
using System.Diagnostics;
using System.Net;
using System.Web;
using System.IO;
using System.Text;
....

        // 郵便番号→住所のためのURL
        private const string Zip2AddressURL = "http://search.post.japanpost.jp/7zip/zip.cgi";

        private void Post()
        {
            System.IO.Stream  stream = null;
            System.IO.StreamReader sr = null;
            try 
            {
                System.Net.WebRequest webReq = HttpWebRequest.Create( Zip2AddressURL );
                webReq.Method = "POST"; 
                // 1秒でタイムアウトさせる。
                webReq.Timeout = 1000; 
                // IE のProxy 設定を使用する。
                webReq.Proxy = System.Net.WebProxy.GetDefaultProxy();
                // デフォルトのコンテントタイプ
                webReq.ContentType = "application/x-www-form-urlencoded"; 
                // POST パラメータを書く。

                // 正確なパラメータを渡すために HttpUtility.UrlEncode()でエンコードする。
                string parameters = "mode=search&start=0&end=400&keyword=";
                parameters += HttpUtility.UrlEncode( "111-");
                parameters += "&new=on";

                // Ascii なので、エンコーディングは指定する必要なし。
                Stream reqStream = webReq.GetRequestStream();
                StreamWriter sw = new StreamWriter(reqStream);
                sw.Write(parameters);
                sw.Close();

                // 結果を受け取る。
                WebResponse webRes = webReq.GetResponse();
                // HttpWebRequest からストリームを取得する。
                stream = webRes.GetResponseStream();
                // SHIFT JIS で読み取る。
                sr = new StreamReader(stream, Encoding.GetEncoding("SHIFT-JIS"));
                String str = null;
                
                str = sr.ReadToEnd();
                Debug.WriteLine( str );
            } 
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
            }
            finally
            {
                if (sr != null) sr.Close();
                if (stream != null) stream.Close();
            }
        }

5.非同期 HTML POST アクセスパターン

1から書こうとするとはまるんですよねぇ。。。
郵政公社の郵便番号検索ページは POST で作られています。
次のサンプルは、郵便番号から住所を検索する POST 処理を非同期で行う場合のサンプルコードです。

非同期で POST する場合のパターン
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using System.IO;
using System.Net;
using System.Web;
using System.Diagnostics;
using System.Threading;
....

        // 郵便番号→住所のためのURL
        private const string Zip2AddressURL = "http://search.post.japanpost.jp/7zip/zip.cgi";

        public void WriteCallBack(IAsyncResult ar)
        {
            Debug.WriteLine("WriteCallBack");

            HttpWebRequest req = (HttpWebRequest) ar.AsyncState;

            Encoding enc = System.Text.Encoding.GetEncoding("SHIFT-JIS");
            StreamWriter sw = new StreamWriter(req.EndGetRequestStream(ar), enc);

            // 正確なパラメータを渡すために HttpUtility.UrlEncode()でエンコードする。
            string parameters = "mode=search&start=0&end=400&keyword=";
            parameters += HttpUtility.UrlEncode( "111-");
            parameters += "&new=on";

            sw.Write(parameters);
            sw.Close();
            
            Debug.WriteLine("WriteCallBack End");
        }

        public void ReadCallBack(IAsyncResult ar)
        {
            Debug.WriteLine("ReadCallBack");

            HttpWebRequest req = (HttpWebRequest) ar.AsyncState;
            HttpWebResponse response = (HttpWebResponse) req.EndGetResponse(ar);

            Encoding enc = System.Text.Encoding.GetEncoding("SHIFT-JIS");
            StreamReader sr = new StreamReader(response.GetResponseStream(), enc);

            string str = sr.ReadToEnd();
            Debug.WriteLine(str);
            sr.Close();
            
            Debug.WriteLine("ReadCallBack End");
        }

        private void Request()
        {
            try
            {
                Debug.WriteLine("Start");
                WebRequest webReq = HttpWebRequest.Create( Zip2AddressURL );
                // 1秒でタイムアウトさせる。
                webReq.Timeout = 1000; 
                // IE のプロキシ設定を使用する。
                webReq.Proxy = System.Net.WebProxy.GetDefaultProxy(); 
                webReq.Method = "POST";
                webReq.ContentType = "application/x-www-form-urlencoded";
                                
                // 非同期要求に対するコールバックを設定します。
                AsyncCallback writeCallBack = new AsyncCallback(this.WriteCallBack); 
                // 非同期で要求します。
                IAsyncResult r = webReq.BeginGetRequestStream(writeCallBack, webReq);

                // 待つ場合
                r.AsyncWaitHandle.WaitOne();
                ///////////////////////////////////////////////


                // 非同期要求に対するコールバックを設定します。
                AsyncCallback readCallBack = new AsyncCallback(this.ReadCallBack); 
                // 非同期で要求します。
                IAsyncResult rAr = webReq.BeginGetResponse(readCallBack, webReq);
                // 待つ場合
                rAr.AsyncWaitHandle.WaitOne();
                while(! rAr.IsCompleted)
                    Debug.Write(".");
                Debug.WriteLine("Finished");
            }
            catch (Exception exc)
            {
                // わかりやすいメッセージに変える。
                throw(new WebException("xxxに接続できませんでした。" + exc.Message));
            }
        }

6.ソースコード

変更履歴
2003/5/26 初版作成 V1.0 同期POST.cs、非同期POST.cs
2004/3/21 タイムアウト値が1000秒になっていたのを修正。>> m_ _ m Unyoraさん
同期POST.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;
using System.Net;
using System.Web;
using System.IO;
using System.Text;

namespace HTMLPost
{
    /// <summary>
    /// Form1 の概要の説明です。
    /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button button1;
        /// <summary>
        /// 必要なデザイナ変数です。
        /// </summary>
        private System.ComponentModel.Container components = null;

        public Form1()
        {
            //
            // Windows フォーム デザイナ サポートに必要です。
            //
            InitializeComponent();

            //
            // TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
            //
        }

        /// <summary>
        /// 使用されているリソースに後処理を実行します。
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

                #region Windows Form Designer generated code
        /// <summary>
        /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディタで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(136, 72);
            this.button1.Name = "button1";
            this.button1.TabIndex = 0;
            this.button1.Text = "button1";
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                          this.button1});
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
                #endregion

        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new Form1());
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            Post();
        }

        // 郵便番号→住所のためのURL
        private const string Zip2AddressURL = "http://search.post.japanpost.jp/7zip/zip.cgi";

        // 住所→郵便番号のためのURL(かな検索)
        private const string Address2ZipURL = "http://search.post.japanpost.jp/7zip/kana.cgi";

        private void Post()
        {
            System.IO.Stream  stream = null;
            System.IO.StreamReader sr = null;
            try 
            {
                System.Net.WebRequest webReq = HttpWebRequest.Create( Zip2AddressURL );
                webReq.Method = "POST"; 
                // 1秒でタイムアウトさせる。
                webReq.Timeout = 1000; 
                // IE のProxy 設定を使用する。
                webReq.Proxy = System.Net.WebProxy.GetDefaultProxy();
                // デフォルトのコンテントタイプ
                webReq.ContentType = "application/x-www-form-urlencoded"; 
                // POST パラメータを書く。

                // 正確なパラメータを渡すために HttpUtility.UrlEncode()でエンコードする。
                string parameters = "mode=search&start=0&end=400&keyword=";
                parameters += HttpUtility.UrlEncode( "111-");
                parameters += "&new=on";

                // Ascii なので、エンコーディングは指定する必要なし。
                Stream reqStream = webReq.GetRequestStream();
                StreamWriter sw = new StreamWriter(reqStream);
                sw.Write(parameters);
                sw.Close();

                // 結果を受け取る。
                WebResponse webRes = webReq.GetResponse();
                // HttpWebRequest からストリームを取得する。
                stream = webRes.GetResponseStream();
                // SHIFT JIS で読み取る。
                sr = new StreamReader(stream, Encoding.GetEncoding("SHIFT-JIS"));
                String str = null;
                
                str = sr.ReadToEnd();
                Debug.WriteLine( str );
            } 
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
            }
            finally
            {
                if (sr != null) sr.Close();
                if (stream != null) stream.Close();
            }
        }
    }
}
非同期Post.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using System.IO;
using System.Net;
using System.Web;
using System.Diagnostics;
using System.Threading;


namespace HTMLPutAsync
{
    /// <summary>
    /// Form1 の概要の説明です。
    /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button button1;
        /// <summary>
        /// 必要なデザイナ変数です。
        /// </summary>
        private System.ComponentModel.Container components = null;

        public Form1()
        {
            //
            // Windows フォーム デザイナ サポートに必要です。
            //
            InitializeComponent();

            //
            // TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
            //
        }

        /// <summary>
        /// 使用されているリソースに後処理を実行します。
        /// </summary>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null) 
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

                #region Windows Form Designer generated code
        /// <summary>
        /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
        /// コード エディタで変更しないでください。
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Location = new System.Drawing.Point(120, 56);
            this.button1.Name = "button1";
            this.button1.TabIndex = 0;
            this.button1.Text = "button1";
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                          this.button1});
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
                #endregion

        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main() 
        {
            Application.Run(new Form1());
        }

        private void button1_Click(object sender, System.EventArgs e)
        {
            Request();
        }

        // 郵便番号→住所のためのURL
        private const string Zip2AddressURL = "http://search.post.japanpost.jp/7zip/zip.cgi";

        public void WriteCallBack(IAsyncResult ar)
        {
            Debug.WriteLine("WriteCallBack");

            HttpWebRequest req = (HttpWebRequest) ar.AsyncState;

            Encoding enc = System.Text.Encoding.GetEncoding("SHIFT-JIS");
            StreamWriter sw = new StreamWriter(req.EndGetRequestStream(ar), enc);

            // 正確なパラメータを渡すために HttpUtility.UrlEncode()でエンコードする。
            string parameters = "mode=search&start=0&end=400&keyword=";
            parameters += HttpUtility.UrlEncode( "111-");
            parameters += "&new=on";

            sw.Write(parameters);
            sw.Close();
            
            Debug.WriteLine("WriteCallBack End");
        }

        public void ReadCallBack(IAsyncResult ar)
        {
            Debug.WriteLine("ReadCallBack");

            HttpWebRequest req = (HttpWebRequest) ar.AsyncState;
            HttpWebResponse response = (HttpWebResponse) req.EndGetResponse(ar);

            Encoding enc = System.Text.Encoding.GetEncoding("SHIFT-JIS");
            StreamReader sr = new StreamReader(response.GetResponseStream(), enc);

            string str = sr.ReadToEnd();
            Debug.WriteLine(str);
            sr.Close();
            
            Debug.WriteLine("ReadCallBack End");
        }

        private void Request()
        {
            try
            {
                Debug.WriteLine("Start");
                WebRequest webReq = HttpWebRequest.Create( Zip2AddressURL );
                // 1秒でタイムアウトさせる。
                webReq.Timeout = 1000; 
                // IE のプロキシ設定を使用する。
                webReq.Proxy = System.Net.WebProxy.GetDefaultProxy(); 
                webReq.Method = "POST";
                webReq.ContentType = "application/x-www-form-urlencoded";
                                
                // 非同期要求に対するコールバックを設定します。
                AsyncCallback writeCallBack = new AsyncCallback(this.WriteCallBack); 
                // 非同期で要求します。
                IAsyncResult r = webReq.BeginGetRequestStream(writeCallBack, webReq);

                // 待つ場合
                r.AsyncWaitHandle.WaitOne();
                ///////////////////////////////////////////////


                // 非同期要求に対するコールバックを設定します。
                AsyncCallback readCallBack = new AsyncCallback(this.ReadCallBack); 
                // 非同期で要求します。
                IAsyncResult rAr = webReq.BeginGetResponse(readCallBack, webReq);
                // 待つ場合
                rAr.AsyncWaitHandle.WaitOne();
                Debug.WriteLine("Finished");
            }
            catch (Exception exc)
            {
                // わかりやすいメッセージに変える。
                throw(new WebException("xxxに接続できませんでした。" + exc.Message));
            }
        }
    }
}