2014年2月12日 星期三

[ASP.NET C#] 簡易由網頁自動輸出 Office 文件

Reference:http://tlcheng.twbbs.org/Paper/RunPC/132/Office.htm


簡易由網頁自動輸出 Office 文件

鄭子璉
由於企業內部或政府部門經常使用Office文件,使得透過網站功能自動輸出Office文件成為大量的需求,甚至部分網頁系統在政府採購標單內指定要求此功能;要輸出成為Office文件,大部分採用Automation (DCOM)方式,以物件操控方式建立,在這類前提下,只能選擇ASP/ASP.NET作為建立的網頁平台。
  而即使使用物件操控建立,網頁使用者權限不足,開發者接著就是面對一連串的權限調整,甚至到最後還是無法正確完成權限設定,在ASP.NET可以以不同使用者權限執行,在此方面有較佳的彈性,但是提高網頁應用程式的權限時,可能Server遇到被攻擊的風險也跟著升高,而二進位的Office也可能因Server的Office遭受巨集病毒感染,而大量散佈到Client端。
  此外,以物件方式建立尚需面臨由Server轉送至Client端前需要產生暫存文件,以ASP開發更需複雜的暫存文件管理機制,以避免同時存取發生鎖死及磁碟空間管理,若發生程式碼錯誤或使用者中斷,可能導致Office軟體無法正確從記憶體中釋放、或是轉送之暫存檔無法刪除等問題而拖垮系統資源,亦有Server端執行物件帳號來自動產生之Office暫存檔管理困擾;也因Office文件建立時,需耗費大量記憶體,且執行較為緩慢,多人同時瀏覽相同網頁會拖累系統效能或導致鎖死。以資策會目前正在執行部分政府委辦計畫為例,資策會選用IStart元件產生Excel報表及PowerPoint簡報,係屬在Client端以DCOM方式存取,執行速度緩慢,一份5 ~ 8頁制式格式簡報檔可能需時3 ~ 5分鐘才能自動完成,若中間發生網路連線問題或使用者中斷,都容易產生DCOM的資源無法正確被釋放。
  在Office XP/2003以後直接支援HTML檔案,只要妥善運用就可輕易的匯出成為Office文件,下面先介紹一個簡單同時支援Word、Excel及PowerPoint的範例:
<%@ Page Language="vb" AutoEventWireup="false" CodePage=”950" %>
<script language="vb" runat="server" id="modOffice">
   Public Function SetResponseHeader(Byval sContentType As String, Byval sFileName As String, _
      Byval bSaveFile As Boolean)
      Dim sContentDisposition As String
      With Response
         If bSaveFile Then
            sContentDisposition = "attachment; " ' 強制存檔,未設定則依瀏覽器預設開啟或存檔
         End If
         If Len(sFileName) > 0 Then
            sContentDisposition = sContentDisposition & "filename=" & sFileName ' 檔名
         End If
         If Len(sContentDisposition) > 0 Then
            .AddHeader("Content-disposition", sContentDisposition)
         End If
         .ContentType = sContentType
      End With
   End Function
</script>
<%If Len(Request.QueryString("ext")) > 0 Then
   SetResponseHeader(Request.QueryString("ContentType"), "Office." & Request.QueryString("ext"), False)
End If%>
<HTML>
   <HEAD>
      <title>測試</title>
      <META http-equiv="Content-Type" content="text/html; charset=big5">
      <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
   </HEAD>
   <body bottomMargin="0" leftMargin="0" topMargin="0" rightMargin="0">
      <TABLE cellSpacing="1" cellPadding="1" width="100%" border="1">
         <TR><Th>欄0</Th><Th>欄1</Th><Th>欄2</Th></TR>
         <TR><Th>列1</Th><TD style="COLOR: yellow; BACKGROUND-COLOR: green">1,1</TD><TD>1,2</TD></TR>
         <TR><Th>列2</Th><TD>2,1</TD>
            <TD style="FONT-SIZE: 32px; FONT-STYLE: italic; FONT-FAMILY: 'Bauhaus 93'">2,2</TD></TR>
      </TABLE>
      <p>輸出格式 
         <a href="Office.aspx?ext=doc&ContentType=application/msword">Word</a> 
         <a href="Office.aspx?ext=xls&ContentType=application/vnd.ms-excel">Excel</a> 
         <a href="Office.aspx?ext=ppt&ContentType=application/vnd.ms-powerpoint">PowerPoint</a>
      </p>
   </body>
</HTML>
在這個範例中,程式碼轉譯區塊 (<% … %>) 以上是ASP.NET的程式碼,以下是純HTML語法文件,挑選兩表格格子輸出為不同的樣式,以利對照比較。以Internet Explorer(以下簡稱IE)網頁瀏覽顯示如圖1。


圖 1 在IE顯示之原始網頁

  當點選圖上任一輸出格式時,視IE安全性設定,可能會跳出圖2的對話框,在圖2對話框中,可以明顯看出,這個網頁的檔案類型已經被當成Microsoft PowerPoint文件,並非是當成HTML文件開啟了。


圖 2 檔案下載對話框

  若未出現圖2對話框,可能是允許內崁於網頁上。點選圖2開啟按鈕後,依IE安全性設定,可能內崁於網頁或啟動Office軟體單獨開啟,或另存新檔後,直接透過檔案總管點選開啟。單獨開啟如圖3所示,內崁於網頁如圖4所示。

(a)Word(b)PowerPoint
圖 3 由Office軟體單獨開啟


(a)Excel(b)PowerPoint
圖 4 Office文件內崁於IE之中

技術說明

細觀原始碼後,原始碼僅在HTML內容類型加入檔名設定及內容類型(ContentType)設定,因此本文介紹的方法將不限於應用在ASP.NET上,亦可應用在ASP、PHP或其他支援此功能設定的網頁平台。而造成IE能判讀為Office文件的原因為內容類型的正確設定,檔名設定是便於使用者儲存檔案後,得以對應的Office軟體開啟,並非絕對必要,比如說將檔名設為Office.htm,仍可以對應的Office軟體開啟,如圖5所示,此外,會在檔案下載對話框內出現警告訊息。若要強制啟用檔案下載對話框,可在呼叫函數SetResponseHeader時,設定bSaveFile為True。而要輸出為Office文件時,則依指定的內容類型來設定,不同Office文件之內容類型如下表:
內容類型副檔名Office軟體
application/msword.docMicrosoft Word
application/vnd.ms-excel.xlsMicrosoft Excel
application/vnd.ms-powerpoint.pptMicrosoft PowerPoint


圖 5 設定為不同格式之附檔名

更進一步

在前述部份,僅利用Office自動開啟HTML檔案的能力,並未針對各軟體設定對應功能,在大部分自動產生Office文件的要求,多半屬於報表或是特定格式的對應,一般來說可能會有制式的樣版檔,此時可先以Office軟體產生樣版檔後,利用關鍵字來替換特定字串,來輸出制式報表,當Office文件編輯完成後,將其另存為HTML或XML檔後,以檔案讀入功能讀入後,並輸出成為文件。
  本文以一簡易公文為例來說明,首先先以Word設計一公文樣本,並將其存成XML格式文件,在範本中,欲以程式替換的文字,以關鍵字存於檔案內,本例中,以(key:…)為搜尋替換關鍵字,如圖6所示。


圖 6 公文樣本

  依前述觀念開發一個可讀取文字檔並處理的網頁程式,其中Word存成XML檔時,預設格式為UTF-8,因此在讀檔及輸出時,應注意字串的編碼方式轉換。網頁程式範例如下:
<%@ Page Language="vb" AutoEventWireup="false" CodePage="950" %>
<!-- #include virtual = "StrTools.aspx" -->
<!-- #include virtual = "FileTool.aspx" -->
<!-- #include virtual = "ResponseFile.aspx" -->
<script language=vb runat=server id="modCount">
   Public Function ResponseWord()
      Dim sFile As String = MyGetFullTextFile(Server.MapPath("/Test/Office/公文.xml"), _
         enuStandardCodePages.SCP_CP_UTF8)
      sFile = Replace(sFile, "(key:受文者)", "網頁程式設計師")
      sFile = Replace(sFile, "(key:主旨)", "自動輸出WORD文件說明。請查收。")
      sFile = Replace(sFile, "(key:說明)", "本文為說明簡易輸出方式,程式碼說明如附件。")
      sFile = Replace(sFile, "(key:正本收文)", "本文閱讀者")
      sFile = Replace(sFile, "(key:副本收文)", "鄭子璉")
      Dim arrBytes = StringToBytes(sFile, enuStandardCodePages.SCP_CP_UTF8)
      ResponseFile(arrBytes, "application/msword", "test.doc")
   End Function
</script>
<% ResponseWord() %>
當本網頁執行時,將會詢問使用者Word檔處理方式,如圖7所示。以Word開啟後,可以看到,欲替換的字串已經填入在對應位置,如圖8所示。讀者若需直接輸出Office文件,亦可詳加研讀相關語法後,直接輸出。


圖 7 檔案下載詢問畫面



圖 8 自動填入資料產生公文

小結

本文以簡易的內容類型替換方式,讓網頁程式產生Office文件更容易,也免去複雜的Windows權限設定、DCOM可能耗損Server的記憶體及程序鎖死的情形,網頁程式設計師可依個人需求調整而直接輸出HTML格式或XML格式,因屬純文字格式,使得變更資料內容或依指定格式變更更為容易,且不使用二進位資料,不易發生因DCOM無法正確釋放,而使得系統資源逐漸減少。此外,輸出時採用Office文件副檔名,有助於檔案總管直接開啟,換句話說,本文內容亦可在Windows Form程式下應用,或其他作業系統下產生對應文字檔做資料交換,助於系統整合、政府採購及企業內部電子文件交流。

其他參考資訊:

DCOM元件權限設定:http://tlcheng.twbbs.org/TLCheng/Basic/vbs/dcom/automation.htm
在ASP.NET中動態共用原始碼:http://www.microsoft.com/taiwan/msdn/columns/mvp/aspxcode.htm
公文範例所引用的程式碼:http://tlcheng.twbbs.org/TLCheng/Net/NetList.aspx

作者簡介:

沒有留言:

張貼留言