關於我

我的相片
用心思考、保持熱情,把工作上的經驗作分享與紀錄。希望能夠跟大家一起不斷的成長~

javascript windows.location

當我們在撰寫Asp.Net時, 如果要讓程式於執行完成時,

可出現Message,最常的用法是在codebehidn寫入下方程式:

Page.ClientScript.RegisterStartupScript(this.GetType(), "Msg", "<script>alert('執行成功');</script>");

即可讓程式在Response時,寫入client的script,跳出訊息視窗.

 

但當遇到希望可以回傳成功的訊息,並跳轉導入其他頁面.

如果使用下方的寫法:

Page.ClientScript.RegisterStartupScript(this.GetType(), "Msg", "<script>alert('執行成功');</script>"); 
Page.Response.Redirect("xxx.aspx");

先註冊一段client端的Script,接著再將Response導至預期的頁面。

看似一切都沒什麼問題,但當實際執行時,便會發生訊息不見的冏境。

 

實際分析了一下,原因很簡單,因為頁面已經被導至其他頁面了.

所以被註冊在原始頁面的Script,當然不會被執行到囉!

自然而然,訊息是不會出現的.

 

可是那要怎麼辦呢?!沒有辦法可以做到這個功能嗎?!

有的,可參考下面的這行程式:

Page.ClientScript.RegisterStartupScript(this.GetType(), "Msg", "<script>alert('執行成功'); window.location = 'xxx.aspx';</script>");

發現了嗎?!我們將導至其他頁面的動作,保留到Client再由JavaScript去完成他!

這樣就可以在不影響訊息顯示的情況下,依然導入預期頁面了!

 

這就是好用的JavaScript "windows.location"!

Oledb Export DataSet to Excel

同事遇到一個需求,須將Data匯出成已排版完成的Word檔,

成為一份電子書,給予User下載。還需要有封面、目錄、速查表等頁面。

最後同事決定,將Data彙整於DataTable中,

並將所有Data於DataTable中,將所有資料均排版完成。

原始資料如下圖,是一般常見的資料狀況:

擷取拷貝

經過編輯後,被排版成下圖,

擷取拷貝2

這樣的好處是,可以將此排版好的DataTable,

直接用套表的方式匯出,後段程式只需注意套表與字型等問題即可,不需再費心於排版上。

在製作目錄或速查表等需計算頁數之頁面時,也將簡單許多。

 

而今天的重點來了,因為需要修改此段排版程式,須加入其他商業邏輯。

但排版好的DataTable,我們又看不到,怎麼快速確定是否正確呢?!

有了這個念頭,便想到之前有找到過將DataTable匯出為Excel的參考範例

今天趕緊將此找到的範例程式記錄下來。方便下此再次瞭解使用。

 

程式碼如下:

public static void ExportDataSetToExcel(DataSet data, String excelFileName)
{
  System.IO.File.Delete(excelFileName);
  string strConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
  + System.IO.Path.GetDirectoryName(excelFileName) + @"\" + System.IO.Path.GetFileName(excelFileName)
  + @";Extended Properties='Excel 8.0;HDR=YES'";
  using (System.Data.OleDb.OleDbConnection objConn = new
  System.Data.OleDb.OleDbConnection(strConnectionString))
  using (System.Data.OleDb.OleDbCommand cmd = new
  System.Data.OleDb.OleDbCommand("", objConn))
  {
    objConn.Open();
    foreach (DataTable dt in data.Tables)
    {
      cmd.CommandText = "CREATE TABLE [" + dt.TableName + "] (";
      String valueNames = "(";
      Boolean first = true;
      foreach (DataColumn dc in dt.Columns)
      {
        if (!first)
        {
          cmd.CommandText += ",\r\n";
          valueNames += ", ";
        }
        cmd.CommandText += " [" + dc.ColumnName + "] NVARCHAR(100)";
        valueNames += " [" + dc.ColumnName + "]";
        first = false;
      }
      cmd.CommandText += ")";
      valueNames += ")";
      cmd.ExecuteNonQuery();
      foreach (DataRow dr in dt.Rows)
      {
        String values = "(";
        first = true;
        foreach (DataColumn dc in dt.Columns)
        {
          if (!first)
            values += ", ";
          values += " '" + dr[dc] + "'";
          first = false;
        }
        values += ")";
        cmd.CommandText = "INSERT INTO [" + dt.TableName + "$] " +
        valueNames + " VALUES " + values;
        cmd.ExecuteNonQuery();
      }
    }
  }
}

而上方兩張截圖,就是用此方式,將DataTable匯出程Excel後,

開啟之結果。用此方式快速許多。

