SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

現役エンジニア直伝! 「現場」で使えるコンポーネント活用術(ActiveReports)

Windows Azure上で帳票コンポーネント「ActiveReports for .NET 6.0J」を動作させてみた

  • このエントリーをはてなブックマークに追加

ActiveReportsを動作させるワーカーロールコード

 PDFはワーカーロール側で生成するため、ActiveReports関連のコードはすべてワーカーロール側に記述します。サンプルプログラム作成開始時点では、もちろんWindows Azure特有の問題やその対応方法も分からなかったので、ActiveReportsを使用するクラスライブラリの作成時と同じ手順でプログラミングしてみました。その時の作業を順番に追ってみます。

ActiveReportsの参照設定

 まず、ソリューションエクスプローラーで「CZ1009CloudWorkerRoleワーカーロール」を右クリックして、「Graprcity ActiveReports for .NET」「Document」「PDF Export」「Viewer」のコンポーネントへの参照を追加します。

図12 参照の追加
図12 参照の追加

ActiveReports 6.0Jファイルの追加

 参照の追加が完了したら、再びソリューションエクスプローラーで「CZ1009CloudWorkerRoleワーカーロール」を右クリックして、[追加]-[新しい項目]を選択し、ActiveReportsの帳票定義体ファイルを追加します。

図13 「ActiveReports 6.0Jファイル」の追加
図13 「ActiveReports 6.0Jファイル」の追加

 図13を見れば分かるように、ActiveReportsの定義体には、2つのファイル形式があります。「ActiveReports 6.0Jファイル」を選択した場合には、クラスファイルとして定義体が追加され、WindowsフォームやWebフォームのようにビルド後はアセンブリの一部となります。もちろん、IDEで該当ファイルをダブルクリックすれば、ActiveReportsの帳票デザイナが開きます。

 もう1つの「ActiveReports 6.0Jファイル(XMLベース)」を選択した場合は、rpxファイルとしてプロジェクトに追加され、ビルド後もアセンブリとは別のrpxファイルとして動作環境に配置されます。つまり、動作環境上のrpxファイルを編集することで、再ビルドなしに帳票定義体の修正ができるという利点があります。業務アプリケーションでは、帳票のちょっとした修正というのは意外と多いため、筆者はこのファイル形式をよく使っています。

 しかし、この形式は実行時にrpxファイルの読み込みが必要なため、動作環境のどこにrpxファイルがあるかが分かっていなくてはなりません。ASP.NET Webロールの場合は、「My.Request.PhysicalApplicationPath」プロパティで位置が判明しますが、ワーカーロールの場合は、どのようにファイルパスを取ればよいか明確には分からなかったため、今回はアセンブリの一部となる「ActiveReports 6.0Jファイル」形式を採用しました。

ActiveReports 6.0J帳票定義体の定義

 ActiveReportsの帳票定義体デザイナは、非常に使いやすい操作性になっています。基本的には、Windowsフォームデザイナと同じようにツールボックスからコントロールをドラッグ&ドロップし、配置するときにはスナップ線を頼りに最適な位置を決めることができます。Windowsフォームデザイナと異なるのは、コントロールとコントロールの間が0ピクセル、つまり開きがない状態が最適な位置と設定されている点です。

 一覧表などを作る際、表のタイトルをPageHeaderセクションに配置し、データ部分をDetailセクションに配置するような場合でも、セクションをまたがってスナップ線が表示できるため、タイトル位置とデータ位置を容易に合わせることができます。

図14 ActiveReportsの帳票定義体デザイナ
図14 ActiveReportsの帳票定義体デザイナ

 また、CrossSectionLineコントロールやCrossSectionBoxコントロールを使えば、セクション間をまたがった罫線も簡単に引くことができ、一覧表の罫線部分も簡単に定義できます。さらに、PageFooterセクションまで含めておけば、“データがなくてもページの下までいつも同じ大きさで枠線を引いておく”といった設定も簡単に実現できます。

