- PR -

[Crystal Reports]実行環境が変わるとレスポンスが低下する

投稿者投稿内容
ぺどら
会議室デビュー日: 2006/02/17
投稿数: 14
お住まい・勤務地: かごしま
投稿日時: 2006-02-21 12:19
はじめまして。いつも参考にさせていただいております。
今回、自力での解決が困難な問題が発生したため、皆さんの
お知恵を拝借しようと思い、投稿させていただきました。


--開発環境--

Srv :Windows2003 Server
OS :Windows2000 / XP (最新のパッチ適用済み)
言語:VB.NET 2003
CR :Crystal Reports for Visual Studio .NET

※ソースコード、exe等はすべてサーバ上に保存してあります。


--目的--

複数(約20種類)レポートと、各々のレポートで使用するデータテーブルを
まとめたデータセットの定義を持つDLLを作成し、Windows アプリから
レポート出力を行う際にこのDLLを利用させて、レポートの一元管理を
行いたいと思っています。

--問題点--

上記目的により作成したDLLを使って、本番機でレポート出力を行うと
開発機での出力時よりもレスポンスが低下し、数十秒程待たなければ出力
されません。
開発機と本番機は物理的に離れた場所にあり、同一LAN上にもありません。


ステップ実行にて確認した結果、
レポートのオブジェクトを生成した直後にプロパティ参照や、メソッドの
呼出しを行っている部分で、待機させられました。

その際の通信状況をパケットキャプチャにて確認した結果、
本番機にて実行しているにも関わらず、開発機への参照を試みた形跡があり
ここで、開発機からの応答を待っていたために待機していることが判明しま
した。


--試したこと--

デザイナで確認可能なプロパティや、レポートの定義ファイルを調べました
が、参照先サーバに関する記述は見当たりませんでした。
デザイナにて データベースの照合 や、ConnectionInfoを利用した接続先DB
の変更など試したのですが、改善しませんでした。

海外のサイト(URLは失念しました…)を参考にテーブルをセットする記述を
myReport.SetDataSource([テーブル]) から、
myReport.Database.Tables(0).SetDataSource([テーブル])
に変更しましたが、これでも改善しませんでした。

Windows アプリのレスポンスは変わらなかったので、クリレポ側に原因がある
と思うのですが、どこにも表示されていないので途方に暮れています。


どなたか、似たような事例の対応方法や、参照先サーバを変更する方法
(クリレポ、フレームワーク問わず)等々、皆さんのお知恵を拝借頂けない
でしょうか。

よろしくお願い致します。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-02-21 12:41
引用:

ぺどらさんの書き込み (2006-02-21 12:19) より:

Windows アプリのレスポンスは変わらなかったので、クリレポ側に原因がある
と思うのですが、どこにも表示されていないので途方に暮れています。


ということは、Web アプリケーションですか?

そのサーバーに配置された DataSet の集まりである DLL ですが、これは依存関係にあるものですか?
アセンブリ ローダーがローカル外まで検索しにいく時点で厳格な関係にないように思えるのですが...

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
ぺどら
会議室デビュー日: 2006/02/17
投稿数: 14
お住まい・勤務地: かごしま
投稿日時: 2006-02-21 14:27
じゃんぬねっとさん 返信ありがとうございます。

