FTPでファイルのダウンロードと進行状況の表示
C#のWindows上のフォームから、FTPでファイルをダウンロードする必要があったので、以下で実装しました。
前提条件として、
- ダウンロード中の進行状況の表示
- ユーザによる途中キャンセル
が、ありました。
以下、フォームに
が、貼ってあるものとします。
キャンセルボタンのEnable化などは省略
>|cs|
//ダウンロード中のフラグ
private bool onDownloading = false;
//ダウンロード用のWebClient
private WebClient wc = null;
//ダウンロードボタンクリック
private void downloadButton_Click(object sender, EventArgs e)
{
Uri uri = new Uri("ダウンロード先のパス ftp://example.com/example.txt");
if (wc == null)
{
wc = new WebClient();
//webClientに進行状況、完了時のイベントハンドラを追加
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
}
//ダウンロード開始
wc.DownloadFileAsync(uri, "保存先のローカルパス")
onDownloading = true;
}
//ダウンロードの進歩イベント
private void wc_DownloadProgressChanged(Object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
//完了時のイベント
private void wc_DownloadFileCompleted(Object sender, AsyncCompletedEventArgs e)
{
if ( (e.Error != null) && (!e.Cancelled) )
{
MessageBox.Show("ダウンロード中にエラーが発生しました。内容:" + e.Error.Message, "エラー",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (e.Cancelled)
{
MessageBox.Show("ダウンロードがキャンセルされました。", "完了", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("データのダウンロードが完了しました。", "完了", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
onDownloading = false;
}
//キャンセルボタンクリック
private void cancelButton_Click(object sender, EventArgs e)
{
//ダウンロード中なら、ダウンロードをキャンセルする
if (onDownloading)
{
if (wc != null)
{
wc.CancelAsync();
}
}
}
ClickOnceで困った・・・
過去の遺物だと思っていた「dll hell」の再来か??????
ClickOnceって、内部でどのように動いているのかまで理解していない(もっとも、普通のmsiのセットアップだとて理解出来ていない)が、非常に便利なので、標準で使っている。
特に、修正を行ったとき、「サーバーに上げてお仕舞い!」の手軽さが最高だった。
しかし、本日は、困った。
いつものように、
・バージョン番号を確認して
・発行して
・サーバーに上げて
・テストマシンで、対象アプリを起動すると
・いつものように、アップデートのダイアログが出て
・OKをクリックすると
エラーになった・・・・・・・
詳細ボタンをクリックすると
エラーの詳細
この操作中に次のエラーが検出されました。
* [2014/03/13 10:59:11] System.ArgumentException
- 値が有効な範囲にありません。
- ソース:System.Deployment
- スタック トレース:
場所 System.Deployment.Internal.Isolation.IStore.LockApplicationPath(UInt32 Flags, IDefinitionAppId ApId, IntPtr& Cookie)
場所 System.Deployment.Application.ComponentStore.LockApplicationPath(DefinitionAppId definitionAppId)
場所 System.Deployment.Application.SubscriptionStore.LockApplicationPath(DefinitionAppId definitionAppId)
場所 System.Deployment.Application.FileDownloader.PatchFiles(SubscriptionState subState)
場所 System.Deployment.Application.FileDownloader.Download(SubscriptionState subState)
こんなスタックトレースでは、わからん。
ぐぐっても、
インストールされる
C:\Users\ユーザ名\AppData\Local\Apps\2.0
以下のフォルダを削除しろ!
とか、バカなことしか見つからない。
削除したら、他のClickOnceアプリとデータが吹っ飛ぶでしょうが?
Gitで、以前のアップデートリリース時点まで戻り
再度、ファイルを修正して発行しても同じ。
発行したセットアップファイルに問題があるのか?
インストールしたテストマシンに問題があるのか?
誰か、教えて下さい。
追記
エラーの出るマシンと出ないマシンとがある。
結局は、エラーの出るマシンは、アンインストール、再インストールで対応する。
しかし、データをClickOnceに任せていたら、一緒にアンインストールされるので、データは別なところへ置かないと、気軽にアンインストール出来なくなる。
PCにインストールされているブラウザをC#で自動操縦する
PCにインストールされているブラウザをC#で自動操縦する
まずは、Windowsなのだから、IEはインストールされているとして、
が、インストールされているかを確認する。
方法は、ぐぐった結果レジストリの
HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\
に、[firefox.exe]、[chrome.exe]があれば、インストールされていると判断する。
後は、Nugetで
・Selenium WebDriver
・Selenium WebDriver Support Classes
・Selenium.WebDriver.ChromeDriver
・Selenium.WebDriver.IEDriver
をインストールする。
早速
IWebDriver driver = new ChromeDriver();
driver.Url = "www.example.com";
と、やるとChromeが起動して、指定したURLにアクセスする。
だけど・・・・・
ログを吐くようなコマンドプロンプトのウィンドウも出てくる。
オブジェクトブラウザで見て、
>|cs|
InternetExplorerOptions ieOptions = new InternetExplorerOptions();
InternetExplorerDriverService ieDriverService = InternetExplorerDriverService.CreateDefaultService();
ieDriverService.HideCommandPromptWindow = true;
driver = new InternetExplorerDriver(ieDriverService, ieOptions);
||<
だと出ない
>|cs|
ChromeOptions chromeOptions = new ChromeOptions();
ChromeDriverService chromeService = ChromeDriverService.CreateDefaultService();
chromeService.HideCommandPromptWindow = true;
driver = new ChromeDriver(chromeService, chromeOptions);
||<
で、出ないようになった。
ブラウザに表示されるフォームに自由に値を設定したり、
ボタンをクリックしたり、javascriptの起動と何でも出来る。
これで遠隔操作でもされると、マズいね。
VS2013 と SQL Server Compact 4.0 SP1
[2015/09/29 追記]
Windows10 + VS2015に対して
[2015/04/16 追記]
最後に追記あり
Windows XPが、後1ヶ月のサポートになったので、環境を
「Windows8.1 + IE11 + VS2013」
で、新しく構築。
早速、以前のプロジェクトを読み込んでみたが、いつものVSとは違い
アップグレートウィザードが走らずに普通に読み込めた。
自分は、SQL Server Compactが大のお気に入りで、
クライアントPCで完結するアプリで、DBが必要な場合には
SQL Server Compactで決まり。
以前のプロジェクトのDBテーブルの変更があったので、
VS2013を起動して、[ツール] - [データベースへの接続]を選択したが、
データソースに、SQL Server Compactがない・・・・・・。
こりゃ、別途インストールが必要なのかと思い、
MSのサイトから、SQL Server Compact 4.0 SP1をインストールした。
さて、DBに繋ごうと、[データベースへの接続]を選択したが
「じぇ、じぇ、じぇ・・・!」
相変わらず、データソースがない。
で、ぐぐってみると、
VS2013から、大好きなSQL Server Compactはサポートされないらしい。
MSDN Blog
http://blogs.msdn.com/b/sqlexpress/archive/2011/07/12/introducing-localdb-a-better-sql-express.aspx
ローカルでDB使いたければ、LocalDBを使えと、いうことらしい。
でも、ネット上では、LocalDBは重いとか、配布が大変だとかで
よい評判は聞かない。
(開発者がSQL Serverをターゲットの開発に使うのは良いらしい。)
MSに対して、引き続きVS2013でも、サポートするように嘆願しているらしい。
嘆いていても、はじまらないので、ぐぐってみました。
捨てる神あれば、拾う神ありで、CodePlexで公開されていました。
SQL Server Compact Toolbox
http://sqlcetoolbox.codeplex.com/documentation
これをインストールすると、今までのサーバーエクスプローラとは違うウィンドウが開くが、今までと同じように使える。
これで問題解決かと思いきや、
なんと、
なんと、
セットアップファイルを作成する段階で、
必須コンポーネントのところに、「必要なブートストラップが見つかりません。」と警告が出る。
構わず、セットアップファイルを作るとエラーにはならず作成される。
実行環境にインストールしてみると、案の定
「ファイルまたはアセンブリ 'System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。」
と、エラーになる。
実行環境にユーザ自身で、MSのサイトからインストールしてもらうしかないのか????
で、調べた結果
VS2012 のマシンの
Program Files (x86)\Microsoft SDKs\Windows\v8.0A\Bootstrapper\Packages
にある
SQL Server Compact Edition 4.0
を、
VS2013のマシンの
\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\Bootstrapper\Packages
にコピーしてみた。
とりあえず、これで必須コンポーネントの警告は消えた。
ライセンス的に問題があるのか、現在調査中・・・・・
だれか知りませんか~
追記:
警告は消えたけど、manifestには含まない・・・・・・orz
[2015/04/16 追記]
上記の件が、
Visual Studio 2013 で SQL Server Compact がサポートされない問題に対応 | SHIN-ICHI の技術ブログ
にありましたので、本日追試。
もう一度、
BootStrapを
Windows8 VS2012 → Windows 8.1 VS2013
へコピー。
ClickOnce発行時に、[発行]-[必須コンポーネント]で
SQL Server Compact 4.0 SP1
がチェックできて、警告がないのを確認。
普通に、ClickOnceの発行。
Windows7のクリーンなマシンを用意して、インストールURLへアクセスして、インストールボタンをクリック。
無事に、SQL Server Comact 4.0 SP1がインストールされました。
又、ライセンス的にも問題がないようです。
[2015/09/29 追記]
環境をWindows10 + VS2015をクリーンインストール。
VS2013と同じようにBootStrapをコピーしようとしましたが、Windows8.1とはで入れクトリ構成が違うようで、
C:\Program Files (x86)\Microsoft Visual Studio 14.0\SDK\Bootstrapper\Packages
に、コピーすると、警告が消えました。
[2017/10/05 追記]
VS2017では、Bootstrapsのパスが変わっています。
C:\Program Files (x86)\Microsoft SDKs\ClickOnce Bootstrapper\Packages
にコピーすると警告が消えました。
log4netでformのtextBoxにlogを出力
log4net関連で、備忘録。
WindowsFormに貼り付けたTextBoxに、log4netを使ってLogを出力する。
パクリ元はStackOverflow
何のため?
ユーザに今、何が起こっているのかを知らせる。
プログレスバーは、作業全体のどれくらいが終わっているかのみを表示するが、こちらは、今、何をしているかを表示できる。
log4netのconfig
>|xml
<root>
<level value="INFO"/>
<appender-refref="OutToTextBox1"/>
</root>
||<
public class TextBoxAppender : AppenderSkeleton
{
private TextBox _textBox;
public TextBox AppenderTextBox
{
get
{
return _textBox;
}
set
{
_textBox = value;
}
}
public string FormName { get; set; }
public string TextBoxName { get; set; }
private Control FindControlRecursive(Control root, string textBoxName)
{
if (root.Name == textBoxName) return root;
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, textBoxName);
if (t != null) return t;
}
return null;
}
protected override void Append(log4net.Core.LoggingEvent loggingEvent)
{
if (_textBox == null)
{
if (String.IsNullOrEmpty(FormName) ||
String.IsNullOrEmpty(TextBoxName))
return;
Form form = Application.OpenForms[FormName];
if (form == null)
return;
_textBox = (TextBox)FindControlRecursive(form, TextBoxName);
if (_textBox == null)
return;
form.FormClosing += (s, e) => _textBox = null;
}
_textBox.Invoke((MethodInvoker)delegate
{
_textBox.AppendText(loggingEvent.RenderedMessage + Environment.NewLine);
});
}
}
var textBoxAppender =newTextBoxAppender();
textBoxAppender.TextBoxName="textBox1";
textBoxAppender.FormName="FormXXX";
textBoxAppender.Threshold= log4net.Core.Level.All;var consoleAppender =new log4net.Appender.ConsoleAppender{Layout=new log4net.Layout.SimpleLayout()};varlist=newAppenderSkeleton[]{ textBoxAppender, consoleAppender };
log4net.Config.BasicConfigurator.Configure(list);
||<
以上でファイルに出力するLogをtextBoxにも出力出来た。
log4netでハマった・・・・
Nugetからインストールして、使い回しのconfig取り込んでと、
メチャ簡単なんで使いました。
でも・・・・・・
開発マシンには、キチンとログが出る。
実行環境へインストールすると、何も出ない?????なんで~
出力されないからと、設定ファイルを疑って半日。
もしかして設定ファイルが読み込まれていないのか??????
原因は、
AssemblyInfo.csに
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "./Log4net.Config.xml", Watch = true)]
と、相対パスでlog4netの設定ファイル位置を書いたのだが、
セットアップで、アプリケーションファイルを見ると、
なんと、、、
データファイル(自動)となってました・・・・・・・
↓
↓
↓
含むに変えると、キチンと出力された。
読み込まれないんなら、実行時にファイルがないとエラーになって欲しい。
これだけで、半日ツブした。
はい、バカなのは私です。
怒りをブツけるところがないので、ここへ。