[.NET] ASP.NETでローカルにファイルを自動保存して開かせたい!?

新年早々書くような内容の話ではないが、ちょっと調べたので載せておきます。
今更書くような内容ではないんですけど、、久々のニッチな.NETネタです。。。

今更、ActiveX!?と思われるでしょうが、実はワシのページの中で「ActiveXがインストールされない謎を追え!!」は、
未だにアクセスが絶えません。何かしら皆さんお困りのようです。
今回はそれとは直接関係ありませんが、多少有益な情報も含まれています。
ま、実際自分がやってみて困ったからともいいますが・・・ってことで、はじまり。

タイトルを見ていただければわかると思いますが、何をやりたいのかは
あまり伝わらないかもしれません。やりたいことは、Webアプリケーションで
サーバサイドで生成したファイルをクライアントのローカルフォルダに保存するという話。
ちなみに、自動保存はとダイアログも表示せずに保存処理を行うことをさしています。

何でそんなことせにゃならんの?と思うことでしょう。
私もそう思います・・・。

まぁ、こういうことをどうしてもやりたいというお客様もいらっしゃるということで、
こういうことを実現することがワシらの仕事でもあるので仕方がないことかと。

ブラウザを介するWebアプリケーションはセキュリティ上、ローカルリソースへの
アクセスは出来ないようになっています(これが出来ちゃうと何でもできてしまうので)。
ま、これが出来てしまうのはいわゆるブラウザのセキュリティホールということになります。
(最近ではGoogle ChromeがNative Clientを導入するとかいう話がありましたが、
あれってどうなったんですかね?)

この壁をぶち破るためには、Microsoftの悪しき資産(今となっては)であるActiveXを利用することになります。
まぁ、前からActiveXを使えば出来ると何となく知ってはいましたが、
実際に試したことがなかったので本当にできるのか?という好奇心もあり調べてみました。
(ま、今更ですけどね・・・)

[ゴール]


サーバで生成したファイルをローカルにこっそり保存する。
さらに追加で、保存後にサーバ上の特定のファイルを開く。

[前提]


  • 既存のWebアプリはC#のASP.NET
  • .NET Frameworkのバージョンは2.0
  • ActiveXを使う
  • 保存するファイルはActiveReportで作成したExcelファイル

[実現方式]


元々はサーバ上でExcelファイルを生成してダウンロードダイアログを表示させていましたが、
一旦サーバ上のTemp領域に保存し、そのファイルをActiveXにてユーザのローカルに保存します。

とその前に、ここに至るまでに他に考えた手段について以下に簡単に書いておきます。

[案①:ActiveXオブジェクトの「FileSyetemObject」を使ってどうにかできないか?]
JavaScriptでFileSystemObjectをCreateObjectで生成して、FileCopyメソッドで
できれば簡単に出来るのではないか!?とまず考えました。

しかし、FileSystemObjectは現状のIEではセキュリティが厳しくなり、デフォルトでは
使えなくなっています。使えるようにするためにはレジストリを変更する必要があり、
セキュリティ上かなり問題があるため、あきらめました。

下記のKBにあるレジストリを削除すれば使えるようにすることは出来ると思います。
(すみません。試してません。)

[案②:.NETのWindowsフォーム コントロール ライブラリではどうだ?]
ActiveXもどきと言われる(?)Windowsフォーム コントロール ライブラリで
簡単にできるんじゃないか?と思い調べてみました。
前提条件として当然ではありますが、クライアントに.NET Frameworkが
インストールされている必要があります。

ボタンを1つだけ配置しているようなコントロールを作成し、クリックイベントで
System.IO.File.Copyでファイルをコピーするようなものを作成し、ビルド。
AutoSaveCtrl.dll(適当につけた名前)をASP.NETのアプリをホストするディレクトリの
ルートにコピーし、Default.aspxファイル(とりあえず)に下記のタグを貼り付ける。

<object id=”AutoSaveCtrl” classid=”http:AutoSaveCtrl.dll#AutoSaveCtrl.UserControl1″ height=”500″ width=”500″ VIEWASTEXT />

そったら、実際にアクセスしてみます。

ActiveX_2_1

色々とコントロールが張り付いていますが(汗)、赤で囲ったところがWindowsフォーム
コントロール ライブラリです。で、ボタンクリック・・・すると。

ActiveX_2_2

何か怒られました、セキュリティを緩めてあげないといけないようです。。。
で、どの設定を変えればいいのか?、まだわかっていません。。。
顧客環境では.NET Frameworkを適用するのが難しい可能性があるため、
これ以上はココでは調べないことに。。。

★参考情報

[案③:VB6でActiveXを作る]
本題です。本当はC++で作らないと現状はまずいのですが、、ワシのスキルが足りないため
とりあえず動作確認ということでVB6で作りました。。。
Visual Studio 2008でC++で作ろうとして立ち往生していたのですが、VB6だとアリエナイぐらい
簡単に作れてしまった。。。VB様さまです。もうサポート切れてるけど。。
やってることは、結局FileSystemObjectでCopyFileして、Shell関数でExcelを起動する
だけなんですけどね・・・orz

作成したActiveXをASP.NETで動作するようにしてあげます。

VB6でコンポーネントの発行を行うと、確認用のhtmファイルが生成されます。
こいつの中身をみると以下のObjectタグがあります。こいつをコピーして、
ASP.NETのDefault.aspxに貼り付けてやります。

<OBJECT ID=”usrCtrl”
CLASSID=”CLSID:9679F117-6628-45D9-8D38-7AFEE5DB39F4″
CODEBASE=”AutoSaveAX.CAB#version=1,0,0,0″>
</OBJECT>

このActiveXのメソッドを呼び出すJavaScriptは以下のものです。
ボタンのクリックイベントのメソッドを呼び出しているだけです。

<script type=”text/javascript”>
function loadExcel(){
document.getElementById(“usrCtrl”).Command1_Click();
}
</script>

以上で案③により開発環境で意図する動作をするところまでは確認できました。
次に実際の顧客環境に展開する際に必要となるパッケージ化の作業を行います。

[パッケージ化]


作成したActiveXを配布するためのパッケージ化を行います。
以下の流れで作業を行います。

  1. Cabファイル作成
  2. デジタル証明書の作成
  3. デジタル署名

①Cabファイル作成
Microsoft Visual Studio 6.0ツールのディストリビューション ウィザードを使って作成します。

  1. 起動したらプロジェクトファイルを選択し、「パッケージ」ボタンをクリック
  2. 「ディストリビューション ウィザード – パッケージスクリプト」でパッケージを選択(無ければ適当な名前をつけて作成)し、「次へ」をクリック
  3. 「ディストリビューション ウィザード – パッケージの形式」で「インターネット パッケージ」を選択し、「次へ」をクリック
  4. 「ディストリビューション ウィザード – パッケージフォルダ」でフォルダを指定し「次へ」をクリック
  5. 「ディストリビューション ウィザード – 含まれるファイル」で、そのまま「次へ」をクリック
  6. 「ディストリビューション ウィザード – ファイルソース」で、そのまま「次へ」をクリック
  7. 「ディストリビューション ウィザード – 安全性設定」で「スクリプト化の安全性保持」および「初期化の安全性保持」を「はい」に変更し、「次へ」をクリック
  8. 「ディストリビューション ウィザード – 完了!」でスクリプト名を設定し、「完了」をクリック

②オレオレ デジタル証明書の作成
正式にはVeriSignあたりで正式な証明書を取得してください。
ここでは動作確認なのでテスト用のオレオレ証明書を作ります。

調査中
(ここはありものの「コード署名」するためのテスト用の証明書をもらいました。。)

作成した証明書をデジタル署名するPCにインストールし、「信頼されたルート証明書機関」に
等されていることを確認してください。