図15 CrossSectionBoxによる罫線定義
図15 CrossSectionBoxによる罫線定義

 ただし、CrossSectionLineコントロールとCrossSectionBoxコントロールのStartプロパティとEndプロパティのプロパティ設定値はcm(センチメートル)単位ではなく、インチ単位なので注意が必要です。プロパティで位置を決めるときは、cmからインチへの単位変換を行い、その値を小数点以下まで含めてプロパティに設定するようにしないと、Lineなど他のコントロールがcmでプロパティを設定しているので、微妙にずれることがあります。

HTTP内部エンドポイントの追加

 Webロールからワーカーロールを呼び出すには、Windows Azure Storage Serviceのキューを使って非同期に連携する方法もありますが、非同期生成したPDFデータの扱いなどの考慮も必要になるため、今回はワーカーロールにHTTPで呼び出す内部インターフェース(内部エンドポイント)を定義して、それを同期的に呼び出すシンプルな方式にしました。

 HTTPを使った内部エンドポイントを定義するには、ソリューションエクスプローラーからクラウドサービス定義(サンプルでは「CZ1001Cloud」)にあるワーカーロール定義のプロパティで、エンドポイントの追加を行います。今回定義するエンドポイントは、種類を「internal」としてAzure内部でのみ使用するように定義し、プロトコルに「http」を指定してWebロールからHTTPで呼び出せるようにします。

HTTP内部エンドポイントの設定

 HTTP内部エンドポイントを設定したら、生成直後のワーカーロールにはRunメソッド、OnStartメソッド、RoleEnviromentChangingメソッドのコードが既に記載されているので、Runメソッドにエンドポイントが呼び出された時の処理を追加します。

リスト4 エンドポイントに対する処理
Private Shared listener As New HttpListener

Public Overrides Sub Run()
    Dim endpoint As IPEndPoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints("HttpEndpoint").IPEndpoint

    listener.Prefixes.Add(String.Format("http://{0}:{1}/", endpoint.Address, endpoint.Port))
    listener.Start()
    Do While (True)
        Dim context As HttpListenerContext = listener.GetContext()

        Using mes As System.IO.Stream = context.Response.OutputStream
            Try
                Dim byteMsg As Byte() = GetPdfDatas(False)

                mes.Write(byteMsg, 0, byteMsg.Length)
            Catch ex As Exception
                Dim msg As String = ex.Message
                Dim byteMsg As Byte() = System.Text.Encoding.UTF8.GetBytes(msg)

                mes.Write(byteMsg, 0, byteMsg.Length)
            End Try
        End Using
    Loop
End Sub

 エンドポイントの処理は、エンドポイントに対してlistenerを定義して呼び出しを待ち合わせし、呼び出されたら対応した処理を行うということになります。

 listenerの定義は、エンドポイント名を「HttpEndPoint」とした場合、InstanceEndpoints("HttpEndpoint")でエンドポイントを取得して、HttpListenerに追加(Add)します。後は、Startメソッドでlistenerを開始してGetContextメソッドで呼び出しを待ちます。

PDF生成コードの作成

 GetContextメソッドで待ち合わせていた呼び出しが行われたら、PDF作成用のGetPdfDatasメソッドを呼び出します。GetPdfDatasメソッドには、次のようなコードを記述します。

リスト5 PDFファイルをバイナリデータとして生成

     :
    (中略)
     :
Imports DataDynamics.ActiveReports
Imports DataDynamics.ActiveReports.Export.Pdf