最後,就完成了排版完成的Word檔案囉~~~

擷取拷貝3

這張報表(這算報表嗎?!)實在是不好寫,

也順便記錄下同事的Ideal,如果下次遇到,也可以參考。

這樣就可以將程式拆開,不會又要排版又要寫資料..又要計算頁次等一堆事情,

全擠在同一支程式裡,大大的增加了程式的可維護性囉~~

讚!!!

(順帶一提,同事的Word套表,是用Html方式產生套表的。)

使用 SharpZipLib 發生解壓時,壓縮檔毀損問題

上次有寫了一篇關於使用SharpZipLib的文章 Streaming a zip file over http in .net with SharpZipLib 

結果在客戶端實際使用時,當客戶下載zip檔案後,

使用Windows內建的compressed (zipped) Folders開啟解壓縮時,發現匯出現下方錯誤訊息!

擷取

 

在Google上搜尋了一下,查出發生的原因為,預設SharpZipLib使用的是Zip64格式

而Windows內建的compressed (zipped) Folders是不支援此格式的。

因此解決方法需要強制指定壓縮時,不使用Zip64格式。即可解決此問題。

加入程式碼:

zipOutput.UseZip64 = UseZip64.Off;

該段程式修改後如下:

byte[] buffer = new byte[1024 * 8];
using (ZipOutputStream zipOutput = new ZipOutputStream(stream))
{
  zipOutput.UseZip64 = UseZip64.Off;  //強制指定不使用Zip64格式壓縮,避免windows內建zip無法開啟
  foreach (string fileName in fileNames)
  {
    ZipEntry zipEntry = new ZipEntry(fileName.Substring(fileName.LastIndexOf('\\') + 1));
    zipOutput.PutNextEntry(zipEntry);
    using (FileStream fread = File.OpenRead(fileName))
    {
      StreamUtils.Copy(fread, zipOutput, buffer);
    }
  }
  zipOutput.Finish();
}

即可解決此問題了!!

Streaming a zip file over http in .net with SharpZipLib

今天因為專案需求,需要於網站上可以將多個檔案zip後,Popup下載視窗,讓User可下載檔案zip包。這個需求之前有做過的做法如下:
  1. 先將所有要zip的檔案zip至一個暫存的目錄中。
  2. 將zip檔讀入為byte[],再Response.binarywrite出該byte[]檔案。
  3. 再將暫存檔案刪除。

可是這樣的做法,多了一個暫存的動作。

實在不是個好的做法。

因此今天花了點時間,找到了一個參考Sample

以此Sample即可達成省去暫存zip檔的步驟。

  1. 將要壓縮的檔案,一個一個讀入,zip後放入Stream中。
  2. 直接將Stream於網頁output出來即可。

以下為實際完成的程式。

using System;
using System.Text;
using System.Web;
using System.Xml;
using System.Data;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Core;
using System.IO;
using System.Collections.Generic;
namespace VAT2005.Forms
{
  class Utility
  {
    /// <summary>
    /// 將多個檔案zip後,Response下載!
    /// </summary>
    /// <param name="context">HttpContext</param>
    /// <param name="fileNames">要zip的多個檔案完整路徑與檔名</param>
    /// <param name="outputfilename">要output之zip檔案檔名</param>
    public static void DownloadFilesZip(HttpContext context, List<string> fileNames, string outputfilename)
    {
      context.Response.ContentType = "application/x-zip-compressed";
      context.Response.AppendHeader("content-disposition", string.Format("attachment; filename={0}", outputfilename));
      context.Response.ContentEncoding = Encoding.Default;
      context.Response.Charset = "";
      //設定zip時,buffer的大小
      byte[] buffer = new byte[1024 * 8];
      using (ZipOutputStream zipOutput = new ZipOutputStream(context.Response.OutputStream))
      {
        //依序讀入要zip的檔案
        foreach (string fileName in fileNames)
        {
          //新增zip檔案
          ZipEntry zipEntry = new ZipEntry(fileName.Substring(fileName.LastIndexOf('\\') + 1));
          //放入OutputStream中
          zipOutput.PutNextEntry(zipEntry);
          //讀入file
          using (FileStream fread = File.OpenRead(fileName))
          {
            //將file(Stream)使用buffer zip後,放入zipOutput中
            StreamUtils.Copy(fread, zipOutput, buffer);
          }
        }
        zipOutput.Finish();
      }
      context.Response.Flush();
      //完成Stream寫出,讓User下載
      context.Response.End();
    }
  }
}
透過上方做法,即可直接將要zip的多個檔案,zip後,讓User下載!

當然,此zip做法是使用SharpZipLib,必須要referance才可使用!