SQLの窓

2013年07月18日


VS2010(C#) Form : Google API でログインして Google ドライブにアップロード

ダウンロードする zip は、VS2010 用のテンプレートです

SkyDrive へ移動



ダイアログを表示して、ログインした後ダイアログを閉じて、フォームより画像をアップロードします( 他の種類のファイルをアップロードするには、コードを変更して MIME と拡張子の関係を設定して下さい )

ダイアログ( Form2 ) から Form1 のコントロールを参照できるように、該当するコントロールの modifiers を Public に変更しています。

Client ID と Client secret と Redirect URIs が必要です( APIs Console )

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;

namespace Google_Drive_Upload4
{
    public partial class Form1 : Form
    {
        // *******************************************
        // 以下の3つの static な文字列を設定して下さい
        // *******************************************
        public static string client_id = "";
        public static string client_secret = "";
        // ▼ 登録しているものを設定しないとエラーになります
        public static string redirect_uri = "";

        // ログインで取得する値
        public string access_token = null;
        public string token_type = null;

        // ログインダイアログ
        public Form2 login = null;

        // ここで使用する為に static にしています
        public VS2010_GoogleDrive vgd = new VS2010_GoogleDrive(
                    client_id,
                    client_secret,
                    redirect_uri
        );

        public Form1()
        {
            InitializeComponent();
        }

        // ***************************************************************
        // 投稿
        // ***************************************************************
        private void button1_Click(object sender, EventArgs e)
        {
            // ダイアログを開く準備
            this.openFileDialog1.Filter = "JPEG|*.jpg*;*.jpg";
            this.openFileDialog1.FilterIndex = 0;
            this.openFileDialog1.FileName = "";
            // ダイアログを開く
            DialogResult dr = this.openFileDialog1.ShowDialog();
            if (dr == System.Windows.Forms.DialogResult.OK)
            {
                // 実際は、拡張子によって、MIME を変更する
                vgd.Upload(openFileDialog1.FileName, "image/jpeg", token_type, access_token);
                vgd.GoogleUploadResult += (object _sender, VS2010_GoogleDrive.GoogleUploadArgs _e) =>
                {
                    this.textBox1.Text = _e.Message;
                };
            }
        }

        // ***************************************************************
        // ログインダイアログを開く
        // ***************************************************************
        private void button2_Click(object sender, EventArgs e)
        {
            login = new Form2();
            login.ShowDialog(this);
        }
    }
}

Form2.cs

WebBrowser のみを配置したダイアログです
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Net;
using Newtonsoft.Json.Linq;

namespace Google_Drive_Upload4
{
    public partial class Form2 : Form
    {
        // 親フォーム参照用の変数
        private Form1 owner = null;
        private WebClient webClient = null;

        // アクセストークン取得用の URL
        private string _auth2_url = "https://accounts.google.com/o/oauth2/token";

        public Form2()
        {
            InitializeComponent();
        }

        // ***************************************************************
        // 初期処理
        // ***************************************************************
        private void Form2_Load(object sender, EventArgs e)
        {
            // 初期処理として、親フォーム参照用の変数をセット
            owner = this.Owner as Form1;
            // ログイン用のページを表示
            this.webBrowser1.Navigate(new Uri(owner.vgd.LoginUrl));
        }

        // ***************************************************************
        // code を取得
        // ***************************************************************
        private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            string url = e.Url.ToString();
            if (url.IndexOf("code=") != -1)
            {
                Debug.WriteLine(url);

                // URL に含まれる code を取得する
                int cur = url.IndexOf("=");
                string _code = url.Substring(cur + 1);

                webClient = new WebClient();

                webClient.UploadStringCompleted += new UploadStringCompletedEventHandler(get_token);
                // POST 用
                webClient.Headers["Content-Type"] = "application/x-www-form-urlencoded";

                string param = "";
                param = "code=" + _code;
                param += "&grant_type=authorization_code";
                param += "&redirect_uri=" + Form1.redirect_uri;
                param += "&client_id=" + Form1.client_id;
                param += "&client_secret=" + Form1.client_secret;
                // 呼び出し
                webClient.UploadStringAsync(new Uri(_auth2_url), "POST", param);

            }

        }

        // ***************************************************************
        // 有効なアクセストークンを取得
        // ***************************************************************
        private void get_token(object sender, UploadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                Debug.WriteLine("get_token:" + e.Error.Message);
            }
            else
            {
                string json_string = e.Result;
                Debug.WriteLine(json_string);

                // Json.NET の処理
                JObject data = JObject.Parse(json_string);
                owner.access_token = data["access_token"].ToString();
                owner.token_type = data["token_type"].ToString();

                // 全ての処理が終わったのでメインページへ戻る
                // ( コントロールの modifiers を public にしているので参照可能 )
                owner.button1.Enabled = true;
                owner.textBox1.Enabled = true;

                webClient.Dispose();

                // ダイアログを閉じる
                this.Close();
            }
        }

    }
}