いきなりの大御所さんからのレスでビックリしています(^^;
じゃんぬねっとさんのサイトには.NETを始めてからかなりお世話になっております。
この場を借りてお礼申し上げます。

引用:

じゃんぬねっとさんの書き込み (2006-02-21 12:41) より:
引用:

ぺどらさんの書き込み (2006-02-21 12:19) より:

Windows アプリのレスポンスは変わらなかったので、クリレポ側に原因がある
と思うのですが、どこにも表示されていないので途方に暮れています。


ということは、Web アプリケーションですか?



いえ。.NET Framework 側に原因があるのであれば、同じソリューションの他の
Windows アプリのレスポンスも悪くなると思うのですが、遅延が発生するのは
DLL 内部での話なので、クリレポ側に原因があるんじゃないか?という考えに至ったわけです。


引用:

そのサーバーに配置された DataSet の集まりである DLL ですが、これは依存関係にあるものですか?



DLL が依存しているのは、今作成中のアプリで使用している共通クラスの他には、
Crystal Reports 絡みのDLLしか心当たりがありません。

引用:

アセンブリ ローダーがローカル外まで検索しにいく時点で厳格な関係にないように思えるのですが...



DLL 参照などでの遅延は発生していません。
具体的なソースは以下のとおりです。

Report() メソッドを呼び出す前に、DLLが持つ型付データセットのテーブルへ
Windowsアプリ側からデータをセットしてから、Report() メソッドを呼び出しています。
その際に、DLLがもつ列挙体へも参照しますし、Report() メソッドを呼び出した直後に
データセットの型を参照すると、遅延なく参照可能です。

# ということは、アセンブリ ローダ的にはこのDLL を問題なくロードできている。
# と、認識しているのですが…。あってますか?

下記ソース中の GetReport() メソッド中にある
コード:
myReport.Database.Tables(0).SetDataSource(dataSource)


のように、オブジェクトに対するメソッド呼出しなどを行ったときに、開発機への参照を行っています。
ここで、数十秒程の 待ち が発生してしまいます。


コード:
Imports CrystalEngine = CrystalDecisions.CrystalReports.Engine

Public Class CryReporter

    'レポートの表示方法
    Public Enum ReportMode
        Print   'プリントアウト
        Preview 'プレビュー表示
    End Enum

    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' dataSource で指定されたテーブルを使用するレポートの出力
    ''' </summary>
    ''' <param name="dataSource">レポートのデータソース。
    ''' このDLLが持つ型付データセット(CryDataSet)のテーブルを指定</param>
    ''' <param name="reportType">レポートの表示方法。</param>
    ''' -----------------------------------------------------------------------------
    Public Sub Report _
        (ByVal dataSource As System.Data.DataTable, ByVal reportType As ReportMode)

        'データソースをバインドしたレポートオブジェクトを受け取る
        Dim myReport As CrystalEngine.ReportClass

        'dataSource の型により処理分け
        Select Case True
            Case TypeOf dataSource Is CryDataSet.DataTable_1
                myReport = GetReport(dataSource)

            Case TypeOf dataSource Is CryDataSet.DataTable_2
                myReport = GetReport(dataSource)

        End Select

        'reportType により処理分け
        Select Case reportType
            Case Print
                'プリントアウト
                myReport.PrintToPrinter(1, True, 0, 0)

            Case Preview
                'プレビュー表示
                Dim preview As New PreviewForm
                preview.reportViewer.ReportSource = myReport
                preview.ShowDialog()

        End Select

    End Sub

    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' データソースをバインドしたレポートオブジェクトを返す。
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Private Overloads Function GetReport _
        (ByVal dataSource As CryDataSet.DataTable_1) _
        As CrystalEngine.ReportClass

        'レポートのインスタンスを生成
        Dim myReport As New CrystalReport1

        'データソースのバインド
        myReport.Database.Tables(0).SetDataSource(dataSource)

        Return myReport
    End Function

    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' データソースをバインドしたレポートオブジェクトを返す。
    ''' </summary>
    ''' -----------------------------------------------------------------------------
    Private Overloads Function GetReport _
        (ByVal dataSource As CryDataSet.DataTable_2) _
        As CrystalEngine.ReportClass

        'レポートのインスタンスを生成
        Dim myReport As New CrystalReport2

        'データソースのバインド
        myReport.Database.Tables(0).SetDataSource(dataSource)

        Return myReport
    End Function

End Class


じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-02-21 15:03
引用:

ぺどらさんの書き込み (2006-02-21 14:27) より:

いきなりの大御所さんからのレスでビックリしています(^^;
じゃんぬねっとさんのサイトには.NETを始めてからかなりお世話になっております。
この場を借りてお礼申し上げます。


こちらこそ、ありがとうございます。(*_ _)

引用:

いえ。.NET Framework 側に原因があるのであれば、同じソリューションの他の
Windows アプリのレスポンスも悪くなると思うのですが、遅延が発生するのは
DLL 内部での話なので、クリレポ側に原因があるんじゃないか?という考えに至ったわけです。


遅延が発生するのは、アセンブリ ローダーが開発元環境を見に行くからですね。
「Windows アプリケーション側では遅延なくできた」というのは、
DLL 上でこの処理を実装せず、EXE 側で処理を実装して検証したということでしょうか?

引用:

myReport.Database.Tables(0).SetDataSource(dataSource)


ここでの遅延ですが、.NET Framework の DataTable でも発生しますか?
もちろん、問題の DLL 側に実装しなければ検証になりません。

引用:

DLL が依存しているのは、今作成中のアプリで使用している共通クラスの他には、
Crystal Reports 絡みのDLLしか心当たりがありません。


そういう意味ではなかったのですが、"遅延呼び出し" をしているわけじゃなさそうですね。
(ここでの「遅延」は、問題になっている処理上の遅延とは異なります)

引用:

Report() メソッドを呼び出す前に、DLLが持つ型付データセットのテーブルへ
Windowsアプリ側からデータをセットしてから、Report() メソッドを呼び出しています。
その際に、DLLがもつ列挙体へも参照しますし、Report() メソッドを呼び出した直後に
データセットの型を参照すると、遅延なく参照可能です。


2 回目以降で遅延なく実行できるのは、アセンブリのロードが完了しているからですね。

引用:

# ということは、アセンブリ ローダ的にはこのDLL を問題なくロードできている。
# と、認識しているのですが…。あってますか?


合ってます。
一度ロードされたアセンブリ モジュールは AppDomain が解放されるまではそのままです。

構成に問題があるのかもしれない、という結論になってしまうのですが、
実行環境には開発環境があるわけじゃないんですよね?

CrystalReports 側のインフラ的な依存関係が原因かもしれません。
(でも、それなら実行できないと思うんですよね... どうやって解決してるんだろう?)

マージ モジュールを含めたセットアップはされていますか?

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
ぺどら
会議室デビュー日: 2006/02/17
投稿数: 14
お住まい・勤務地: かごしま
投稿日時: 2006-02-21 15:42
じゃんぬねっとさん お忙しい中、素早いレスありがとうございます。
頭が混乱してきているので、的を射た回答ができるかどうか不安ですが…

引用:

じゃんぬねっとさんの書き込み (2006-02-21 15:03) より:
引用:

ぺどらさんの書き込み (2006-02-21 14:27) より:

いえ。.NET Framework 側に原因があるのであれば、同じソリューションの他の
Windows アプリのレスポンスも悪くなると思うのですが、遅延が発生するのは
DLL 内部での話なので、クリレポ側に原因があるんじゃないか?という考えに至ったわけです。


遅延が発生するのは、アセンブリ ローダーが開発元環境を見に行くからですね。
「Windows アプリケーション側では遅延なくできた」というのは、
DLL 上でこの処理を実装せず、EXE 側で処理を実装して検証したということでしょうか?


アセンブリ ローダが開発環境を見に行くのであれば、問題の DLL を使わないWindows アプリでも
レスポンスが悪くなると思うのですが、そうじゃないのでクリレポに原因があるんじゃないかと思ったわけです。

アセンブリ ローダの参照先を実際にexeが動くPCから指定することができれば良さそうなのですが、
「.NET Configuration 1.1」なるツールを使っても、指定できそうな項目がありませんでした…。


引用:

じゃんぬねっとさんの書き込み (2006-02-21 15:03) より:
引用:

myReport.Database.Tables(0).SetDataSource(dataSource)


ここでの遅延ですが、.NET Framework の DataTable でも発生しますか?
もちろん、問題の DLL 側に実装しなければ検証になりません。


.NET Framework の DataTable というと、System.Data.DataTable のことでしょうか?
型付データセットのテーブルは .NET Framework の DataTable ではないのですか?
もし、そうであれば、DataTable を持っているのは、DLL 側になるのですが…。


引用:

じゃんぬねっとさんの書き込み (2006-02-21 15:03) より:
引用:

Report() メソッドを呼び出す前に、DLLが持つ型付データセットのテーブルへ
Windowsアプリ側からデータをセットしてから、Report() メソッドを呼び出しています。
その際に、DLLがもつ列挙体へも参照しますし、Report() メソッドを呼び出した直後に
データセットの型を参照すると、遅延なく参照可能です。


2 回目以降で遅延なく実行できるのは、アセンブリのロードが完了しているからですね。


あっ、言い忘れていたことが…。
問題の DLL を使ったレポート出力は、何度やっても(一度出力がなされたあとでも)、レスポンス低いです…。


引用:

じゃんぬねっとさんの書き込み (2006-02-21 15:03) より:

構成に問題があるのかもしれない、という結論になってしまうのですが、
実行環境には開発環境があるわけじゃないんですよね?

CrystalReports 側のインフラ的な依存関係が原因かもしれません。
(でも、それなら実行できないと思うんですよね... どうやって解決してるんだろう?)

マージ モジュールを含めたセットアップはされていますか?


本番機には開発環境はありません。
セットアップ プロジェクトの作成担当者に確認してみましたが、
「クリレポ絡みの DLL はすべて最新バージョンのものがセットアップ プロジェクトに含まれている。
マージ モジュールに対するライセンスの設定も行っている。」という回答が返ってきました。


# アセンブリ ローダが見に行くサーバを設定するような方法などありますでしょうか?
# それをイジれば、解決しそうな気が…。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-02-21 16:29
すいません、何点か誤解があったようです。

引用:

ぺどらさんの書き込み (2006-02-21 15:42) より:

アセンブリ ローダが開発環境を見に行くのであれば、問題の DLL を使わないWindows アプリでも
レスポンスが悪くなると思うのですが、そうじゃないのでクリレポに原因があるんじゃないかと思ったわけです。


いえ、EXE 単体だったら "動的に" ローダーが働く必要がないですよね?
EXE -> DLL と依存関係があるので、必要なタイミングでロードしにいくのです。
そのタイミングで、何かを探そうとしているのかな? と思ったのですが、

引用:

複数(約20種類)レポートと、各々のレポートで使用するデータテーブルを
まとめたデータセットの定義を持つDLLを作成し


ここに ReportDocument クラスのオブジェクト類も含まれるんでしょうか?
もし、そうであれば ReportDocument (コード例で挙がっている myReport) が、
インスタンス化された時に遅延しないと話が合わなくなるような気がしますね...

引用:

.NET Framework の DataTable というと、System.Data.DataTable のことでしょうか?
型付データセットのテーブルは .NET Framework の DataTable ではないのですか?
もし、そうであれば、DataTable を持っているのは、DLL 側になるのですが…。


ここは、私が勘違いしていたみたいですね。
型付の DataSet だけでなく、DataTable なども含まれているのですね。

ますます、わからなくなってきました...

引用:

あっ、言い忘れていたことが…。
問題の DLL を使ったレポート出力は、何度やっても(一度出力がなされたあとでも)、レスポンス低いです…。


その度に、ローカル外に何かしようとしているということでしょうか?
だとすると、アセンブリ ローダー云々は関係ないということになりますね。

引用:

本番機には開発環境はありません。


本番機でない「別の開発環境 (2 とします)」だとどうなりますか?
本番機でも見に行こうとしている「開発環境 (1 とします)」を見に行こうとするんでしょうか?

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
ぺどら
会議室デビュー日: 2006/02/17
投稿数: 14
お住まい・勤務地: かごしま
投稿日時: 2006-02-21 17:09
じゃんぬねっとさん
誤解を招くような書き方をしてしまって申し訳ありません。


引用:

じゃんぬねっとさんの書き込み (2006-02-21 16:29) より:

引用:

複数(約20種類)レポートと、各々のレポートで使用するデータテーブルを
まとめたデータセットの定義を持つDLLを作成し


ここに ReportDocument クラスのオブジェクト類も含まれるんでしょうか?


はい。ReportClass を継承したクラスの定義が DLL のソリューションに含まれています。
VisualStudio で CrystalReport1.rpt というファイルを追加すると
CrystalReport1.vb というファイルが自動で作られ、その中にクラスが定義されています。

ちなみに、DLL が持つレポートの数が影響しているのかと思い、本番環境にて問題の DLL から
レポートの定義を1つだけ残して、あと全てを削除した状態でビルドしてみましたが、駄目でした。
と、同時に本番環境でレポートを追加したものを実行してみましたが、同じく駄目でした。


引用:

じゃんぬねっとさんの書き込み (2006-02-21 16:29) より:

もし、そうであれば ReportDocument (コード例で挙がっている myReport) が、
インスタンス化された時に遅延しないと話が合わなくなるような気がしますね...


そうなのですが、インスタンス生成時には待たされないんです。


引用:

じゃんぬねっとさんの書き込み (2006-02-21 16:29) より:

引用:

あっ、言い忘れていたことが…。
問題の DLL を使ったレポート出力は、何度やっても(一度出力がなされたあとでも)、レスポンス低いです…。


その度に、ローカル外に何かしようとしているということでしょうか?
だとすると、アセンブリ ローダー云々は関係ないということになりますね。


関係ありませんか…。突破口が見えたような気がしてたのですが…。

引用:

じゃんぬねっとさんの書き込み (2006-02-21 16:29) より:

引用:

本番機には開発環境はありません。


本番機でない「別の開発環境 (2 とします)」だとどうなりますか?
本番機でも見に行こうとしている「開発環境 (1 とします)」を見に行こうとするんでしょうか?



えっと…。(社内での)開発用サーバを 192.168.100.001 として、
(現場での)本番用サーバが 192.168.000.001 と、192.168.000.002 の2台があります。
000.001 は実際にオペレータさんが使用する際のサーバで、000.002 は現場でのメンテ用のサーバです。

どの環境で行っても、それ以外の2台のサーバを参照しに行きます。
開発用サーバに繋がっているルータは、192.168.100.xxx 以外へのリクエストは、許可していないらしく
参照しに行った瞬間に、応答なし としてすぐレスポンスが返ってきます。


先ほど、本番環境下の端末のIPアドレスとDNS サーバのアドレスを自動割当てから
固定IPに変えたら待たされなくなりました。
# これで解決にしたいのですが、運用上固定IPは厳しいとのことで無理でした…
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-02-21 17:43
引用:

ぺどらさんの書き込み (2006-02-21 17:09) より:

誤解を招くような書き方をしてしまって申し訳ありません。


私も読み違えていたようで、申し訳ありません。(*_ _)

引用:

どの環境で行っても、それ以外の2台のサーバを参照しに行きます。
開発用サーバに繋がっているルータは、192.168.100.xxx 以外へのリクエストは、許可していないらしく
参照しに行った瞬間に、応答なし としてすぐレスポンスが返ってきます。


単に DB サーバを見に行くならわかるんですが、開発環境を見に行くのが解せないですね。
初歩的な確認で申し訳ないのですが、DB のコネクションってサーバ自身になってるんですよね?
これが開発環境の DB だとしたら、わかるんですが、まさかそんなことはないでしょうし...

あとは最小限に縮めた状態で、ミニマムテストを行って根本的な原因を探るしかなさそうです。

# 同じような構成で納品したことがあるんですが、こんなことはなかったような... orz

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌

スキルアップ/キャリアアップ(JOB@IT)