Public Class WorkerRole
    Inherits RoleEntryPoint
     :
    (中略)
     :
    Private block As Object = Nothing
    ''' <summary>
    ''' PDFデータを取得する
    ''' </summary>
    Public Function GetPdfDatas() As Byte()
        Dim memStream As System.IO.MemoryStream
        Dim ds As DataSet = GetRecords

        Using _rpt As New CZ1009Reports
            _rpt.Document.Printer.PrinterName = ""
            _rpt.PageSettings.PaperKind = System.Drawing.Printing.PaperKind.A4
            _rpt.PageSettings.Orientation = Document.PageOrientation.Portrait
            _rpt.PageSettings.Margins.Top = ActiveReport.CmToInch(0.5F)
            _rpt.PageSettings.Margins.Bottom = ActiveReport.CmToInch(0.5F)
            'データを割り当てる
            _rpt.DataSource = ds.Tables("Enviroment")
            ' レポートを作成します
            _rpt.Run(False)
            ' PDFエクスポートオブジェクトを生成します
            Using _pdf = New PdfExport
                ' PDFの出力用のメモリストリームを作成します
                memStream = New System.IO.MemoryStream
                ' メモリストリームにPDFエクスポートを行います
                _pdf.Security.Use128Bit = True
                _pdf.Security.OwnerPassword = "hatsune"
                _pdf.Security.Permissions = PdfPermissions.AllowPrint
                _pdf.Security.Encrypt = True
                _pdf.Export(_rpt.Document, memStream)
            End Using
        End Using
        Return memStream.ToArray()
    End Function
     :
    (中略)
     :
End Class

 メソッドの中のコードは、リスト1で紹介したASP.NET Webアプリケーションのコードとまったく同じです。

ActiveReportsを動作させるWebロールコード

ASP.NET Webロールからワーカーロールを呼び出す

 今回のサンプルでは、Default.aspxの[PDF出力]ボタンをクリックすると「My.Response.Redirect("CZ1009Reports.aspx")」を実行して、CZ1009Reports.aspxページを呼び出します。このCZ1009Reports.aspxページで、ワーカーロールを呼び出します。

 ワーカーロールの呼び出し方は、動的に決定される内部エンドポイントのIPアドレスとポート番号を取得し、webClient.DownloadDataメソッドを使って呼び出します。

リスト6 ASP.NET Webロールからワーカーロールを呼び出す
Public Class CZ1009Reports
    Inherits System.Web.UI.Page
    Private block As Object = Nothing

    Protected Sub Page_Load(ByVal sender As Object,
                            ByVal e As System.EventArgs) _
                        Handles Me.Load
        If Not Me.IsPostBack Then
            Call GetRecords(isEmbedFonts)
        End If
    End Sub

    Private Function GetRecords(ByVal isEmbedFonts As Boolean) As Boolean
        Using webClient As New System.Net.WebClient
            Dim userID As String = My.User.Name
            Dim workerEndPoint = Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.Roles("CZ1009CloudWorkerRole").Instances(0).InstanceEndpoints("HttpEndpoint")
            Dim pdfStream() As Byte
            Dim pdf() As Byte = System.Text.Encoding.UTF8.GetBytes("%PDF")

            pdfStream = webClient.DownloadData("http://" & workerEndPoint.IPEndpoint.ToString)
            If pdfStream(0) = pdf(0) AndAlso pdfStream(1) = pdf(1) AndAlso pdfStream(2) = pdf(2) AndAlso pdfStream(3) = pdf(3) Then
                Response.ContentType = "application/pdf"
                Response.AddHeader("content-disposition", "inline; filename=AzureActiveReports.PDF")
            End If
            Response.BinaryWrite(pdfStream)
            Response.End()
        End Using
        Return True
    End Function
End Class

次のページ
ActiveReportsを動作させた実行例

修正履歴

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
現役エンジニア直伝! 「現場」で使えるコンポーネント活用術(ActiveReports)連載記事一覧

もっと読む

この記事の著者

初音玲(ハツネアキラ)

 国内SIerのSEでパッケージ製品開発を主に行っており、最近は、空間認識や音声認識などを応用した製品を手掛けています。 個人的には、仕事の内容をさらに拡張したHoloLensなどのMRを中心に活動しています。 Microsoft MVP for Windows Development ブログ:http://hatsune.hatenablog.jp/

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/5477 2010/10/04 17:42

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング