カテゴリー別アーカイブ: C#

SmtpClientをSSL有効でメール送信する場合の注意点

SmtpClientクラスを用いて、メールを送信するプログラムがあるのだが、
どうもgmailをホストに指定した場合に動作しない。
設定値は以下の通り。

最初は何かしら設定が間違っているのだろうと思ったが、
下記のVBScriptでは問題なく送信ができる。
なので、設定値に間違いはなく、C#コードのコーディングミスと判断し、調査していた。

しかし、どうもミスらしき場所が見つからない。
エラーも「送信できませんでした」以上のことがでず、八方ふさがりとなった。

色々調べて、以下で解決した。

・ポートを465でなく587を用いる。

つまり、18行目あたりを以下のように修正し、問題は解消した。

どうやらこれは.NETの仕様で、
SmtpClientクラスはポート465をサポートしていないのだ。

SmtpClient.EnableSsl プロパティ
How can I send emails through SSL SMTP with the .NET Framework?

言われれば「なんだぁ」だが、VBScriptで送信できたことで、設定値を疑うことが遅れてしまった。
こういうことがあるから、MSDNはよく確認しなくては。

MonoでC#のコンパイル

C#で簡易的なツールを作ったとき、Xamarin Studioとかでコンパイルはできる。
できるが、ソリュージョンとして作るほどのものでもないしなぁ・・・ということが多い。

コマンドからMonoでコンパイルできないかな、と思ったら案の定できることがわかった。

ちなみに、参照追加が必要なコードの場合はオプションで追加できる。
例えば、僕はSystem.Xml.Linqをusingするコードをコンパイルしたかったので、以下のようにした。

何という内容の無さ。

C#でEvernoteアプリを作る

Evernoteは言わずとしてたクラウドメモツールだ。
使い道は人それぞれだが、僕はwebクリップでプログラミング関連のページを保存したり、
2chで面白いと思ったスレやレスを保存したり、
画像スレの画像をページごと保存したり、
ロクでもない使い方をしている。
で、EvernoteはAPIを公開しており、これを使えば誰でもEvernote関連アプリケーションが作成できる。
C#でも公開されており、C#しか使わない僕にも使えた。
テキスト投稿アプリならすぐに作れてしまう程分かりやすい仕組みになっている。
何より日本語化されているのがいい。リファレンスは英語だけど。
備忘の為、0からの使い方を以下にまとめた。

  1. Developer登録をする
    1. https://dev.evernote.com/intl/jp/に行き、「APIを使いはじめる」をクリックする。
    2. APIドキュメントのページが表示されるので、「APIキーを取得」をクリックする。
    3. 申し込みフォームが表示されるので、必要事項を入力する。
      (API権限は作りたいアプリ種類によって選択する。投稿アプリならベーシックアクセスでいいし、既存Noteの編集を行うならフルアクセスが必要。
      とりあえず試すだけならフルアクセスにしておけばいいと思う)
    4. コンシューマーキーとコンシューマーシークレットが発行されるので、メモしておく。
  2. SDKを取得する
    1. APIドキュメントでC#の「SDKをインストール」をクリックする。
    2. Githubのページがでてくるので、右下の「Download ZIP」をクリックし、ソースコードを取得する。
      (勿論クローンでもいいです。お好きな方で)
  3. EvernoteSandbox(開発環境)のアカウントを取得する
    1. EvernoteのAPIはいきなり通常のアカウントに対しては使えず、
      まず開発環境内で動作検証をして、OKだと思ったら本番環境での使用許可を得る、という形になっています。
      開発環境はEvernote社が提供しているので、そのアカウントを取得します。
    2. https://sandbox.evernote.com/で「アカウントを作成」する。
      以下、手順にしたがってアカウントを作成してください。
      このときのアカウントとパスワードは自分のEvernoteアカウントとは全く無関係なものでOKです。
  4. デベロッパトークンを取得する
    1. いちいち自分の環境に対してユーザーIDとパスワードを入力して認証するのは
      面倒ですが、デベロッパトークンを用いることでその作業を省略できます。
    2. ここのページ中段の「サンドボックス用のデベロッパトークンを取得」をクリックする。
    3. 先程取得したSandboxのアカウントとパスワードを入力する。
    4. 「Creat a developer token」とクリックし、表示されたデベロッパトークンをメモする。
  5. Sampleアプリを動かしてみる
    1. 2でダウンロードしたSDKをZIPなら展開し、sample→client内のEvernote.slnをVisualStudioで開く。
    2. SampleAppプロジェクト内のEDAMTest.csを開く。これがサンプルアプリのコードです。
    3. 40行あたりにauthTokenが定義されているので、先程取得したデベロッパトークンに設定してください。
    4. VisualStudio上で実行してください。上手く実行されればsandbox環境内に新規ノートが作成されます。