③デジタル署名
.NET Framework SDK等に入っている「signtool.exe」で署名します。
「-t」オプションでオレオレ証明書を指定しています。

signtool sign /f test.pfx /t http://timestamp.verisign.com/scripts/timstamp.dll AutoSaveAX.CAB

実行すると以下のメッセージが表示され、署名完了です。

Done Adding Additional Store
Successfully signed and timestamped: AutoSaveAX.CAB

作成したCabファイルをASP.NETの仮想フォルダに配置して準備完了です。

[ActiveXのインストール]


開発機以外でちゃんと動くかどうか確認します。

しかーし!!

いざ、インストールしてもなぜかインストールされず。
画面を更新するたびに「インストールしますか?」と聞かれるし・・・
何度繰り返しても同じ。。。

途方にくれていると・・・

C:Documents and SettingsXXXXLocal SettingsTemporary Internet Files
に何やらファイル(下記のファイル名)が出力されており。見てみると何やらエラーが出力されているではないですか!

?CodeDownloadErrorLog!name={9679F117-6628-45D9-8D38-7AFEE5DB39F4}

尚、IEのキャッシュは削除しておかないと、このファイルを見つけるのが大変なので、
事前にキャッシュをクリアしておくことをお勧めします。
実際にActiveXがインストールできない場合にも同様にエラーが出ている可能性もありますので、
うまくインストールされない場合には要チェックです。

*** Code Download Log entry (06 Jan 2010 @ 20:07:55) ***
Code Download Error: (hr = 800c0300) Unknown Error!!
Operation failed. Detailed Information:
CodeBase: http://192.168.0.7/AutoSave/AutoSaveAX.CAB
CLSID: {9679F117-6628-45D9-8D38-7AFEE5DB39F4}
Extension:
Type:

LOG: Item AutoSaveAX.ocx being processed.
— Detailed Error Log Follows —
LOG: Download OnStopBinding called (hrStatus = 0 / hrResponseHdr = 0).
LOG: Item AutoSaveAX.ocx being processed.
LOG: Item scrrun.dll being processed.
ERR: INF Processing: Failed (800c0300) processing: scrrun.dll
. Cannot get primary/default language!LOG: URL Download Complete: hrStatus:0, hrOSB:800c0300, hrResponseHdr:0, URL:(http://192.168.0.7/AutoSave/AutoSaveAX.CAB)
LOG: Reporting Code Download Completion: (hr:800c0300 (FAILED), CLASSID: 9679f117…, szCODE:(http://192.168.0.7/AutoSave/AutoSaveAX.CAB), MainType:(null), MainExt:(null))

出力されているエラーコード「800c0300」あたりでググっていくと・・・ありました。

実行時エラー:429 ActiveXコンポーネントはオブジェクトを作成できません。 – 教えて!goo

どうも「scrrun.dll」が古すぎているために、インストール時にエラーとなっているようです。
実際、Cabファイルを生成するのにはVisual Studio 6.0のディストリビューション ウィザードを
使っているため、そのせいかもしれません。

そこで、scrrnjp.dllおよびscrrun.dllあたりを削除して再度Cabファイルを作り直して、
再度インストール!!

ん・・・いつもより長いこと何かやってる!

きたー!!やっとインストールできました。。。
「でも、今更ActiveX」と思うと、現実に引き戻されます。。

[まとめ]
WEBアプリからクライアントのローカルにファイルを保存したい場合は、AjaxとかFlash(Flexとか)なんかを
駆使してもセキュリティ上できませんが、ActiveXを利用すれば確かに出来ます。
しかしながら、IEでしか利用できないことや今後のことを考えると、基本的には
「セキュリティ上、ローカルへのファイル保存は出来ません!」とお断りするべきだと思います。

[参考情報]
あまり精査してませんが、調査中に見たとおぼしきサイト達。

[.NET] ASP.NETでローカルにファイルを自動保存して開かせたい!?

コメントを残す