VS2010_GoogleDrive.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Threading;

namespace Google_Drive_Upload4
{
    public class VS2010_GoogleDrive
    {
        private string _client_id;
        private string _client_secret;
        private string _redirect_uri;
        private SynchronizationContext sc = null;

        // ログイン用の URL
        private string loginUrlBase = "https://accounts.google.com/o/oauth2/auth";
        private string responseType = "code";
        // https://developers.google.com/drive/training/drive-apps/auth/scopes?hl=ja
        // https://developers.google.com/drive/v2/reference/files/insert
        private string scope = "https://www.googleapis.com/auth/drive.file+https://www.googleapis.com/auth/drive+https://www.googleapis.com/auth/drive.appdata";

        // アップロード用の URL
        private string upload_url = "https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart";
        //        private string upload_url = "http://localhost/test.php";

        // イベント引き渡し用クラス
        private class MyParam
        {
            public WebRequest web_request;
            public string boundary;
            public string file_path;
            public string content_type;
        }

        public VS2010_GoogleDrive(
            string client_id,
            string client_secret,
            string redirect_uri
            )
        {
            _client_id = client_id;
            _client_secret = client_secret;
            _redirect_uri = redirect_uri;
        }

        // ***************************************************
        // GoogleログインURLを取得する
        // https://developers.google.com/accounts/docs/OAuth2Login
        // ***************************************************
        public string LoginUrl
        {
            get
            {
                string url = loginUrlBase + "?";

                url += "client_id=" + _client_id;
                url += "&response_type=" + responseType;
                url += "&scope=" + scope;
                url += "&redirect_uri=" + _redirect_uri;

                return url;
            }
        }

        // ***************************************************
        // アップロード
        // ***************************************************
        public void Upload(string path, string contentType, string tokenType, string token)
        {
            // UI スレッドに戻る為のコンテキスト
            sc = SynchronizationContext.Current;

            HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(upload_url);
            // 経過処理を可能にする為に、キャッシュをしない設定
            webRequest.AllowWriteStreamBuffering = false;
            webRequest.SendChunked = true;

            webRequest.Method = "POST";

            // 地道なアップロード処理の開始
            string strBoundary = DateTime.Now.Ticks.ToString("x");
            webRequest.ContentType = "multipart/form-data; boundary=" + strBoundary;
            webRequest.Headers.Add("Authorization", tokenType + " " + token);

            AsyncCallback writeCallBack = new AsyncCallback(WriteCallBack);
            MyParam myParam = new MyParam()
            {
                web_request = webRequest,
                boundary = strBoundary,
                file_path = path,
                content_type = contentType
            };

            // 要求開始
            IAsyncResult iar1 = webRequest.BeginGetRequestStream(writeCallBack, myParam);

        }

