SQLの窓

2013年07月26日


まぎらわしい『AdSenseの終了』を知らせる『日本語ページ』

、と巷で評判になってましたが、Google 側がさすがにまずいと思ったらしく、表現が変わっていました。
( つい数時間前まで『AdSenseの終了』)

『Google サイトでの AdSense 掲載終了について』

英語ページに変更すると、いまだに『Sunsetting AdSense』となっていますが、そちらでは『 AdSense on any of your Google Sites』なんで間違う人もいないと思います。実際、Google.com で検索すると、焦点は『Googleサイトでもう収入は得られないのか?』というものでした。でも、日本じゃ騒然とするのも仕方無いですね。

だいたい、Google のドキュメントは、英語ページと日本語ページで違う事も多く、ある英単語に対して時期が違うと違う日本語の単語になっていたりする事もあります。ただ、たいていにおいて、『ん?』となる程度で問題になった事はあまりないでしょうが、今回はさすがに対応したみたいですね(笑)



そう言えば、最後の1文は前は無かったはずです。

『Google サイト以外でお使いの AdSense への影響はなく、通常通りご利用いただけます。』



posted by lightbox at 2013-07-26 16:15 | 記録 | このブログの読者になる | 更新情報をチェックする

2013年07月25日


VS2010(C#) : TKMP.DLL(3.1.2)を使った、『さくらインターネット』用メール送信テンプレート

SkyDrive へ移動


さくらインターネット

現在2アカウント(スタンダード)を運用していますが、この7月(17日)から新規契約の人が容量が 30G => 100G へ増量されています。既存契約者は 9月からとアナウンスされているのですが・・・・なんでやねん。

メールメールアドレスを無制限で作成できます(当然容量内ですが)。
メールボックスの容量を1MBから2048MBまで任意に指定できます。
※ サーバのディスク容量がひっ迫していると、しきい値内であってもメールは届きません。
※ さくらのメールボックス・さくらのレンタルサーバライトプランでは、メールボックスの容量を 1MBから1024M まで 任意に指定できます。
ウェブメール ※ 一応あります( そんなに力を入れてるとは思えないです ) ❸ メーリングリストは10個 コスト 月額500円 レンタルサーバーとしては、さくらのブログの内容が Seesaa ブログの劣化版である事をのぞけば、結構いたれりつくせりだと思っています。 基本仕様一覧 Ruby は 1.8.x なんで、ちょっと古いと思っています。 データベース使用量は、こんなふうに昔から記述されています。
基本的に制限は設けておりませんが、共用データベースサーバでは使用量の目安がございます。
目安以上の容量を使用された場合、他のお客様への影響がでたり、障害が発生した場合、データの復旧が正常に行えない 可能性がございます。
SSL は 共有SSL が使えます。気軽にログイン部分等、暗号化可能です。 CRONの設定数は 5 です
            MailClass mc = new MailClass()
            {
                SmtpServer = "初期ドメイン",
                Port = 587,
                User = "ユーザ名@ドメイン",
                Pass = "パスワード",
                Protocol = AuthenticationProtocols.TLS
            };

            var result = mc.SendMail(
                "宛て先",
                "ユーザ名@ドメイン",
                this.subject.Text,
                this.body.Text,
                null,   // 必要な場合、宛先を日本語で
                null,   // 必要な場合、差出人を日本語で
                (MailClass.MailClassErrorArg _e) =>
                {
                    this.error.Text = _e.Message;
                }
            );
関連する記事

VS2010(C#) : TKMP.DLL(3.1.2)を使った、メール送信テンプレート


posted by lightbox at 2013-07-25 22:09 | VS(C#) | このブログの読者になる | 更新情報をチェックする

2013年07月24日


Trigger Rally(WebGL+Three.js) のコースを無視してひたすら悪路を走りまくる



Bandicam で録画しました。
( 動画も便利ですが、静止画もさらに便利ですね )

WebGL+Three.js なので、Google Chrome で実行しています。Trigger Rally は、Three.js をエンジンとして CoffeeScript で書かれています。

結論から言うと、ヒマつぶしに持ってこいです。

上下矢印キー : 前進・後退
左右矢印キー : ハンドル
スペースキー : ハンドブレーキ
C キー : カメラビューの変更
R キー : リスタート

以上の操作で、ただひたすらにどこまても悪路を走り続ける事ができます。本来は、コースを作ってタイムトライアルをするのですが、コースをカスタマイズしたりデモコース以外を走ったりするには PayPal で 5ドル程度を支払うと可能になります。( イマイチ詳細が良く解りません )

この時、車の種類が2台増えるのですが・・・・あまり面白く無いのでフリーで遊べばいいと思います。( 検証の為に 5ドル払いました )

羽の生えた車を使って大空をグライダー飛行したり、天空のダートコースを走ったりできるのですが・・・たぶんすぐ飽きちゃうと思います。







posted by lightbox at 2013-07-24 22:06 | 記録 | このブログの読者になる | 更新情報をチェックする

Google Chrome を強制終了すると、後で『開いていたページを復元』できますが、ログイン状態も復元してしまいます。



しごく当たり前の事ですが、自宅以外のコンピュータでどこかのサービースへログインしたままシャットダウンまたはログオフしてしまうと、次に Google Chrome を実行した人がそのサービスへのログイン状態のまま作業ができてしまいます。



posted by lightbox at 2013-07-24 09:10 | Google Chrome | このブログの読者になる | 更新情報をチェックする

2013年07月23日


VS2010(C#) : TKMP.DLL(3.1.2)を使った、メール送信テンプレート

SkyDrive へ移動

( TKMP.DLL 同梱 )

久しぶりにメールの処理の検証をしてみようと、最新(周辺)の Microsoft の Framework をチェックしてみたのですが、相変わらず標準的なものはなさそうなので、最新の TKMP.DLL で検証してみました。TKMP.DLL は運用はした事がありませんが、メール送信に非同期処理が無い事を除いて、たいていは間に合いそうな気がします。

しかし、いかに簡単に使えるように設計されていても、メール処理はそれなりに煩雑なので、単に『メール送信』に特化してクラスを作成しました。

メールは Hotmail でなくても使えますが、送信用のクラスを作成する為のテストに Hotmail を使って行い、Hotmail の特性に従ってエラー処理もしています。

Hotmail を使用する場合は、ひとつ注意が必要で、エラーになる原因としてメールサービスがスパム対策として確認用の画像を読ませいログインさせようとする場合があるようです。
MailClass.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TKMP.Writer;
using TKMP.Net;

namespace TKMP_SendMail3
{
    class MailClass
    {
        private MailWriter mw = null;

        public string SmtpServer { get; set; }
        public int Port { get; set; }
        public string User { get; set; }
        public string Pass { get; set; }
        public AuthenticationProtocols Protocol { get; set; }

        private string err_message = "";

        public class MailClassErrorArg
        {
            public string Message { get; set; }
        }

        public delegate void MailClassError(MailClassErrorArg e);

        public bool SendMail(string To, string From, string Subject, string Body, string To_J, string From_J, MailClassError mce)
        {
            bool bResult = true;

            mw = new MailWriter();

            try
            {
                mw.ToAddressList.Add(To);
            }
            catch (Exception ex)
            {
                bResult = false;
            }
            if (!bResult)
            {
                if (mce != null)
                {
                    MailClassErrorArg e = new MailClassErrorArg() { Message = "宛先が正しくありません" };
                    mce(e);
                }
                return bResult;
            }

            // From が未指定や正しくない文字列の場合
            try
            {
                mw.FromAddress = From;
            }
            catch (Exception ex)
            {
                // ユーザが正しければ、以下のように設定しても『ユーザ名 <メールアドレス>』に変換される
                mw.FromAddress = "______@hotmail.co.jp";
            }

            TextPart tp = new TextPart(Body);
            mw.MainPart = tp;

            if (To_J != null)
            {
                mw.Headers.Add("To", To_J + " <" + To + ">");
            }
            else
            {
                mw.Headers.Add("To", To);
            }
            if (From_J != null)
            {
                mw.Headers.Add("From", From_J + " <" + From + ">");
            }
            else
            {
                // Hotmail では、自動的に 『ユーザ名 <メールアドレス>』に変換される
                mw.Headers.Add("From", From);
            }

            mw.Headers.Add("Subject", Subject);
            mw.Headers.Add("X-Mailer", "TKMP Version 3.1.2");

            var logon = new TKMP.Net.AuthLogin(User, Pass);
            SmtpClient sc = new SmtpClient(SmtpServer, Port, logon);
            sc.AuthenticationProtocol = Protocol;

            try
            {
                if (!sc.Connect())
                {
                    err_message = "接続に失敗しました";
                    bResult = false;
                }
                else
                {
                    sc.SendMail(mw);
                    sc.Close();
                }
            }
            catch (Exception ex)
            {
                err_message = ex.Message;
                bResult = false;
            }
            if (!bResult)
            {
                if (mce != null)
                {
                    MailClassErrorArg e = new MailClassErrorArg() { Message = err_message };
                    // このメソッドの引数である、ErrorHandler デリゲートを呼び出す
                    mce(e);
                }
            }

            return bResult;
        }

        public bool SendMail(string To, string From, string Subject, string Body, string To_J, string From_J)
        {
            return SendMail(To, From, Subject, Body, To_J, From_J, null);
        }

        public bool SendMail(string To, string From, string Subject, string Body)
        {
            return SendMail(To, From, Subject, Body, null, null, null);
        }

    }

}

エラー処理は、引数にデリゲートを渡す仕様にしているので、Java の 引数へのインターフェイス渡しのような感じで『ラムダ式』を使ってその場で記述する事を想定しています。

これによって、細かいエラー情報が必要な場合は記述し、そうでない場合はオーバーロードされた引数の少ないメソッドを使って成功が失敗かだけをチェックすればいいようになっています。
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.Mail;
using System.Net;
using TKMP.Writer;
using TKMP.Net;

namespace TKMP_SendMail3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            MailClass mc = new MailClass()
            {
                SmtpServer = "smtp.live.com",
                Port = 587,
                User = "ユーザ名@hotmail.co.jp",
                Pass = "パスワード",
                Protocol = AuthenticationProtocols.TLS
            };

            var result = mc.SendMail(
                "宛先メールアドレス",
                "ユーザ名@hotmail.co.jp",
                this.subject.Text,
                this.body.Text,
                null,   // 必要な場合、宛先を日本語で
                null,   // 必要な場合、差出人を日本語で
                (MailClass.MailClassErrorArg _e) =>
                {
                    this.error.Text = _e.Message;
                }
            );

            if (result)
            {
                MessageBox.Show("メールを送信しました");
            }

        }

    }
}

Hotmail の仕様に関しては、正式には 『アプリから Outlook.com メールを送受信する』というページにある、『POP3 または SMTP をサポートするアプリ』という中にあります

受信 (POP3) サーバー
サーバー アドレス: pop3.live.com
ポート: 995
SSL 暗号化: はい

送信 (SMTP) サーバー
サーバー アドレス: smtp.live.com
ポート: 25 (25 がブロックされている場合は 587)
認証: はい
TLS または SSL で暗号化された安全な接続: はい
ユーザー名: メール アドレス
パスワード: パスワード
一般的にどこのメールサービスでも、TLS または SSL と書かれていますが、TLS で 587、SSL で 465 です。( このへんはかなり仕様がわかり難いです / Microsoft は、TLS のみ。Google は、両方。他は SSL のみだったり ) メッセージのソースの様子 ( ソースは GMail で確認するのが一番良さそうです )
From: =?iso-2022-jp?B?GyRCOjk9UD9NGyhCQg==?= <______@hotmail.co.jp>
To: =?iso-2022-jp?B?GyRCMDhAaBsoQkI=?= <______@gmail.com>
Date: Tue, 23 Jul 2013 20:10:15 +0900
MIME-Version: 1.0
Subject: =?iso-2022-jp?B?GyRCN29MPhsoQg==?=
X-Mailer: TKMP Version 3.1.2
Content-Type: text/plain; charset="iso-2022-jp"
Content-Transfer-Encoding: 7bit

$BK\J8$N(B
$BFbMF(B

Gmail 用テンプレート

コードは同じですが、smtp サーバーが、『smtp.gmail.com(TLS/587)』になります。ユーザは、Hotmail ではメールアドレスでしたが、Gmail では、ユーザ名部分だけで認証します(メールアドレスでもOKなはずです)。

Nifty 用テンプレート

同様に、コードは同じです。smtp サーバーは、『smtp.nifty.com(SSL/465)』になります。ユーザは、NiftyID を使用したメールアドレスを使いますが、From では通常の別名を使用します。

Yahoo 用テンプレート

同様です。smtp サーバーは、『smtp.mail.yahoo.co.jp(SSL/465)』になります。アカウントは、「@yahoo.co.jpより前の部分」となります。

関連する記事

VS2010(C#) : TKMP.DLL(3.1.2)を使った、『さくらインターネット』用メール送信テンプレート


posted by lightbox at 2013-07-23 20:22 | VS(C#) | このブログの読者になる | 更新情報をチェックする

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 投稿


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

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

VS 2010 用のテンプレートです。

SkyDrive へ移動


Twitter API : POST statuses/update_with_media

❶ API 1.1 での URL は、https://api.twitter.com/1.1/statuses/update_with_media.json です。
❷ 認証用のデータは、oauth_* のみ使って、status は使用しません
❸ 日本語投稿部分は、URLエンコードでは無く、UTF-8 で出力します
❹ UI スレッドへのアクセスは、SynchronizationContext を使用しています
❺ カスタムイベントで、投稿結果の JSON を取得します( UI スレッド )

生データをチェックしたい場合、AN HTTPD では、トレースを出力するようにして、http://localhost/test.php を投稿先とし、test.php には OK とのみ書いておきます。

Progress が必要な場合は、wr.AllowWriteStreamBuffering = false; と wr.SendChunked = true; を実行して、ファイルを書き込むループ内で処理するか、そこから外部へのイベントを作成すれば良いと思います。

ここでは、409600 というバッファのサイズにあまり意味はありませんが、どの程度のサイズのファイルのアップロードの Progress をテストするかによって、考慮する必要が出て来ると思います。しかし、実装段階での効率の良いサイズとしては、大きすぎず、小さすぎず程度でいいと思います。

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 LBOX_Tool;
using System.Net;

namespace Twitter_Post_with_Media_test1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.FileName = "";
            ofd.Filter = "JPEG|*.jpg;*.jpeg";
            ofd.FilterIndex = 0;

            if (ofd.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            VS2010_Twitter twitter =
                new VS2010_Twitter(
                    "Consumer key",
                    "Consumer secret",
                    "Access token",
                    "Access token secret"
                );

            twitter.TwitterImageUploadResult += (object _sender, VS2010_Twitter.TwitterImageUploadArgs _e) =>
            {
                this.textBox2.Text = _e.Message;
            };

            twitter.Tweet(this.textBox1.Text, ofd.FileName);

        }
    }
}



VS2010_Twitter.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Net;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace LBOX_Tool
{
    class VS2010_Twitter
    {
        private string _consumer_key;
        private string _consumer_secret;
        private string _token;
        private string _secret;
        private SynchronizationContext sc = null;

        // API 1.1 における最新の URL
        private string _tweet_api = "https://api.twitter.com/1.1/statuses/update_with_media.json";

        // イベント引き渡し用クラス
        private class MyParam
        {
            public WebRequest wr;
            public string image_path;
            public string strBoundary;
            public string text;
        }

        public VS2010_Twitter(
            string consumer_key,
            string consumer_secret,
            string token,
            string secret
            )
        {
            _consumer_key = consumer_key;
            _consumer_secret = consumer_secret;
            _token = token;
            _secret = secret;
        }

        public void Tweet(string text, string path)
        {
            // UI スレッドに戻る為のコンテキスト
            sc = SynchronizationContext.Current;

            // ソートされるリスト
            SortedList<string, string> sl = new SortedList<string, string>();
            sl.Add("oauth_consumer_key", _consumer_key);
            sl.Add("oauth_nonce", Nonce());
            sl.Add("oauth_signature_method", "HMAC-SHA1");
            sl.Add("oauth_timestamp", TimeStamp());
            sl.Add("oauth_token", _token);
            sl.Add("oauth_version", "1.0");
            // 画像投稿では、以上で認証用のデータを作成する( status は使用できない )

            // http ヘッダ用シグネチャ作成
            string work = "";
            foreach (KeyValuePair<string, string> kvp in sl)
            {
                if (work != "")
                {
                    work += "&";
                }
                work += kvp.Key + "=" + kvp.Value;
            }

            string work2 = "";
            // メソッド
            work2 += "POST" + "&";
            // API URL
            work2 += Uri.EscapeDataString(_tweet_api) + "&";
            // Oauth + データ
            work2 += Uri.EscapeDataString(work);

            // OAuth tool チェック用
            Debug.WriteLine(work2);

            string oauth_signature = Signature(work2);

            // ヘッダ情報を作成
            work = "";
            foreach (KeyValuePair<string, string> kvp in sl)
            {
                // oauth_* のみを使用する
                if (work != "")
                {
                    if (kvp.Key.Substring(0, 6) == "oauth_")
                    {
                        work += ", ";
                    }
                }
                if (kvp.Key.Substring(0, 6) == "oauth_")
                {
                    work += kvp.Key + "=" + Dd(kvp.Value);
                }
            }
            // シグネチャを追加( ヘッダーはソートの必要は無い )
            work += ", oauth_signature=" + Dd(Uri.EscapeDataString(oauth_signature));

            // OAuth tool チェック用
            Debug.WriteLine(work);

            // 投稿準備(1)
            string strBoundary = DateTime.Now.Ticks.ToString("x");
            HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create(_tweet_api);
            // 生データをチェックしたい場合
            // HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create("http://localhost/test.php");
            // Progress が必要な場合
            //wr.AllowWriteStreamBuffering = false;
            //wr.SendChunked = true;

            // HttpWebRequest の基本部分の設定
            wr.Method = "POST";
            wr.ContentType = "multipart/form-data; boundary=---" + strBoundary;
            wr.Headers["Authorization"] = "OAuth " + work;

            // ストリームへの書き込みイベント
            AsyncCallback writeCallBack = new AsyncCallback(WriteCallBack);
            MyParam myParam = new MyParam() { wr = wr, image_path = path, strBoundary = strBoundary, text = text };
            // 呼び出し
            IAsyncResult iar1 = wr.BeginGetRequestStream(writeCallBack, myParam);

        }

        // 書き込み
        public void WriteCallBack(IAsyncResult ar)
        {
            HttpWebRequest req = (HttpWebRequest)(ar.AsyncState as MyParam).wr;
            string path = (ar.AsyncState as MyParam).image_path;
            string strBoundary = (ar.AsyncState as MyParam).strBoundary;
            string text = (ar.AsyncState as MyParam).text;

            // 書き込み用のストリーム
            Stream sw = req.EndGetRequestStream(ar);

            // ▼ 以下、Twitter のドキュメントサンプル
            //--cce6735153bf14e47e999e68bb183e70a1fa7fc89722fc1efdf03a917340
            //Content-Disposition: form-data; name="status"
            //
            //Hello 2012-09-07 15:51:41.375247 -0700 PDT!
            //--cce6735153bf14e47e999e68bb183e70a1fa7fc89722fc1efdf03a917340
            //Content-Type: application/octet-stream
            //Content-Disposition: form-data; name="media[]"; filename="media.png"
            //...
            //--cce6735153bf14e47e999e68bb183e70a1fa7fc89722fc1efdf03a917340--

            // 書き込み処理
            Encoding encoding = Encoding.ASCII;
            // セクション(1) / 日本語投稿本文
            Byte[] content = encoding.GetBytes("-----" + strBoundary + "\r\n");
            sw.Write(content, 0, content.Length);

            content = encoding.GetBytes("Content-Disposition: form-data; name=\"status\"\r\n\r\n");
            sw.Write(content, 0, content.Length);

            content = Encoding.GetEncoding("UTF-8").GetBytes(text + "\r\n");
            sw.Write(content, 0, content.Length);

            // セクション(2) / 生バイナリ画像部分
            content = encoding.GetBytes("-----" + strBoundary + "\r\n");
            sw.Write(content, 0, content.Length);

            content = encoding.GetBytes("Content-Type: application/octet-stream\r\n");
            sw.Write(content, 0, content.Length);

            content = encoding.GetBytes("Content-Disposition: form-data; name=\"media[]\"; filename=\"media.jpg\"\r\n\r\n");
            sw.Write(content, 0, content.Length);

            // ファイルのバイナリデータ( バッファサイズの大きさにあまり意味はありません )
            FileStream fs = new FileStream(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);
                sw.Write(file_data, 0, read_size);
                if (read_size < buffer_len)
                {
                    break;
                }
            }
            fs.Close();
            fs.Dispose();

            // multipart の終了
            content = encoding.GetBytes("\r\n-----" + strBoundary + "--\r\n");
            sw.Write(content, 0, content.Length);

            sw.Close();
            sw.Dispose();

            // 最終的なレスポンスの取得
            AsyncCallback readCallBack = new AsyncCallback(this.ReadCallBack);
            IAsyncResult iar2 = req.BeginGetResponse(readCallBack, req);

        }

        // 読み込み
        public void ReadCallBack(IAsyncResult ar)
        {
            string result = "";

            HttpWebRequest req = (HttpWebRequest)ar.AsyncState;
            HttpWebResponse response = null;
            // ここで時々接続が切られたりします 
            try
            {
                response = (HttpWebResponse)req.EndGetResponse(ar);

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

                result = sr.ReadToEnd();
                Debug.WriteLine(result);
                sr.Close();
                sr.Dispose();
            }
            catch (Exception ex)
            {
                result = ex.Message;
                Debug.WriteLine(result);
            }

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

        }

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

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

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

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

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

        // ダブルクォートで挟む
        private string Dd(string base_string)
        {
            return "\"" + base_string + "\"";
        }

        private string Nonce()
        {
            Random rand = new Random();
            int nonce = rand.Next(1000000000);
            return nonce.ToString();
        }

        // タイムスタンプ
        private string TimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        // シグネチャ
        private string Signature(string target)
        {
            string work = _consumer_secret + "&" + _secret;
            byte[] bin = Encoding.UTF8.GetBytes(target);

            HMACSHA1 hmacsha1 = new HMACSHA1();
            hmacsha1.Key = Encoding.UTF8.GetBytes(work);
            byte[] hash = hmacsha1.ComputeHash(bin);

            return Convert.ToBase64String(hash);
        }

    }

}

関連する記事Twitter API 1.1 : POST statuses/update_with_media / 画像付き投稿 -- の注意事項Windows Phone から Facebook に画像アップロード


posted by lightbox at 2013-07-18 04:37 | VS(C#) | このブログの読者になる | 更新情報をチェックする

2013年07月14日


Formアプリ(C#) でFacebookにログインして60日間のアクセストークンを取得して投稿



JSON の処理は行っていませんが、Json.NET がおすすめです

投稿ボタンとテキストエリアは、コントロールの modifiers を public にしているので Form2 より参照可能です。

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 Facebook_POST
{
    public partial class Form1 : Form
    {
        public static string app_id = "App ID";
        public static string app_secret = "App Secret";
        public string url_api = "https://www.facebook.com/dialog/oauth/?redirect_uri=http://www.facebook.com/connect/login_success.html&response_type=token&client_id="+app_id+"&scope=user_about_me,user_photos,read_stream,publish_stream";
        public string access_token = null;
        public Form2 login = null;

        public Form1()
        {
            InitializeComponent();
        }

        // ***************************************************************
        // 投稿
        // ***************************************************************
        private void button1_Click(object sender, EventArgs e)
        {
            VS2010_Facebook facebook =
                new VS2010_Facebook(
                    app_id,
                    app_secret,
                    access_token
                );

            // ただ投稿するだけなら twitter.Tweet(this.textBox1.Text);
            facebook.Post(this.textBox1.Text, (object _sender, UploadStringCompletedEventArgs _e) =>
            {
                if (_e.Error == null)
                {
                    // JSON
                    String stringResult = _e.Result;
                    MessageBox.Show(_e.Result);
                }
                else
                {
                    MessageBox.Show("通信エラーが発生しました。\r\n" + _e.Error.Message);
                }

            });

        }

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



ログインは、WebBrowser コントロールで行います。上の画像では、フォームを親コンテナとしてドッキングしています。実際には、ログイン済みなのかまたは、アクセストークンを保存して使う等の実装が必要ですが、ここでは必ずログインし、ログインが成功する事を前提として、Form1 から投稿を行うようになっています。

Form2.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.Diagnostics;
using System.Net;

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

        public Form2()
        {
            InitializeComponent();
        }

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

        // ***************************************************************
        // 2時間有効なアクセストークンを取得
        // ***************************************************************
        private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            string url = e.Url.ToString();
            if (url.IndexOf("access_token") != -1)
            {
                Debug.WriteLine(url);
                string target_line = url.Substring(url.IndexOf("access_token"));
                string[] separators = new string[1];
                separators[0] = "&";
                string[] part_string = target_line.Split(separators, System.StringSplitOptions.RemoveEmptyEntries);

                Dictionary<string, string> dic = new Dictionary<string, string>();
                separators[0] = "=";
                string[] part_values = null;
                part_values = part_string[0].Split(separators, System.StringSplitOptions.RemoveEmptyEntries);
                dic.Add(part_values[0], part_values[1]);
                part_values = part_string[1].Split(separators, System.StringSplitOptions.RemoveEmptyEntries);
                dic.Add(part_values[0], part_values[1]);

                // 60日間有効なアクセストークンを取得する為の処理
                WebClient webClient = new WebClient();

                webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(get_Token60);
                // 60日間有効なアクセストークンを取得する API
                url = String.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&client_secret={1}&grant_type=fb_exchange_token&fb_exchange_token={2}",
                    Form1.app_id,
                    Form1.app_secret,
                    dic["access_token"]);

                // 呼び出し
                webClient.DownloadStringAsync(new Uri(url));
            }

        }

        // ***************************************************************
        // 60日間有効なアクセストークンを取得
        // ***************************************************************
        private void get_Token60(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                    Debug.WriteLine(e.Error.Message);
            }
            else
            {
                string new_token_line = e.Result;
                Debug.WriteLine(new_token_line);

                string[] separators = new string[1];
                separators[0] = "&";
                string[] part_string = new_token_line.Split(separators, System.StringSplitOptions.RemoveEmptyEntries);

                Dictionary<string, string> dic = new Dictionary<string, string>();
                separators[0] = "=";
                string[] part_values = null;
                part_values = part_string[0].Split(separators, System.StringSplitOptions.RemoveEmptyEntries);
                dic.Add(part_values[0], part_values[1]);
                part_values = part_string[1].Split(separators, System.StringSplitOptions.RemoveEmptyEntries);
                dic.Add(part_values[0], part_values[1]);

                Debug.WriteLine(dic["access_token"]);

                owner.access_token = dic["access_token"];

                WebClient webClient = new WebClient();

                webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(get_UserInfo);
                string url = String.Format("https://graph.facebook.com/me?access_token={0}",
                    dic["access_token"]);

                webClient.DownloadStringAsync(new Uri(url));
            }
        }

        // ***************************************************************
        // ユーザ情報を取得
        // ( 投稿するだけなら必要ありません )
        // ***************************************************************
        private void get_UserInfo(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                    Debug.WriteLine(e.Error.Message);
            }
            else
            {
                Debug.WriteLine(e.Result);

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

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

    }
}


VS2010_Facebook.cs

このクラスは実際には、POST しているだけです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace Facebook_POST
{
    class VS2010_Facebook
    {
        private string _app_key;
        private string _app_secret;
        private string _token;

        private string _tweet_api = "https://graph.facebook.com/me/feed";

        public VS2010_Facebook(
            string app_key,
            string app_secret,
            string token
            ) {
                _app_key = app_key;
                _app_secret = app_secret;
                _token = token;
        }

        public void Post(string text,UploadStringCompletedEventHandler newEvent=null)
        {

            WebClient wc = new WebClient();

            if (newEvent != null)
            {
                wc.UploadStringCompleted += newEvent;
            }

            wc.Headers["Content-Type"] = "application/x-www-form-urlencoded";

            // 投稿
            wc.UploadStringAsync(new Uri(_tweet_api), 
                "POST", 
                "message=" + Uri.EscapeDataString(text) + "&access_token=" + _token ); 

        }
    }
}





posted by lightbox at 2013-07-14 00:12 | VS(C#) | このブログの読者になる | 更新情報をチェックする

2013年07月12日


Live SDK v5.4 : VS2012(C#) + Form アプリ / ファイルアップロード

SkyDrive へ移動( VS2012 用テンプレート )




VS2010 では動作しませんでした。

SkyDrive でアプリを作成して、クライアント ID を取得して使用します。
Form1.cs
using Microsoft.Live;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
	public partial class Form1 : Form
	{
		public LiveAuthClient auth;
		public LiveConnectClient lcc = null;
		private CancellationTokenSource ctsUpload = new CancellationTokenSource();

		public Form1()
		{
			InitializeComponent();
		}

		// ログイン結果より、セッションを作成
		private async void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
		{
			// リダイレクトされた URL の処理
			string url = e.Url.ToString();
			string[] param = url.Split(new string[] { "=", "&" }, StringSplitOptions.None);
			Debug.WriteLine(param);

			// ( テスト的な方法 )
			// リダイレクトされた結果の中で、必要な情報が含まれる処理を対象とする
			if (param[2] == "lc")
			{
				Debug.WriteLine(auth.Session);
				var target = await auth.ExchangeAuthCodeAsync(param[1]);
				Debug.WriteLine(auth.Session);
				// セッションの作成
				lcc = new LiveConnectClient(target);

				// テスト的な情報表示
				Debug.WriteLine(lcc.Session);
				var Result = await lcc.GetAsync("me/skydrive/files");
				Debug.WriteLine(Result.RawResult);

				// アップロード用の参照ボタンを有効にする
				this.button2.Enabled = true;

			}
		}

		// ログイン処理をブラウザ内で行う
		private void button1_Click(object sender, EventArgs e)
		{
			auth = new LiveAuthClient("クライアント ID");
//			auth.IntializeAsync();
			string url = auth.GetLoginUrl(new string[] { "wl.signin", "wl.basic", "wl.skydrive_update" });
			Debug.WriteLine(url);
			// WebBrowser でログイン画面を表示
			this.webBrowser1.Navigate(url);
		}

		// ファイルを参照してアップロード
		private async void button2_Click(object sender, EventArgs e)
		{
			this.openFileDialog1.Filter = "すべて|*.*";
			this.openFileDialog1.FilterIndex = 0;
			DialogResult dr = this.openFileDialog1.ShowDialog();
			if (dr == System.Windows.Forms.DialogResult.OK)
			{
				// 中止ボタンを有効にする
				this.button3.Enabled = true;
				// 選択されたファイルのパス
				string FileName = Path.GetFileName(openFileDialog1.FileName);
				Debug.WriteLine(openFileDialog1.FileName + "をアップロードします");

				// トークンにキャンセル直後の処理を登録
				ctsUpload.Token.Register(() =>
				{
					Debug.WriteLine("キャンセルされました");
				});

				// 経過処理用プライベートクラス
				ProgressUpload pu = new ProgressUpload();
				// アップロードが正常終了した時の戻り値
				LiveOperationResult Result = null;

				// キャンセルすると、WebException が発生
				try
				{
					Result = await lcc.UploadAsync(
						"me/skydrive",
						FileName,
						File.OpenRead(openFileDialog1.FileName),
						OverwriteOption.Overwrite,
						ctsUpload.Token,
						pu
					);
				}
				catch (Exception ex)
				{
					Debug.WriteLine(ex.Message);
				}

				// トークンより、キャンセルを判断
				if (ctsUpload.Token.IsCancellationRequested)
				{
					MessageBox.Show("アップロードはキャンセルされました");
				}
				else
				{
					// 正常終了
					Debug.WriteLine(Result.RawResult);
					MessageBox.Show("アップロードしました");
				}
			}
		}

		// 経過処理用のクラス
		private class ProgressUpload : IProgress<LiveOperationProgress> {
			public void Report(LiveOperationProgress value) {
				Debug.WriteLine(value.ProgressPercentage);
			}
		}

		// キャンセル
		private void button3_Click(object sender, EventArgs e)
		{
			ctsUpload.Cancel();
		}
	}
}

関連する記事

わりと簡単に作れるので、SkyDrive の運用はアプリケーションを作ると便利になると思います。Windows ストアの場合はもっと統合されているのですが、現状では落ちるので使えません。
Windows8 ストアアプリは、年額4900円を払って登録しないと専用の API は使用できません。
Live SDK v5.4 : VS2010 + Windows Phone / 画像アップロード
posted by lightbox at 2013-07-12 19:55 | VS(C#) | このブログの読者になる | 更新情報をチェックする

Live SDK v5.4 : VS2010 + Windows Phone / 画像アップロード

VS2010 で動いたのは、Windows Phone だけでした。Form アプリで動作させるには、VS2012 が必要なようです。( VS2010 で、一部、情報の参照は動いたのですが、アップロードやダウンロードという一番必要なものが落ちました。dll が足らないとか言われます。しかし、VS2012 では同じものが動作しています )

Microsoft のドキュメントは、どれもこれも微妙にウソでした。

my:SignInButton の追加は、コントロールの Toolbox の『Windows Phone コントロール』で右クリックして『アイテムの選択』で、Program Files 内の "Microsoft SDKs\Live\v5.4\Windows Phone 7.1\References\Microsoft.Live.Controls.dll" を読み込んで使います。

というか、そもそも、Windows8 ストアで動かすとログイン完了で落ちます
( Win8 ストアでは、Login する為の単独メソッドがあり、パスワードを間違うとちゃんと反応しますが、ログインがうまく行くと落ちます )
Windows8 ストアアプリは、年額4900円を払って登録しないと専用の API は使用できません。
コード内で使うクラスは、Microsoft.Live.dll を参照します。 Micrsoft のドキュメントでは、同様のものが Windows ストアにもあるような記述がされているのですが、Live SDK v5.4 ではみあたりません。 MainPage.xaml
<phone:PhoneApplicationPage 
    x:Class="PhoneApp2.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True"
    xmlns:my="clr-namespace:Microsoft.Live.Controls;assembly=Microsoft.Live.Controls">

    <!--LayoutRoot は、すべてのページ コンテンツが配置されるルート グリッドです-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock
                x:Name="ApplicationTitle"
                Text="Live SDK v5.4"
                Style="{StaticResource PhoneTextNormalStyle}" />
            <TextBlock
                x:Name="PageTitle"
                Text="画像アップロード"
                Margin="9,-7,0,0"
                Style="{StaticResource PhoneTextTitle1Style}"
                FontSize="40"
                TextWrapping="Wrap" />
        </StackPanel>

        <!--ContentPanel - 追加コンテンツをここに入力します-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <my:SignInButton
                Content="Button"
                Height="101"
                HorizontalAlignment="Left"
                Margin="16,20,0,0"
                Name="signInButton1"
                VerticalAlignment="Top"
                Width="420"
                ClientId="自分のアプリのクライアントID"
                SessionChanged="signInButton1_SessionChanged"
                Scopes="wl.signin wl.basic wl.skydrive_update" />
            <TextBlock
                Height="301"
                HorizontalAlignment="Left"
                Margin="19,127,0,0"
                Name="infoTextBlock"
                VerticalAlignment="Top"
                Width="417"
                FontSize="22"
                TextWrapping="Wrap" />
            <Button
                Content="画像アップロード"
                Height="96"
                HorizontalAlignment="Left"
                Margin="19,434,0,0"
                Name="button1"
                VerticalAlignment="Top"
                Width="417"
                Click="button1_Click"
                IsEnabled="False" />
        </Grid>
    </Grid>
 
    <!--ApplicationBar の使用法を示すサンプル コード-->
    <!--<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>-->

</phone:PhoneApplicationPage>

MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Live;
using Microsoft.Phone.Tasks;
using System.Diagnostics;

namespace PhoneApp2
{
    public partial class MainPage : PhoneApplicationPage
    {

        private LiveConnectClient client;
        private LiveConnectSession session;

        // コンストラクター
        public MainPage()
        {
            InitializeComponent();
        }

        // ****************************************************
        // サインイン・ボタン
        // ****************************************************
        private void signInButton1_SessionChanged(object sender, 
            Microsoft.Live.Controls.LiveConnectSessionChangedEventArgs e)
        {
            if (e.Status == LiveConnectSessionStatus.Connected)
            {
                session = e.Session;
                client = new LiveConnectClient(session);
                infoTextBlock.Text = "サインイン";
                this.button1.IsEnabled = true;
            }
            else
            {
                infoTextBlock.Text = "未接続";
                client = null;
            }
        }

        // ****************************************************
        // 画像アップロードボタン
        // ****************************************************
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            // 画像参照オブジェクト
            var picker = new PhotoChooserTask();
            // 画像参照オブジェクトに選択完了のイベントを登録
            picker.Completed +=
                new EventHandler<PhotoResult>(Image_Selected);
            // 参照開始
            picker.Show();
        }

        // ****************************************************
        // 選択完了のイベント
        // ****************************************************
        private void Image_Selected(object sender, PhotoResult e)
        {
            if (e.Error != null)
            {
                this.infoTextBlock.Text = "画像選択エラー: " + e.Error.ToString();
            }
            else
            {
                // Windows Phone 内部のパスよりファイル名を取得
                //string[] filePathSegments = e.OriginalFileName.Split('\\');
                //string fileName = filePathSegments[filePathSegments.Length - 1];
                // SkyDrive を処理するオブジェクトにイベントを登録
                client.UploadCompleted
                    += new EventHandler<LiveOperationCompletedEventArgs>(Live_UploadCompleted);
                // ****************************************************
                // アップロード開始
                // ****************************************************
                client.UploadAsync("me/skydrive", 
                    "PhotoChooserTask.jpg", 
                    e.ChosenPhoto, 
                    OverwriteOption.Overwrite);
            }
        }

        // ****************************************************
        // アップロード完了
        // ****************************************************
        private void Live_UploadCompleted(object sender, LiveOperationCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                IDictionary<string, object> file = (IDictionary<string, object>)e.Result;
                this.infoTextBlock.Text = "File uploaded. Link: " + file["source"];

                foreach (var key in file.Keys)
                {
                    Debug.WriteLine(string.Format("KEY : {0} => VALUE : {1}", key, file[key]));
                }
                
            }
            else
            {
                this.infoTextBlock.Text =
                    "Error uploading file: " + e.Error.ToString();
            }
        }

    }
}


Windows Phone エミュレータでは、『Pause』キーで、キーボードから英数字が入力可能になります。しかし、US キーボード配置なので、@ は、SHIFT+(2 " ふ) で、_ は、SHIFT+(- = ほ) です。
( CTRL+ でも動作するようです )









アプリは、SkyDrive のページの一番下にある『開発者向け情報(英語)』より登録して、『モバイル クライアント アプリ』を『はい』に設定しておきます。VS2012 で、Form アプリからアクセスする場合もこの設定が必要です。



※ Android でテストした時のアプリをそのまま使っています




posted by lightbox at 2013-07-12 19:00 | Windows Phone | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します


Windows
container 終わり

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

Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
CSS ドロップシャドウの参考デモ
Google Hosted Libraries
cdnjs
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり