ASP.NET+Access 安定稼働に向けて奮闘
Access帳票元データはSQL Server 2012 EXPRESSに有ってAccessからODBC接続でリンクテーブルを作成して取り出している。Accessのみの帳票テストでは全く問題ないのだが、ASP.NETから COMのAccessアプリケーションで実行すると、何故か不安定で失敗する。ODBC接続に問題有りと判断した。
帳票データは ODBC不調のためAccessのテーブルに変更
Access単体であればODBC接続のリンクテーブルで全く問題ないのだが、ASP.NET+Accessオートメーションを呼び出すとODBC接続が出来ない様だ。イベントビューワにもログが残らない。ODBCの設定をさんざんトライしたがいい加減ハマってしまったのでAccessの実テーブルに方針変更。
SQL ServerからAccessのテーブルにデータを流し込む事は実績はあったのだが、今回Visual Studioのバージョンが上がっている。それにAccessも .mdb の実績しかない。Access 2016 は .accdb。
余談だが、.adpはODBCの設定不要で直接SQL Serverにダイレクト接続出来て非常に重宝していたのだがAccess2010までしか使えない。どういうこと!って言いたい感じ。なんと冷たい仕打ち。
SQL Server から Accessのテーブルにデータ書き込み
ここに accessへの接続方法の歴史が書いてある。非常に良い 重要
ASP.NETからACCESS2007以降(JETエンジンからACEエンジンに変わった)に接続する方法は
OLEDB(aceoledb.dll)から ACEエンジンにアクセスして .accdbにアクセスする。
'///////////////////////////////////////////////////////// ' MDB ACCDB 接続 ACCES2007からJET→ACE '///////////////////////////////////////////////////////// Imports System.Data.SqlClient Imports System.Web.HttpContext Imports System.Data.OleDb Public Function mdbACEcn(ByVal cn, ByVal sv, ByVal db, ByVal usr, ByVal psw) If cn Is Nothing Then cn = New OleDbConnection cn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & "Data source=" & db End If If Not cn.State = ConnectionState.Open Then Try cn.Open() Catch ex As Exception Return -1 End Try End If Return cn End Function
取り合えず接続してみようということで いきなりこれで接続したが下のエラーで駄目
なにやらライブラリーらしきものがインストールされてませんよ とのエラー
Access2016インストール済みでもだめなんかいな~ 2016用の単体の配布パッケージを探したが見つからない。
結局下の 2010 再頒布可能コンポーネントをインストールをしたら接続できた。
「Microsoft Access データベース エンジン 2010 再頒布可能コンポーネント」内のACE.OLEDB.12.0を使う
これでようやくASP.NETからAccessへ接続できた
次にSQL Server から Accessテーブルへのデータの書き出しだが SqlBulkCopy を使ってみたがさすがにAccessへの接続では使用できなかった。下はあまり推奨されない方法だがデータ量そう多くなければ問題ない。
'////////////////////////////////////////////// ' SQL Server → Access SQL ServerとAccessのテーブル名は同一にすること ' SQLTable:SQL Server のテーブル名 ' ds:SQL Server のDATASET ' cn:Accessへの接続 ' ad_mdb: Access用OleDbDataAdapter ' ds_mdb: Access用DATASET ' rw_mdb: Access用DATAROW '////////////////////////////////////////////// Dim ad_mdb As OleDbDataAdapter Dim ds_mdb As DataSet Dim rw_mdb As DataRow Dim cb_mdb As OleDbCommandBuilder Function write2mdb(ByVal SQLTable As String, ByVal ds As DataSet, ByVal cn As OleDbConnection) As Integer If mdb_r(SQLTable, cn) = -1 Then 'Access空読みして追加用に開いて準備 Return -1 End If Dim rw As DataRow Dim i As Integer = 0 Try For Each rw In ds.Tables(0).Rows 'SQL Serverの各行に対して rw_mdb = ds_mdb.Tables(SQLTable).NewRow 'Accessの新行 For i = 0 To ds.Tables(0).Columns.Count - 1 rw_mdb(i) = rw(i) Next ds_mdb.Tables(SQLTable).Rows.Add(rw_mdb) ad_mdb.Update(ds_mdb, SQLTable) 'コマンドビルダーを準備しておかないとエラーとなる Next Catch e As Exception Return -1 End Try End Function '////////////////////////////////////////////// ' mdb_r() '////////////////////////////////////////////// Function mdb_r(ByVal SQLTable As String, ByVal cn As OleDbConnection) As Integer ad_mdb = New OleDbDataAdapter("select * from " & SQLTable, cn) ds_mdb = New DataSet cb_mdb = New OleDbCommandBuilder(ad_mdb) 'write2mdb()のad_mdb.Update(ds_mdb, SQLTable)で必要 Try ad_mdb.Fill(ds_mdb, SQLTable) Catch e As Exception Return -1 End Try Return ds_mdb.Tables(SQLTable).Rows.Count End Function
これでようやくSQL Serverから Accessの帳票用テーブルに書き出しができた。
イベントビューアー システム イベントID 10010 対策
これでAccess帳票用データは準備できたので、いざPDF作成実行!
下の画面キャプチャーのイベントID 10016 については、解決した。これもDCOMのエラーだが直接今回のAccessアプリケーションには関係ないので、対応について後日別のページに投稿予定。
10010エラー、これにはてこづった。というか、とりあえずの策で対応した。エラーの内容は
WEBアプリケーション内でASP.NETの吐いたエラーは
73A4C9C1-D68D-11D0-98BF-00A0C90DC8D9 って何?
検索すると Microsoft Access Application のアプリケーションID らしい。
この 10010エラーはWEBサーバー起動後 一度もWEBサーバーにログオンせずに、今回のCOMアプリケーションを実行すると必ずと言っていいほど発生する。WEBサーバーに一度ログオンすれば、後はWEBサーバーからログアウトしている状態でもこのエラーは発生しない。
ちなみに同時刻にApplication のログにも MSACCESS.EXE のエラーが記録されている
ファイル名を指定して実行 DCOMCNFG(GUI では「コンポーネントサービス」)、ローカルセキュリティポリシー 等 下記サイトなどを参考に何日もトライしたが 「WEBサーバー起動後 必ず1回WEBサーバーにログオンしないと」 10010 エラーは解消されない。いい加減見切りを付けたい心境。
プロセスモニターでWEBサーバーの詳細な動作を確認してみた
どうしても10010解決できないので、マイクロソフトのフリー「プロセスモニター」をインストールして 10010発生時と発生しないときの詳細なWEBサーバーのプロセスを比較してみた。
【 正常時のプロセスモニターのログ 】
下は【 エラー発生時のプロセスモニターのログ 】
C:\Windows\SysWOW64\bcryptprimitives.dll をロード後 次の
C:\Program Files (x86)\Microsoft Office\root\VFS\ProgramFilesCommonX86\Microsoft Shared\OFFICE16\Mso20win32client.dll が実行されない。まったく原因不明。
手詰まり状態なので電源ONで自動ログオンの設定をする
とりあえずWEBサーバーに一度ログオンすれば良さそうなので自動ログオンの設定をした。
WEBサーバー起動で自動ログオンの設定後、ほぼエラー回避できた。
これでもまだ たまに失敗するので、さらに次の対応をした。
スタートアップにACCESSを登録
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\
ここに
“C:\Program Files (x86)\Microsoft Office\root\Office16\MSACCESS.EXE” のショートカットを配置した。
これで、今の所良さそう。
出来がったPDFの表示方法
// 概念として JavaScript を msg として用意して Response.Writeで表示する <SCRIPT language="JavaScript"> <!-- NW=window.open("/XXX.PDF"); NW.focus(); self.blur(); // --> </SCRIPT> Current.Response.Write(msg)
WEB環境のCOMアプリケーションの環境設定は大変だ
Windowsアプリならばこれほどまで大変ではないのかも。
WEBアプリといってもイントラ運用なのでセキュリティ環境をもっと簡単にできないものだろうか。
インターネット用はこれ、イントラ用これ というようにセキュリティ環境を自動で設定できるようなものがあれば助かる。セキュリティはムズイ。
コメント