後はソースを眺めてAPIの仕組みを大まかに把握し、色々変更してみたりして弄ってみてください。
なお、自分のアプリでAPIを利用する場合は、EDAMプロジェクトをビルドしてできた「Evernote.dll」と「Thrift.dll」をコピーし、アプリのプロジェクトのの参照設定に追加してください。
細かい使い方やリファレンスは他のページにまとまっていますので、そちらを参照したほうが良いと思います。
ちなみに、地味に躓くのが認証する所だと思います。
僕は下記のソースを参考にしています。
参考というか、利用させてもらっています。
MITライセンスだからね。本当に感謝しています。
https://github.com/matchy2/EvernoteOAuth
Sandbox上の検証が十分に完了したら、プロダクション用のデベロッパトークンを使って自分の本アカウントEvernoteに使ってもいいし、アクティベートしてコンシューマーキーをプロダクト環境で利用可能にして、一般公開してもいいと思う。
僕が作ったAppも一応このサイトに置いてあります。
クソコードなので中身はあまり見せられません。

InvokeでFormをCloseして、その後すぐに同じFormインスタンスを生成するときの注意点

タイトルが長くなった。
ちなみに検証できないので内容的に間違っているかもしれません。
解決方法も最善解ではないです。
完全に自分の覚え書き用の記事です。

おおまかに言うと、上記のようなコードを実装していた。
InvokeしてるのはこのメソッドがUIスレッドでない別スレッドで実行されるからです。
簡単に言うと「今表示されているSampleFormを閉じて、初期化して再度表示する」という実行内容。

で、これがいざ実行するとハングすることがある。
困ったのは、100%でなく、起こったり起こらなかったりするところである。

form.Show()の直前でブレイクしてデバッグすると、どうやらここでformがDisposeされていることがあるということが分かった。
しかし、// (中略2)や// (中略3)のどこにもformをDisposeする要素がない。
より詳細に見ようと、// (中略2)にブレイクポイントを置いてデバッグしたところ、問題が一切発生しなくなった。

しばらく頭を捻っていたが、ようやく尤もらしい仮説が見つかった。

InvokeされたCloseによるDispose処理が、「form=new SampleForm()」後に実行され、
折角初期化したformがDisposeされてしまった。

シナリオはこうだ。

1)(処理スレッド)CloseをUIスレッドに託す
2)(UIスレッド)formをCloseする
3)(処理スレッド)処理スレッドformを初期化する
4)(UIスレッド)Closeしたことだし、formをDisposeする
5)(処理スレッド)formをShowする

formはDisposeされてるから無理ですよ〜だ。

4が3と5の間に起こると本件が発生する。
そのタイミングは環境の状態によるので、問題が発生したりしなかったりした訳だ。

で、以下のように1行追加して問題は発生しなくなった。

一度たまっている処理(Close含む、ってか多分Closeしかない)を全て実行させればいいのだ。
Mutexを使う等して排他制御をした方が正確だが、バグの温床に成りかねないのでこの方法にした。
ちょっと不安ではあるけど、これで問題なさそうならこれで行こうと思う。

昔「おまじないだ」と言われたApplication.DoEvents()を使うことになるとはなぁ。
ネットで調べたらあまり勧められない方法らしいけど、そこまで必死に直す箇所じゃないからね。仕方ないね。

DataViewでRowFilterを設定する場合の注意点

DataViewはDataTableと似たようなクラスだが、
インスタンス生成時に既にインデックスを貼ってくれていたり、
まぁ色んな違いがある(投げやり)。

で、最近いじっていたあるコードがある。

DataViewにRowFilterを設定し、その後の処理結果によってまた同じ操作を繰り返すというものだ。
(実際のコード上は無限ループにならないようになっています。念のため)
これがやけに時間がかかる。
原因はRowFilterがRowFilterを何度も行ったことだった。

なぜなら理由は単純で、RowFilterが実行された場合、DataViewは内部的にインデックスを設定してしまっているのだ。
インデックスを設定するために毎回全データを取得しに行っているわけで、これでは大変時間がかかる。

で、幸い「// (dvを使った実行内容)」の内容をRowFilterでなく、FindRowsに置き換えることが可能だったので、それでひとまず解決した。
FindRowsメソッドはインデックスを再設定しないのだ。
(参考:http://msdn.microsoft.com/ja-jp/library/bb669089(v=vs.110).aspx

RowFilterで遅くなっている可能性を全く考えておらず、分かるのに時間がかかった。
ぱっと見、プロパティ設定してるだけに見えるからね、仕方ないね。

・・・修正したはいいけど、割と条件分岐が複雑なメソッドなので、テストに時間かかりそう。
(現に実装終わった後にバグを指摘されまくった)

C#で素因数分解(工夫なし)

案の定というか、更新停止していた。

ネタは書きためているのだけど、書き溜めるだけじゃ何もできん。
プログラミングを学んで一番最初に自分で1から作成したのは素因数分解を行うプログラムの作成だった。
ついさっき、そのコードを見つけたのだけど、これが酷すぎる。
見ていられない。
というわけで、ついさっき書きなおしてみたら5分でできた。それも以前のものより段違いにシンプルで速い。
こんなサンプルに意味はないのだけど、なんとなく載せてみる。

全然関係ないけど、最近、SmartWatchのPebbleのアプリ”Simply.js”でjavascriptだけで色々とできることが分かったので、Twitter投稿アプリを作成しようと目論んでる。
・・・javascript単体だと難しそうなのでサーバーにexe置いてjavascriptで叩いて起動、というフローを想定しているんだけど、できるのかなこんなこと。
どうも、プログラム初心者です。

全角半角を区別せずに文字列を比較する。

Dictionary<string,object>のキーについて、ある文字列と全角半角を無視して比較を行おうとしていた。
最初は
Dictionary<string,object> dic=new Dictionary<string,object>(StringComparer.CurrentCultureIgnoreCase);
と設定すればいけるだろうと考えていたが、これでは全角半角は区別してしまうみたいだ。
他のCultureでも同様だ。

仕方ないので、以下のようにやった。

もっと良いやり方があるような気がするのだけど。

DataTableの特定の行を別のDataTableに格納する。

「DataTableのある特定の行を抽出し、その結果を格納したDataTableを作る」という操作が必要になった。

何も悩む所は無いと思ったのだが、意外と何回も失敗し、最終的にカンニングをしたので、備忘録として書き記す。

つまり、DataRowはDataTableに所属するオブジェクトなので、
違うDataTableに追加するには全く新しい行を作成して追加しなくてはいけないということ。

もっとスマートにできないのかな。
わざわざSelectしたものをさらにDataTableにするというのがそもそもスマートじゃないのかもしれない。

DataTableのFindメソッド

仕事上、.NetのDataTableをよく触る。
主キーが設定されている場合はFindメソッドさんを使えば目的の行を取り出せる。

上記は主キーが”5″である行を取得している。

で、このFindメソッドだけど、どうやら引数の末尾のスペースは考慮しないらしい。
つまり、
dt.Rows.Find(“5”)と
dt.Rows.Find(“5 “)
は同じ結果になってしまう。
回避方法は今のところ不明。
DatatableのSelectメソッドも同様でした。
DataTableの情報には末尾空白のものを持たさないように工夫すべきなのかな。

今日の仕事でここで一瞬詰まった。
コード眺めると何の問題もなさそうだし。
デバッグしたらすぐにおかしいことに気がついたけど、
これは実装中は気付かないなぁ。

調べてみたけどあんまり文献がなかった。常識なのかな。
そういえばSQLのwhere句でも似たようなことがあった気がする。
あんまり覚えていないけど。