インフラジスティックス・ジャパン株式会社のBlog

インフラジスティックス・ジャパン株式会社のチームメンバーが技術トレンド、製品Tips、サポート情報からライセンス、日々の業務から感じることなど、さまざまなトピックについてお伝えするBlogです。

WebDataGrid: ファイル出力時のTips

弊社の ASP.NET 用のグリッドコントロール、WebDataGrid には付属する専用コントロール WebExcelExporter や WebDocumentExporter が用意されています。 これらは、WebDataGrid の内容を非常に簡単に(僅か1行で!)Excel 形式や PDF 形式、XPS 形式などで出力できるコントロールです。

        // Excelファイル出力はこれだけ!
        this.WebExcelExporter1.Export(this.WebDataGrid1);

とても便利な機能ですね!

上記のコード1文で、WebDataGrid から Excel ファイル等を生成し、更に HTTP レスポンスを書きかえてファイルダウンロードを自動で行わせてくれる素晴らしく便利なコントロールです。

しかし、WebDataGrid のセル編集を可能状態にしていた場合、注意しなければならない点がございます

WebDataGrid では、通常、セルの編集が行われた後のポストバック時にサーバ側でデータソースの更新を行い、レスポンスがクライアントサイドに返ってきたタイミングで更新された情報をグリッドにコントロール内部の Javascript で反映しています。
以下の図では、左側がグリッド編集後かつ未ポストバック状態で、2,3行目を編集しているため文字色が若干薄くかつ斜体になっています。(サーバ側のデータソースにコミットされていない状態を表しています。)また、右の図は単純なポストバックを起こした後の状態で、クライアント側で編集したデータがサーバ側のデータソースにコミットされたため薄字かつ斜体だった行が元の表示に戻っている事がわかります。
※分り易くするため、「BatchUpdating=true」のプロパティ設定をしています。

image image

 

ここで、ポストバック時にファイル出力のためにHTTPレスポンスを書きかえてしまうと、サーバ側ではデータソースが更新されているのにクライアント側では更新されていないことになってしまいます。こうなってしまうとオペレーション次第では修正したはずの内容が DB に適用されない、あるいはファイル出力されないといったような不具合に繋がってしまいます。

image

これを防ぐためには、通常行っている HTTP レスポンスを一度クライアント側に返してから、別のレスポンスでファイル出力を行う必要があります。具体的には以下のようなコードで実装することができます。

    /// ファイル出力ボタン押下時の処理
    protected void Button1_Click(object sender, EventArgs e)
    {
        //***********************************
        // Excelデータの作成
        //***********************************
        WorkbookFormat excelFormat = Infragistics.Documents.Excel.WorkbookFormat.Excel2007;

        Workbook wBook = new Infragistics.Documents.Excel.Workbook(excelFormat);

        this.WebExcelExporter1.ExportMode = Infragistics.Web.UI.GridControls.ExportMode.Custom;
        this.WebExcelExporter1.Export(this.WebDataGrid1, wBook);

        Session["WorkbookData"] = wBook;

        //***********************************
        // 一度クライアントにレスポンスを返した後、
        // 再度エクセルダウンロードをさせるスクリプトを組みこむ
        //***********************************
        // ClientScriptManagerを取得
        ClientScriptManager csMgr = Page.ClientScript;

        // ClientScriptを記述
        StringBuilder sb = new StringBuilder(string.Empty);
        sb.Append("<script type='text/javascript'>\r\n");
        sb.Append("window.onload=function(){\r\n");
        sb.Append("\tdocument.forms['form1'].action = 'Default.aspx?action=DownloadFile';\r\n");
        sb.Append("\tdocument.forms['form1'].submit();\r\n");
        sb.Append("}\r\n");
        sb.Append("</script>");

        csMgr.RegisterClientScriptBlock(this.GetType(), "SampleScript", sb.ToString(), false);
    }

上記コードでは、ファイル出力ボタンが押下された際のサーバ側イベントにて、生成したファイルをそのままクライアント出力するのではなく、一度セッションに格納しています。また、クライアントサイドの描画が終わったタイミングで自動的に再度リクエストを投げるような Javascript を埋め込んでいます。

そのため、再リクエストを受けた時の Page_Load イベントの記述が必要です。

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            Session["Data"] = getData();

            WebDataGrid1.DataKeyFields = "BoundColumn_KEY";
        }

        if (Request["action"] == "DownloadFile" &&
        Session["WorkbookData"] != null)
        {            
            Workbook customWorkbook = (Workbook)Session["WorkbookData"];

            //Create the Stream class
            System.IO.MemoryStream theStream = new System.IO.MemoryStream();

            //Write the in memory Workbook object to the Stream
            customWorkbook.Save(theStream);

            //Create a Byte Array to contain the stream and send the exported sheet to the client
            byte[] byteArr = (byte[])Array.CreateInstance(typeof(byte), theStream.Length);
            theStream.Position = 0;
            theStream.Read(byteArr, 0, (int)theStream.Length);
            theStream.Close();
            Session["WorkbookData"] = null;
            Response.Clear();
            Response.AddHeader("content-disposition", "attachment; filename=ExportedTo.xlsx");
            Response.BinaryWrite(byteArr);
            Response.End();
        }

        // *************
        // Bind DataSet
        // *************
        this.WebDataGrid1.DataSource = Session["Data"];
    }

上記コードでは、再リクエストを受けた際に、セッションから直前に生成した Excel ファイルのデータを取り出し、HTTP レスポンスを書きかえてファイル出力を行っています。

image

これでファイル出力時にも正常にグリッドの内容を更新させる事が出来ました!

今回ご紹介した Tips は弊社コントロールに限った問題というわけではなく、HTTP レスポンスの書きかえを行うような処理がある場合には気をつけなければならないポイントです。いつか皆様お役に立てれば幸いです!

無料トライアルダウンロードはこちら
NetAdvantage トライアル版

ASP.NET AJAX 対応、高機能、高パフォーマンス コントロール - Infragistics ASP.NET