        // ***************************************************
        // 書き込み
        // ***************************************************
        private void WriteCallBack(IAsyncResult ar)
        {
            HttpWebRequest webRequest = (HttpWebRequest)(ar.AsyncState as MyParam).web_request;
            string strBoundary = (ar.AsyncState as MyParam).boundary;
            // ファイルのパス
            string file_path = (ar.AsyncState as MyParam).file_path;
            // アップロード用のファイル名
            string file_name = Path.GetFileName(file_path);
            string content_type = (ar.AsyncState as MyParam).content_type;

            Stream binWriter = webRequest.EndGetRequestStream(ar);

            //--foo_bar_baz
            //Content-Type: application/json; charset=UTF-8

            //{
            //  "title": "My File"
            //}
            //--foo_bar_baz
            //Content-Type: image/jpeg

            //JPEG data
            //--foo_bar_baz--

            Encoding encoding = Encoding.ASCII;
            Byte[] content = encoding.GetBytes("--" + strBoundary + "\r\n");
            binWriter.Write(content, 0, content.Length);

            content = encoding.GetBytes("Content-Type: application/json; charset=UTF-8\r\n\r\n");
            binWriter.Write(content, 0, content.Length);

            // JSON フォーマットによるファイルの指定
            content = encoding.GetBytes("{\r\n");
            binWriter.Write(content, 0, content.Length);
            // ファイル名は UTF-8 で
            content = Encoding.GetEncoding("UTF-8").GetBytes("  \"title\": \"" + file_name + "\"\r\n");
            binWriter.Write(content, 0, content.Length);
            content = encoding.GetBytes("}\r\n");
            binWriter.Write(content, 0, content.Length);

            content = encoding.GetBytes("--" + strBoundary + "\r\n");
            binWriter.Write(content, 0, content.Length);

            content = encoding.GetBytes("Content-Type: " + content_type + "\r\n\r\n");
            binWriter.Write(content, 0, content.Length);

            // ファイルのバイナリデータ
            FileStream fs = new FileStream(file_path, FileMode.Open);
            int buffer_len = 409600;
            long length = 0;
            int read_size = 0;
            byte[] file_data = new byte[buffer_len];
            while ((read_size = fs.Read(file_data, 0, buffer_len)) > 0)
            {
                length += read_size;
                Debug.WriteLine("writing...." + length);
                binWriter.Write(file_data, 0, read_size);
                if (read_size < buffer_len)
                {
                    break;
                }
            }
            fs.Close();
            Debug.WriteLine("終了");

            content = encoding.GetBytes("\r\n--" + strBoundary + "--\r\n");
            binWriter.Write(content, 0, content.Length);

            binWriter.Close();

            AsyncCallback readCallBack = new AsyncCallback(this.ReadCallBack);
            IAsyncResult iar2 = webRequest.BeginGetResponse(readCallBack, webRequest);

        }

        // ***************************************************
        // 読み込み
        // ***************************************************
        private void ReadCallBack(IAsyncResult ar)
        {
            HttpWebRequest webRequest = (HttpWebRequest)ar.AsyncState;
            HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(ar);

            Encoding enc = System.Text.Encoding.GetEncoding("UTF-8");
            StreamReader streamReader = new StreamReader(response.GetResponseStream(), enc);

            string str = streamReader.ReadToEnd();
            streamReader.Close();

            Debug.WriteLine(str);

            // 内部のイベントの呼び出し( 最終的なイベントを UI スレッドで実行させる )
            sc.Post((object state) => { OnGoogleUploadResult(new GoogleUploadArgs(str)); }, null);

        }

        // ***************************************************
        // カスタムイベント用引数
        // ***************************************************
        public class GoogleUploadArgs : EventArgs
        {
            // 引数の保存エリア
            private string message;
            // コンストラクタ
            public GoogleUploadArgs(string s)
            {
                message = s;
            }

            // 引数取り出し用のプロパティ
            public string Message
            {
                get { return message; }
            }
        }

        // ***************************************************
        // カスタムイベントハンドラの定義 ( EventHandler<T> )
        // ***************************************************
        public event EventHandler<GoogleUploadArgs> GoogleUploadResult;

        // ***************************************************
        // 外部へイベントを発行する為の内部メソッドの定義( virtual )
        // ***************************************************
        protected virtual void OnGoogleUploadResult(GoogleUploadArgs e)
        {
            EventHandler<GoogleUploadArgs> handler = GoogleUploadResult;

            // イベントが外部で実装されている場合、そのイベントを呼び出す
            if (handler != null)
            {
                handler(this, e);
            }
        }
    }
}

コメントの、"http://localhost/test.php" は、生の投稿データを確認する為に使用しています( トレース )

関連する記事

VS2010(C#) Form : POST statuses/update_with_media で画像を伴った Twitter 投稿


【VS(C#)の最新記事】
posted by lightbox at 2013-07-18 22:20 | VS(C#) | このブログの読者になる | 更新情報をチェックする
container 終わり



フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり