2024年10月31日 星期四

[研究]瀏覽器的「回上一頁」按鈕

[研究]瀏覽器的「回上一頁」按鈕

2024-10-31

 瀏覽器上按下「回上一頁」對資訊安全的威脅?

ChatGPT 說:

按下「回上一頁」通常不會直接構成嚴重的資訊安全威脅,但在某些情況下可能會導致一些風險:

  • 跨站點請求偽造 (Cross-Site Request Forgery, CSRF): 如果瀏覽器的「回上一頁」功能提交了表單或請求到另一個網站,而該網站不適當檢查請求的合法性,可能會執行不受歡迎的操作。防範方法是使用 CSRF 令牌來驗證請求的來源。
  • 緩存的敏感資訊洩露: 當頁面顯示敏感資訊,使用者按「回上一頁」時,可能會讓該資訊重新顯示,增加敏感數據洩露的風險。網頁可以透過控制 HTTP 標頭,例如「Cache-Control: no-store」,來避免敏感資訊在歷史紀錄中被快取。
  • XSS 攻擊 (Cross-Site Scripting): 某些惡意網站可能會利用「回上一頁」功能,將有害的 JavaScript 插入到使用者的瀏覽器歷史中,從而觸發 XSS 攻擊。使用 CSP(內容安全政策)來限制加載資源可以降低這種風險。
  • 前一頁的狀態操作風險: 如果網站使用 GET 請求執行敏感操作或狀態更改(例如,登出或提交交易),按「回上一頁」可能會重新執行該操作。避免此風險的方法是使用 POST 請求處理狀態變更或敏感操作。

一般來說,網站可以透過安全的程式設計最佳實踐,例如適當地設置 HTTP 標頭和驗證機制,來減少「回上一頁」的潛在風險。

********************************************************************************

瀏覽器上按下「回上一頁」按鈕,是從瀏覽器 cache 抓取網址和網頁內容?還是只從 cache 或 url history 抓取網址,用網址去 Web Server 從新抓網頁內容回來顯示?

ChatGPT 說:

按下「回上一頁」按鈕時,瀏覽器會依據頁面的 HTTP 標頭設定與資源的快取策略決定行為。一般而言,瀏覽器會優先從快取(cache)中抓取頁面內容和資源,以加速顯示過去的頁面。如果快取中沒有內容或有過期設定,則瀏覽器才會根據歷史紀錄中的 URL 向 Web Server 重新發送請求以獲取最新內容。

具體流程

  1. 快取優先處理:如果頁面的 HTTP 標頭設定允許快取且資源在快取內未過期,瀏覽器會直接從快取中讀取網頁和資源,並跳過對伺服器的請求。
  2. 檢查過期設置:若頁面在快取內,但已超過有效期限或 HTTP 標頭禁止快取,瀏覽器會向伺服器發送請求以確認資源是否更新。若無更改,則伺服器回應「304 Not Modified」,瀏覽器依然從本地快取中讀取內容;若有更改,則伺服器提供更新後的內容,並將其重新快取。
  3. 無快取時重新獲取:如果該頁面無法快取(例如含有敏感資訊),或使用者設定瀏覽器不快取,則瀏覽器會直接根據 URL 從 Web Server 重新請求內容。

因此,「回上一頁」通常會依據快取策略決定是否從伺服器重新抓取或僅使用快取內容,這樣既保留效率又能確保內容的新鮮度。

********************************************************************************

從瀏覽器 cache 抓取網址和網頁內容?還是只從 cache 或 url history 抓取網址,用網址去 Web Server 從新抓網頁內容回來顯示?

ChatGPT 說:

預設行為:快取優先

  • 如果頁面允許快取(例如 Cache-Control: public 或未指定 no-cache),瀏覽器會優先從快取中直接抓取網址和網頁內容,以加速顯示。

動態內容設定:重新抓取

  • .aspx 頁面通常涉及動態內容,因此伺服器端可能設置 Cache-Control: no-store 或 no-cache。在這些情況下,瀏覽器會從 URL history 中抓取網址,並向 Web Server 發送新的請求,以重新取得最新的網頁內容。

在一般情況下,如果沒有明確的快取限制,瀏覽器會直接使用快取內容;如果有特別的快取控制設定,則會向 Web Server 重新抓取,以確保內容更新。

********************************************************************************

(完)

[研究]SSLLabs報告TLS_RSA_WITH_AES_256_GCM_SHA384是WEAK

[研究]SSLLabs 報告 TLS_RSA_WITH_AES_256_GCM_SHA384 和 TLS_RSA_WITH_AES_128_GCM_SHA384 是WEAK

2024-10-31 

對某網站用  https://www.ssllabs.com/ssltest/ 做測試,結果說

TLS_RSA_WITH_AES_256_GCM_SHA384

TLS_RSA_WITH_AES_128_GCM_SHA384

這2個加密演算法Cipher Suites都是 WEAK

下圖,nmap 7.95 做 nmap --script ssl-enum-ciphers -p 443 <server-ip>

這2個都是A等級,很安全


********************************************************************************

SSLLabs 網站報告 TLS_RSA_WITH_AES_256_GCM_SHA384 和 TLS_RSA_WITH_AES_128_GCM_SHA384 是 WEAK,為什麼?

Copilot

SSLLabs 把 TLS_RSA_WITH_AES_256_GCM_SHA384 和 TLS_RSA_WITH_AES_128_GCM_SHA384 稱為弱密碼,主要原因是這些密碼套件不支援前向保密 (Forward Secrecy)。這意味著,如果攻擊者竊取了私鑰,他們可以解密過去的加密數據。


********************************************************************************

ChatGPT 說:

在 SSLLabs 的報告中,TLS_RSA_WITH_AES_256_GCM_SHA384 和 TLS_RSA_WITH_AES_128_GCM_SHA384 被標記為 "WEAK" 的原因主要和 RSA 金鑰交換有關。

  • RSA 金鑰交換的弱點:這些套件採用了 RSA 密鑰交換,這種交換方式在現代安全標準中被認為較弱,因為它無法提供前向安全性(Forward Secrecy)。前向安全性確保了即使伺服器的長期私鑰被攻破,過去的通訊記錄也不會受到影響。然而,RSA 金鑰交換無法提供此特性,使得它相對不夠安全。
  • 建議使用的替代套件:現今建議使用的加密套件多採用 ECDHE(橢圓曲線 Diffie-Hellman 臨時密鑰交換)以提供前向安全性,例如 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 或 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,這些套件通常會被 SSLLabs 評為「強」。
  • 瀏覽器相容性考量:隨著各大瀏覽器和安全標準對於 RSA 的支持逐漸減少,這些 RSA 密鑰交換套件的安全性問題變得更為突出。未來可能會逐步移除對這類套件的支持,以確保安全。

因此,在 SSLLabs 中,這些套件會被列為「WEAK」,主要是基於安全性上的考量而非加密強度本身。********************************************************************************

【關閉後剩下2個影響】

請問那些 Windows 或 Windows Server 支援 TLS_RSA_WITH_AES_256_GCM_SHA384 和 TLS_RSA_WITH_AES_128_GCM_SHA384,但不支援 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp521r1) 和 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp521r1) ?

ChatGPT 說:

Windows Server 2008 及以下版本:

  • 這些版本的 Windows 系統本身不支持較新版本的 ECDHE 密碼套件,也不支持 secp521r1 曲線(也稱為 NIST P-521 曲線)。因此在這些系統上,您只能使用較舊的 RSA 金鑰交換套件。
  • Windows Server 2008 SP2 和更舊的版本,原生缺少對 secp521r1 的支持,也缺少較新版本的 ECDHE 套件的支持。這些系統仍能支援基於 RSA 的密碼套件,如 TLS_RSA_WITH_AES_256_GCM_SHA384。

Windows 7 和 Windows Server 2008 R2:

  • 雖然這些版本具備部分 ECDHE 支持,但支援的橢圓曲線非常有限,預設不包括 secp521r1。
  • 在這些系統上,即使有 ECDHE 支持,只有較舊或更常見的橢圓曲線(如 secp256r1 或 secp384r1)可以運行。
  • 這些系統若未安裝特定的更新或未手動配置,也無法支持 secp521r1。

更新和設定的影響:

  • 某些 Windows 7 和 Windows Server 2008 R2 可能能夠透過特定更新和設定來支持更多的 ECDHE 套件,但對 secp521r1 支援仍有限制。許多組織選擇升級至更新的系統以獲得更強的 TLS 支援。

總結來說,Windows Server 2008 及更舊版本(包含 Windows 7 和 Windows Server 2008 R2)可能會支持基於 RSA 的 GCM 加密,但無法支持 secp521r1 曲線和相關的 ECDHE 密碼套件。如果您的需求包含 secp521r1 支持,考慮升級至 Windows 10、Windows Server 2016 或更新版本會更合適,因為這些版本有更全面的 TLS 和加密套件支持。

********************************************************************************

請問 Windows 8, 8.1, 10, 11, Windows Server 2019, 2022 都支援  TLS_RSA_WITH_AES_256_GCM_SHA384 和 TLS_RSA_WITH_AES_128_GCM_SHA384 嗎 ?

ChatGPT 說:

是的,以下是詳細資訊:

  • TLS 版本支援:這些密碼套件屬於 TLS 1.2 的一部分,因此需要啟用 TLS 1.2 或更新版本。Windows 8 和以上版本的作業系統(包括 Windows Server 2012 及更新的版本)均已支援 TLS 1.2。
  • 密碼套件支援:TLS_RSA_WITH_AES_256_GCM_SHA384 和 TLS_RSA_WITH_AES_128_GCM_SHA384 這兩種加密套件在 Windows 8.1 及更新版本中內建支援,包括 Windows Server 2012 R2、2016、2019、2022。
  • 啟用情況:根據系統的默認設置和應用需求,這些加密套件可能預設已啟用或可透過 Group Policy、Windows Registry 設置啟用。在 Windows Server 中,若為強化安全性,這些加密套件經常已預設啟用,但在 Windows 8 或更早版本中,可能需要手動設定。

如果需要確認是否啟用特定密碼套件,可以在伺服器或客戶端上使用 PowerShell 指令查看當前系統的 TLS 設定。

********************************************************************************

何謂 前向保密 (Forward Secrecy) ?

ChatGPT 說:

前向保密(Forward Secrecy,簡稱 FS)是一種加密屬性,旨在保護過去的加密通信,即便伺服器的長期私鑰被攻破,過去的會話密鑰仍無法被解密。這項技術確保了通訊記錄的安全性,即使未來密鑰洩露,也無法追溯性地解密已發生的通信。

前向保密的實現

實現前向保密的常見方法是使用臨時密鑰交換協議,如 ECDHE(橢圓曲線 Diffie-Hellman Ephemeral) 或 DHE(Diffie-Hellman Ephemeral),其中「Ephemeral」表示「臨時」。這些協議在每次通信會話中生成獨立的會話密鑰,會話結束後即被丟棄,不會被保存。

在前向保密中,每個會話的密鑰都是臨時的、唯一的,即使攻擊者未來成功取得伺服器的私鑰或其他長期密鑰,也無法解密過去的通信內容,因為這些臨時會話密鑰不再可用。

前向保密的好處

  • 防止回溯性攻擊:假如某天伺服器私鑰被洩露或破解,攻擊者無法利用這個私鑰解密以前的通訊數據。
  • 提升數據安全性:特別是對於敏感的資訊和長期保存的數據,前向保密能有效防止因密鑰洩露而造成的潛在風險。
  • 增強抗量子計算攻擊的能力:未來量子計算可能會讓破解某些加密變得更容易,而前向保密增加了額外的安全層,降低量子計算對過去通信的威脅。

沒有前向保密的風險

若使用不支援前向保密的協議(如 RSA 金鑰交換),伺服器的長期私鑰洩露後,攻擊者可以藉由此私鑰解密所有先前截獲的加密通信。因此,現代網絡安全普遍推薦採用支持前向保密的加密套件。

********************************************************************************

(完)

相關

[研究]Imperva WAF移除Active Ciphers方法
https://shaurong.blogspot.com/2024/10/imperva-wafactive-ciphers.html


2024年10月30日 星期三

[研究]ASP.NET, SummerNote 1.0.3 與 Bootstrap 3.4.1, 4.6.2, 5.3.3 相容測試

[研究]ASP.NET, SummerNote 1.0.3 與 Bootstrap 3.4.1, 4.6.2, 5.3.3 相容測試

2024-10-30

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

[研究]ASP.NET, 夏日筆記 Summernote 1.0.3 WYSIWYG HTML Editor 試用 (MIT)
https://shaurong.blogspot.com/2024/04/aspnetsummernote-wysiwyg-html-editor.html

********************************************************************************

NuGet 安裝 jQuery, bootstrap, summernote 等。

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
    Inherits="WebApplication1.Default"  ValidateRequest="false"  %>
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>

    <!-- CSS Files -->
<link href="Content/bootstrap.css" rel="stylesheet" />
<link href="Content/font-awesome.min.css" rel="stylesheet" />
<link href="Scripts/summernote/summernote.css" rel="stylesheet" />

<!-- JavaScript Files -->
<script type="text/javascript" src="Scripts/jquery-3.7.1.min.js"></script>
<script type="text/javascript" src="Scripts/bootstrap.min.js"></script>
<script type="text/javascript" src="Scripts/summernote/summernote.min.js"></script>
<!-- Custom JavaScript -->
<script type="text/javascript">
    $(document).ready(function () {
        $(".summernoteCssClass").summernote({
            placeholder: '請輸入內容...',
            tabsize: 2,
            height: 200
        });
        // Set background color to white
        $('.note-editable').css('background-color', 'white');
    });
</script>
</head>
<body>
    <form id="form1" runat="server">
        <asp:TextBox ID="TextBox1" CssClass="summernoteCssClass" runat="server"></asp:TextBox>
    </form>
</body>
</html>



Default.aspx.cs

using System;

namespace WebApplication1
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }
    }
}



【使用 Bootstrap 3.4.1 結果】


【使用 Bootstrap 4.6.2 結果】

【使用 Bootstrap 5.3.3 結果】

也就是 NuGet 說明只相依 FontAwesome >= 4.2.0,實際上不只。

官方網站
https://summernote.org/
說需要 Supports Bootstrap: 3.x.x to 5.x.x,但實際 4.6.2不行。

(完)

相關

2024年10月29日 星期二

[研究]ODF 1.4 (Open Document Format 1.4) 草案現況

[研究]ODF 1.4 (Open Document Format 1.4) 草案現況

2024-10-29

OpenDocument standardization
https://en.wikipedia.org/wiki/OpenDocument_standardization#OpenDocument_1.4

OASIS
https://en.wikipedia.org/wiki/OASIS_(organization)

OpenDocument
https://en.wikipedia.org/wiki/OpenDocument

  • Microsoft Office 2007 (with Service Pack 2 or 3) supports ODF 1.1[45] (Windows only)
  • Microsoft Office 2010 supports ODF 1.1 (Windows only)
  • Microsoft Office 2013 supports ODF 1.2 (Windows only)
  • Microsoft Office 2016 and 2019 support ODF 1.2 (Windows: read/write; OS X: read-only after online conversion[46])
  • Microsoft Office 2021 supports ODF 1.3[47] (Windows and MacOS)


Microsoft 365 apps now support OpenDocument Format 1.4
https://techcommunity.microsoft.com/t5/microsoft-365-insider-blog/microsoft-365-apps-now-support-opendocument-format-1-4/ba-p/4226735
Office 365 支援 ODF 1.4

What's new in Word 2024 for Windows and Mac
https://support.microsoft.com/en-us/office/what-s-new-in-word-2024-for-windows-and-mac-9fe36ecd-820b-4f42-a9a2-0861f7615954
Office 2024 支援 ODF 1.4

[MS-OODF14]: Office Implementation Information for ODF 1.4 Standards Support
https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oodf14/ad5a09c6-609d-47b3-bc56-7ab49a8d4f35

[ODF1.4] OASIS, "Open Document Format for Office Applications (OpenDocument) Version 1.4", https://go.microsoft.com/fwlink/?linkid=2255466

ODF GitHub
https://github.com/oasis-tcs/odf-tc/tree/master/docs
https://docs.oasis-open.org/office/OpenDocument/v1.4/csd01/

  • 2024-03-18
  • Updating CSD-01 from WD-03
  • CSD-01(Committee Specification Draft 01): 進入了更正式的標準化過程
  • WD-03(Working Draft 03)

ODF Specification Tooling
https://github.com/oasis-tcs/odf-tc

(待續)

[研究]ASP.NET,WebForm,免ODS套件寫入匯出.ods

[研究]ASP.NET,WebForm,免ODS套件寫入匯出.ods

2024-10-29

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default2.aspx.cs" 
    Inherits="WebApplication1.Default2" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">

    </form>
</body>
</html>



Default.aspx.cs

using System;
using System.IO;
using System.IO.Compression;

namespace WebApplication1
{
    public partial class Default2 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            GenerateOdsFile();
        }
        private void GenerateOdsFile()
        {
            using (MemoryStream odsStream = new MemoryStream())
            {
                using (ZipArchive zip = new ZipArchive(odsStream, ZipArchiveMode.Create, true))
                {
                    // 添加 mimetype 檔案
                    ZipArchiveEntry mimeEntry = zip.CreateEntry("mimetype", CompressionLevel.NoCompression);
                    using (StreamWriter writer = new StreamWriter(mimeEntry.Open()))
                    {
                        writer.Write("application/vnd.oasis.opendocument.spreadsheet");
                    }

                    // 添加必要的 META-INF/manifest.xml 文件
                    ZipArchiveEntry manifestEntry = zip.CreateEntry("META-INF/manifest.xml", CompressionLevel.Fastest);
                    using (StreamWriter writer = new StreamWriter(manifestEntry.Open()))
                    {
                        writer.Write(
                            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                            "<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n" +
                            "  <manifest:file-entry manifest:full-path=\"/\" manifest:media-type=\"application/vnd.oasis.opendocument.spreadsheet\"/>\n" +
                            "  <manifest:file-entry manifest:full-path=\"content.xml\" manifest:media-type=\"text/xml\"/>\n" +
                            "</manifest:manifest>"
                        );
                    }

                    // 添加 content.xml 文件
                    ZipArchiveEntry contentEntry = zip.CreateEntry("content.xml", CompressionLevel.Fastest);
                    using (StreamWriter writer = new StreamWriter(contentEntry.Open()))
                    {
                        writer.Write(
                            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                            "<office:document-content xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" " +
                            "xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" " +
                            "xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" " +
                            "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" " +
                            "office:version=\"1.2\">\n" +
                            "<office:body><office:spreadsheet><table:table table:name=\"Sheet1\" table:style-name=\"ta1\">\n" +
                            "<table:table-column table:style-name=\"co1\" table:number-columns-repeated=\"2\"/>\n" +
                            "<table:table-row table:style-name=\"ro1\"><table:table-cell><text:p>資料1</text:p></table:table-cell>" +
                            "<table:table-cell><text:p>資料2</text:p></table:table-cell></table:table-row>\n" +
                            "<table:table-row table:style-name=\"ro1\"><table:table-cell><text:p>資料3</text:p></table:table-cell>" +
                            "<table:table-cell><text:p>資料4</text:p></table:table-cell></table:table-row>\n" +
                            "</table:table></office:spreadsheet></office:body></office:document-content>"
                        );
                    }
                }

                odsStream.Position = 0;
                Response.Clear();
                Response.ContentType = "application/vnd.oasis.opendocument.spreadsheet";
                Response.AddHeader("Content-Disposition", "attachment; filename=sample.ods");
                odsStream.CopyTo(Response.OutputStream);
                Response.Flush();
                Response.End();
            }
        }
        //---
    }
}







結果 LibreOffice 7.6 正常讀取,但 Excel 2021開啟有警告,修復後正常顯示。這是因為Excel 對 .ods 文件有較嚴格的要求,尤其是 XML 標籤和屬性的結構。敝人嘗試多次,暫時仍無法解決,或許可以一開始用 LibreOffice建立一個正常的 template.ods 給程式插入資料使用。

Default.aspx.cs

using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Xml.Linq;

namespace WebApplication1
{
    public partial class Default3 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string odsFilePath = @"C:\Users\Administrator\Downloads\Template2.ods";
            string targetOdsPath = @"C:\Users\Administrator\Downloads\S2.ods";
            File.Copy(odsFilePath, targetOdsPath, overwrite: true);
            InsertDataToODS(targetOdsPath);
        }
        public void InsertDataToODS(string odsFilePath)
        {
            // 定義要插入的資料
            var data = new string[,]
            {
                { "A1", "B1" },
                { "A2", "B2" }
            };

            // 打開 .ods 檔案 (實際上是 Zip 檔案)
            using (var zip = ZipFile.Open(odsFilePath, ZipArchiveMode.Update))
            {
                // 尋找 content.xml
                var entry = zip.GetEntry("content.xml");
                if (entry == null)
                {
                    throw new FileNotFoundException("content.xml not found in the .ods file.");
                }

                // 讀取 content.xml 並載入 XML 文件
                XDocument doc;
                using (var stream = entry.Open())
                {
                    doc = XDocument.Load(stream);
                }

                // 尋找要插入資料的表格位置 (這裡假設是 Sheet1)
                XNamespace ns = "urn:oasis:names:tc:opendocument:xmlns:table:1.0";
                var sheet = doc.Descendants(ns + "table").FirstOrDefault();

                if (sheet != null)
                {
                    // 生成 2x2 表格的 Row 和 Cell
                    for (int i = 0; i < 2; i++)
                    {
                        var row = new XElement(ns + "table-row");
                        for (int j = 0; j < 2; j++)
                        {
                            var cell = new XElement(ns + "table-cell",
                                new XElement(ns + "p", data[i, j]));
                            row.Add(cell);
                        }
                        sheet.Add(row);
                    }
                }

                // 將修改後的 XML 內容重新寫入 content.xml
                using (var stream = entry.Open())
                {
                    stream.SetLength(0); // 清除原始內容
                    doc.Save(stream);
                }
            }
        }
        //---
    }
}

實際測試,還是有問題,在無 ODS 套件情況,想自己或靠 ChatGPT 的 Code 產出 Excel 2021 可以正常讀取的 .ods 並不容易,運氣好是警告,然後可以讀取,運氣不好是完全不能讀取。

(完)

相關

[研究]ASP.NET,WebForm,免ODS套件匯入讀取.ods

[研究]ASP.NET,WebForm,免ODS套件匯入讀取.ods

2024-10-28

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

免ODS套件讀取.ods】

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
    Inherits="WebApplication1.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:GridView ID="GridView1" runat="server"></asp:GridView>
    </form>
</body>
</html>



Default.aspx.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Xml.Linq;

namespace WebApplication1
{
    public class OdsReader
    {
        public static List<List<string>> ReadOdsFile(string filePath)
        {
            List<List<string>> data = new List<List<string>>();

            using (ZipArchive archive = ZipFile.OpenRead(filePath))
            {
                // 找到 content.xml 檔案
                ZipArchiveEntry contentEntry = archive.GetEntry("content.xml");
                if (contentEntry != null)
                {
                    using (StreamReader reader = new StreamReader(contentEntry.Open(), Encoding.UTF8))
                    {
                        string xmlContent = reader.ReadToEnd();
                        XDocument doc = XDocument.Parse(xmlContent);

                        // 解析 XML 檔案中的資料
                        foreach (var row in doc.Descendants("{urn:oasis:names:tc:opendocument:xmlns:table:}table-row"))
                        {
                            List<string> rowData = new List<string>();
                            foreach (var cell in row.Descendants("{urn:oasis:names:tc:opendocument:xmlns:table:}table-cell"))
                            {
                                string cellValue = cell.Element("{urn:oasis:names:tc:opendocument:xmlns:text:}p")?.Value ?? string.Empty;
                                rowData.Add(cellValue);
                            }
                            data.Add(rowData);
                        }
                    }
                }
            }
            return data;
        }
    }
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                //string filePath = Server.MapPath("~/path/to/your/file.ods");
                string filePath = @"C:\Users\Administrator\Downloads\Sample.ods";
                List<List<string>> odsData = ReadOdsFile(filePath);

                // 將資料綁定到 GridView
                BindGridView(odsData);
            }
        }
        private List<List<string>> ReadOdsFile(string filePath)
        {
            List<List<string>> data = new List<List<string>>();

            using (ZipArchive archive = ZipFile.OpenRead(filePath))
            {
                ZipArchiveEntry contentEntry = archive.GetEntry("content.xml");
                if (contentEntry != null)
                {
                    using (StreamReader reader = new StreamReader(contentEntry.Open(), Encoding.UTF8))
                    {
                        string xmlContent = reader.ReadToEnd();
                        XDocument doc = XDocument.Parse(xmlContent);

                        // 設定 XML 命名空間
                        XNamespace nsTable = "urn:oasis:names:tc:opendocument:xmlns:table:1.0";
                        XNamespace nsText = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";

                        // 解析 table-row 和 table-cell 元素
                        foreach (var row in doc.Descendants(nsTable + "table-row"))
                        {
                            List<string> rowData = new List<string>();
                            foreach (var cell in row.Descendants(nsTable + "table-cell"))
                            {
                                string cellValue = cell.Element(nsText + "p")?.Value ?? string.Empty;
                                rowData.Add(cellValue);
                            }
                            data.Add(rowData);
                        }
                    }
                }
            }

            return data;
        }

        private void BindGridView(List<List<string>> odsData)
        {
            // 將資料轉換為 DataTable
            var dataTable = new System.Data.DataTable();

            // 動態添加列
            for (int i = 0; i < odsData[0].Count; i++)
            {
                dataTable.Columns.Add($"Column{i + 1}");
            }

            // 添加資料行
            foreach (var row in odsData)
            {
                dataTable.Rows.Add(row.ToArray());
            }

            // 綁定資料到 GridView
            GridView1.DataSource = dataTable;
            GridView1.DataBind();
        }
        //---
    }
}



結果

下圖,若 Sample.ods 是 LibreOffice 7.6 建立的

下圖,若 Sample.ods 是 Excel 2021 建立的

其實一開始 ChatGPT 寫的程式完全不能用,後來把 XDocument doc = XDocument.Parse(xmlContent); 讀取到的 doc 丟給 ChatGPT,才改出可以用的程式。不確定此程式通用性多高,doc讀取到內容如下

<?xml version="1.0"?>

+
<office:document-content office:version="1.3"
	xmlns:presentation="urn:oasis:names:tc:opendocument:
	xmlns:presentation:1.0"
	xmlns:css3t="http://www.w3.org/TR/css3-text/"
	xmlns:grddl="http://www.w3.org/2003/g/data-view#"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:dom="http://www.w3.org/2001/xml-events"
	xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:
	xmlns:form:1.0"
	xmlns:script="urn:oasis:names:tc:opendocument:
	xmlns:script:1.0"
	xmlns:form="urn:oasis:names:tc:opendocument:
	xmlns:form:1.0"
	xmlns:math="http://www.w3.org/1998/Math/MathML"
	xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:
	xmlns:field:1.0"
	xmlns:loext="urn:org:documentfoundation:names:experimental:office:
	xmlns:loext:1.0"
	xmlns:xhtml="http://www.w3.org/1999/xhtml"
	xmlns:drawooo="http://openoffice.org/2010/draw"
	xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:
	xmlns:calcext:1.0"
	xmlns:tableooo="http://openoffice.org/2009/table"
	xmlns:xforms="http://www.w3.org/2002/xforms"
	xmlns:of="urn:oasis:names:tc:opendocument:
	xmlns:of:1.2"
	xmlns:oooc="http://openoffice.org/2004/calc"
	xmlns:ooow="http://openoffice.org/2004/writer"
	xmlns:number="urn:oasis:names:tc:opendocument:
	xmlns:datastyle:1.0"
	xmlns:table="urn:oasis:names:tc:opendocument:
	xmlns:table:1.0"
	xmlns:chart="urn:oasis:names:tc:opendocument:
	xmlns:chart:1.0"
	xmlns:svg="urn:oasis:names:tc:opendocument:
	xmlns:svg-compatible:1.0"
	xmlns:dr3d="urn:oasis:names:tc:opendocument:
	xmlns:dr3d:1.0"
	xmlns:draw="urn:oasis:names:tc:opendocument:
	xmlns:drawing:1.0"
	xmlns:rpt="http://openoffice.org/2005/report"
	xmlns:text="urn:oasis:names:tc:opendocument:
	xmlns:text:1.0"
	xmlns:style="urn:oasis:names:tc:opendocument:
	xmlns:style:1.0"
	xmlns:meta="urn:oasis:names:tc:opendocument:
	xmlns:meta:1.0"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:xlink="http://www.w3.org/1999/xlink"
	xmlns:fo="urn:oasis:names:tc:opendocument:
	xmlns:xsl-fo-compatible:1.0"
	xmlns:ooo="http://openoffice.org/2004/office"
	xmlns:office="urn:oasis:names:tc:opendocument:
	xmlns:office:1.0">

(完)

相關

[研究]LibreOffice 24.8.2 SDK 可以單獨安裝嗎?

[研究]LibreOffice 24.8.2 SDK 可以單獨安裝嗎?

2024-10-29

沒有安裝 LibreOffice 24.8.2,LibreOffice 24.8.2 SDK 可以安裝成功嗎?

https://zh-tw.libreoffice.org/download/download-libreoffice/

LibreOffice_24.8.2_Win_x86-64_sdk.msi









測試是32或64位元版本

C:\Program Files\LibreOffice_24.8_SDK\sdk\cli>sigcheck64.exe *.dll

Sigcheck v2.90 - File version and signature viewer
Copyright (C) 2004-2022 Mark Russinovich
Sysinternals - www.sysinternals.com

C:\Program Files\LibreOffice_24.8_SDK\sdk\cli\cli_basetypes.dll:
        Verified:       Unsigned
        Link date:      ?? 07:25 2024/9/24
        Publisher:      n/a
        Company:        OpenOffice.org
        Description:
        Product:        n/a
        Prod version:   1.0.20.0
        File version:   1.0.20.0
        MachineType:    32-bit
C:\Program Files\LibreOffice_24.8_SDK\sdk\cli\cli_cppuhelper.dll:
        Verified:       Unsigned
        Link date:      ?? 07:47 2024/9/24
        Publisher:      n/a
        Company:        n/a
        Description:    n/a
        Product:        n/a
        Prod version:   n/a
        File version:   n/a
        MachineType:    64-bit
C:\Program Files\LibreOffice_24.8_SDK\sdk\cli\cli_oootypes.dll:
        Verified:       Unsigned
        Link date:      ?? 07:47 2024/9/24
        Publisher:      n/a
        Company:        n/a
        Description:    n/a
        Product:        n/a
        Prod version:   n/a
        File version:   n/a
        MachineType:    32-bit
C:\Program Files\LibreOffice_24.8_SDK\sdk\cli\cli_ure.dll:
        Verified:       Unsigned
        Link date:      ?? 07:47 2024/9/24
        Publisher:      n/a
        Company:        OpenOffice.org
        Description:
        Product:        n/a
        Prod version:   1.0.23.0
        File version:   1.0.23.0
        MachineType:    32-bit
C:\Program Files\LibreOffice_24.8_SDK\sdk\cli\cli_uretypes.dll:
        Verified:       Unsigned
        Link date:      ?? 07:47 2024/9/24
        Publisher:      n/a
        Company:        n/a
        Description:    n/a
        Product:        n/a
        Prod version:   n/a
        File version:   n/a
        MachineType:    32-bit

C:\Program Files\LibreOffice_24.8_SDK\sdk\cli>

DLL 檔案的用途說明:

  • cli_basetypes.dll:此 DLL 提供了基本類型的定義和支援,通常用於處理基本數據類型,例如整數、浮點數和其他基本類型的功能。
  • cli_cppuhelper.dll:這個 DLL 提供了 C++ UNO (Universal Network Objects) 的輔助工具,通常用於 UNO 組件的管理和操作。它為開發者提供了便捷的 API 來處理 C++ UNO 對象。
  • cli_oootypes.dll:此 DLL 定義了與 LibreOffice 中的基本 UNO 對象相關的類型,主要用於與 LibreOffice API 進行交互。它提供了一些基本的 UNO 類型和接口。
  • cli_ure.dll:這個 DLL 是 URE (Universal Runtime Environment) 的一部分,提供了 UNO 的運行時環境,支援多種語言的 UNO 組件,並確保這些組件能在 LibreOffice 中正常運行。
  • cli_uretypes.dll:此 DLL 定義了 URE 中的基本類型,支援在 UNO 和 LibreOffice 中使用的常見數據類型。它幫助開發者在其應用程式中正確處理這些類型。

(完)

[研究]LibreOffice 邁入 24.x 版時代

[研究]LibreOffice 邁入 24.x 版時代

2024-10-29

https://zh-tw.libreoffice.org/download/download-libreoffice/

發現以前提供7.6.x版下載,現在發現沒了。(何時變的敝人不知)








(下圖)檢查更新,目前 7.6.7.2,顯示可更新到24.2.6版 (上圖下方的版本)




但是下方的 SDK 只提供 24.8.2,不提供 24.2.6版。


(完)




[研究]ASP.NET,WebForm,用 MiniExcel 1.34.2匯出、匯入 .xlsx (不支援 .ods)

[研究]ASP.NET,WebForm,用 MiniExcel 1.34.2匯出、匯入 .xlsx (不支援 .ods)

2024-10-28

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

Fast, Low-Memory, Easy Excel .NET helper to import/export/template spreadsheet
用於匯入/匯出/範本電子表格的快速、低記憶體、簡單的 Excel .NET 助手

Github : https://github.com/mini-software/MiniExcel

Gitee : https://gitee.com/dotnetchina/MiniExcel

Issues : https://github.com/mini-software/MiniExcel/issues

Todo : https://github.com/mini-software/MiniExcel/projects/1?fullscreen=true

授權 Apache-2.0

匯入、匯出範例:https://github.com/mini-software/MiniExcel?tab=readme-ov-file#getstart1

********************************************************************************

【匯出.xlsx】

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
    Inherits="WebApplication1.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
    </form>
</body>
</html>



Default.aspx.cs

using MiniExcelLibs;
using System;
using System.Collections.Generic;
using System.IO;

namespace WebApplication1
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            var data = new List<Dictionary<string, object>>
            {
                new Dictionary<string, object> { { "Name", "Alice" }, { "Age", 25 }, { "City", "Taipei" } },
                new Dictionary<string, object> { { "Name", "Bob" }, { "Age", 30 }, { "City", "Kaohsiung" } }
            };

            // 設定 Response 內容
            Response.Clear();
            Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            Response.AddHeader("Content-Disposition", "attachment;filename=ExportData.xlsx");

            // 匯出 Excel
            using (var stream = new MemoryStream())
            {
                MiniExcel.SaveAs(stream, data);
                stream.WriteTo(Response.OutputStream);
                Response.Flush();
            }

            Response.End();
        }
    }
}



********************************************************************************

【匯入.xlsx】

Default2.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default2.aspx.cs" 
    Inherits="WebApplication1.Default2" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:FileUpload ID="FileUpload1" runat="server" /><br />
        <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /><br />
        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="true" />
    </form>
</body>
</html>


Default2aspx.cs

using MiniExcelLibs;
using System;
using System.Data;

namespace WebApplication1
{
    public partial class Default2 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {

            if (FileUpload1.HasFile)
            {
                try
                {
                    // 獲取上傳的檔案流
                    using (var stream = FileUpload1.PostedFile.InputStream)
                    {
                        // 使用 MiniExcel 讀取 Excel 檔案
                        //var data = stream.ReadExcel();
                        //var table = MiniExcel.QueryAsDataTable(stream, useHeaderRow: true);
                        //var table = MiniExcel.QueryAsDataTable(stream, useHeaderRow: false);
                        var table = MiniExcel.QueryAsDataTable(stream);

                        // 創建一個新的 DataTable 用於存放處理過的資料
                        DataTable processedTable = new DataTable();

                        // 添加列到 processedTable
                        foreach (DataColumn column in table.Columns)
                        {
                            processedTable.Columns.Add(column.ColumnName, typeof(string));
                            //processedTable.Columns.Add(column.ColumnName, typeof(System.String)); //也可
                        }

                        // 逐行逐列處理資料
                        foreach (DataRow row in table.Rows)
                        {
                            DataRow newRow = processedTable.NewRow();
                            for (int i = 0; i < table.Columns.Count; i++)
                            {
                                newRow[i] = row[i]; // 這裡可以進行自定義處理
                            }
                            processedTable.Rows.Add(newRow);
                        }
                        GridView1.DataSource = processedTable;
                        GridView1.DataBind();
                    }
                }
                catch (Exception ex)
                {
                    // 處理例外情況
                    Response.Write($"錯誤: {ex.Message}");
                }
            }
            else
            {
                Response.Write("請選擇一個檔案進行匯入。");
            }
        }
        //---
    }
}

結果



(完)

相關

[研究]ASP.NET,WebForm,用 EPPlus 7.4.2 匯入、匯出 .xlsx (不支援 .ods)

[研究]ASP.NET,WebForm,用 EPPlus 7.4.2 匯入、匯出 .xlsx  (不支援 .ods)

2024-10-28

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

官方:https://www.epplussoftware.com/

Commerical License and Pricing:https://www.epplussoftware.com/en/LicenseOverview/

License FAQ:https://www.epplussoftware.com/en/LicenseOverview/LicenseFAQ

Noncommercial/free use

  • Can I use EPPlus without a commercial license internally within a commercial company?
  • No, all usage within an commercial company requires a commercial license.

  • Can I use EPPlus for my personal project?
  • Yes, the polyform NC license permits personal use. See Polyform Noncommercial.

  • Can I use EPPlus for free in my project?
  • You can use EPPlus for free if you qualify as a non-commercial organization, See Polyform Noncommercial.

********************************************************************************

相依

  • EPPlus.Interfaces.6.1.1
  • EPPlus.System.Drawing.6.1.1
  • System.Buffers.4.5.1
  • System.ComponentModel.Annotations.5.0.0
  • System.Numerics.Vectors.4.5.0
  • System.Runtime.CompilerServices.Unsafe.4.5.3
  • System.Memory.4.5.5
  • Microsoft.IO.RecyclableMemoryStream.3.0.1
  • EPPlus.7.4.2

********************************************************************************

【匯出成為.xlsx檔案】

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
    Inherits="WebApplication1.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
    </form>
</body>
</html>


Default.aspx.cs

using OfficeOpenXml; // EPPlus 命名空間
using System;
using System.Data; // 假設資料來自 DataTable
using System.IO;

namespace WebApplication1
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            // 設置 EPPlus 授權為非商業用途
            ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

            // 假設資料來自於 DataTable
            DataTable dt = GetData();

            using (ExcelPackage package = new ExcelPackage())
            {
                ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Sheet1");

                // 加入資料到 Excel 工作表
                worksheet.Cells["A1"].LoadFromDataTable(dt, true);

                // 設定標題行的樣式
                using (var range = worksheet.Cells["A1:XFD1"])
                {
                    range.Style.Font.Bold = true;
                    range.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
                    range.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGray);
                }

                // 設定回應內容
                Response.Clear();
                Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                Response.AddHeader("content-disposition", "attachment; filename=Export.xlsx");

                // 將 Excel 資料寫入回應
                using (MemoryStream stream = new MemoryStream())
                {
                    package.SaveAs(stream);
                    stream.WriteTo(Response.OutputStream);
                    Response.Flush();
                    Response.End();
                }
            }
        }
        private DataTable GetData()
        {
            // 模擬資料
            DataTable dt = new DataTable();
            dt.Columns.Add("Column1");
            dt.Columns.Add("Column2");

            dt.Rows.Add("資料1", "資料2");
            dt.Rows.Add("資料3", "資料4");

            return dt;
        }
    }
}



Please set the ExcelPackage.LicenseContext property. See https://epplussoftware.com/developers/licenseexception

Default.aspx.cs 要加上一行

 // 設置 EPPlus 授權為非商業用途
 ExcelPackage.LicenseContext = LicenseContext.NonCommercial;  

再測試




********************************************************************************

【匯入.xlsx檔案】

Default2.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default2.aspx.cs" 
    Inherits="WebApplication1.Default2" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:FileUpload ID="fileUpload" runat="server" /><br />
        <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /><br />
        <asp:GridView ID="gridView" runat="server"></asp:GridView>
    </form>
</body>
</html>


Default2.aspx.cs

using OfficeOpenXml; // EPPlus 命名空間
using System;
using System.Data;
using System.IO;

namespace WebApplication1
{
    public partial class Default2 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            // 確認是否有上傳檔案
            if (fileUpload.HasFile && Path.GetExtension(fileUpload.FileName).Equals(".xlsx"))
            {
                // 設置 EPPlus 授權為非商業用途
                ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

                using (var package = new ExcelPackage(fileUpload.FileContent))
                {
                    // 取得第一個工作表
                    ExcelWorksheet worksheet = package.Workbook.Worksheets[0];
                    DataTable dt = new DataTable();

                    // 建立 DataTable 欄位名稱
                    foreach (var headerCell in worksheet.Cells[1, 1, 1, worksheet.Dimension.End.Column])
                    {
                        dt.Columns.Add(headerCell.Text);
                    }

                    // 讀取資料列並加入 DataTable
                    for (int row = 2; row <= worksheet.Dimension.End.Row; row++)
                    {
                        DataRow dr = dt.NewRow();
                        for (int col = 1; col <= worksheet.Dimension.End.Column; col++)
                        {
                            dr[col - 1] = worksheet.Cells[row, col].Text;
                        }
                        dt.Rows.Add(dr);
                    }

                    // 將資料綁定至 GridView 控制項
                    gridView.DataSource = dt;
                    gridView.DataBind();
                }
            }
            else
            {
                // 顯示錯誤訊息(可選)
                Response.Write("<script>alert('請上傳 .xlsx 格式的 Excel 檔案');</script>");
            }
        }
        //---
    }
}



(完)

相關

2024年10月28日 星期一

[研究]ASP.NET,WebForm,使用 OfficeConverter 1.7.10 轉換 .ods 和 .xlsx

[研究]ASP.NET,WebForm,使用 OfficeConverter 1.7.10 轉換 .ods 和 .xlsx

2024-10-28

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

相依套件很多

WebApplication1

正在安裝:

Newtonsoft.Json.13.0.3

OpenMcdf.2.3.1

RtfPipe.2.0.7677.4303

System.Buffers.4.5.1

System.Drawing.Common.8.0.8

System.Numerics.Vectors.4.5.0

System.Runtime.CompilerServices.Unsafe.6.0.0

System.Memory.4.5.5

Microsoft.Extensions.Primitives.8.0.0

Microsoft.IO.RecyclableMemoryStream.3.0.1

Microsoft.Maui.Graphics.8.0.82

System.Diagnostics.DiagnosticSource.8.0.0

System.Security.Cryptography.Pkcs.8.0.0

System.Security.Principal.Windows.5.0.0

System.Security.AccessControl.5.0.0

Microsoft.Win32.Registry.5.0.0

System.Threading.Tasks.Extensions.4.5.4

Microsoft.Bcl.AsyncInterfaces.8.0.0

Microsoft.Extensions.DependencyInjection.Abstractions.8.0.0

Microsoft.Extensions.DependencyInjection.8.0.0

Microsoft.Extensions.Logging.Abstractions.8.0.0

SharpZipLib.1.4.2

System.ValueTuple.4.5.0

Microsoft.Extensions.Options.8.0.0

Microsoft.Extensions.Logging.8.0.0

UTF.Unknown.2.5.1

MsgReader.5.6.5

PasswordProtectedChecker.1.3.10

OfficeConverter.1.7.9

********************************************************************************

WebApplication1

更新:

MsgReader.5.6.5 -> MsgReader.5.6.6

Microsoft.Extensions.Logging.8.0.0 -> Microsoft.Extensions.Logging.8.0.1

Microsoft.Extensions.Options.8.0.0 -> Microsoft.Extensions.Options.8.0.2

Microsoft.Extensions.Logging.Abstractions.8.0.0 -> Microsoft.Extensions.Logging.Abstractions.8.0.2

Microsoft.Extensions.DependencyInjection.8.0.0 -> Microsoft.Extensions.DependencyInjection.8.0.1

Microsoft.Extensions.DependencyInjection.Abstractions.8.0.0 -> Microsoft.Extensions.DependencyInjection.Abstractions.8.0.2

System.Security.AccessControl.5.0.0 -> System.Security.AccessControl.6.0.1

System.Security.Cryptography.Pkcs.8.0.0 -> System.Security.Cryptography.Pkcs.8.0.1

System.Diagnostics.DiagnosticSource.8.0.0 -> System.Diagnostics.DiagnosticSource.8.0.1

Microsoft.Maui.Graphics.8.0.82 -> Microsoft.Maui.Graphics.8.0.92

System.Drawing.Common.8.0.8 -> System.Drawing.Common.8.0.10

Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1 -> Microsoft.CodeDom.Providers.DotNetCompilerPlatform.4.1.0

********************************************************************************


安裝了一堆SDK API檔案

  • \CLI\x64
  • \CLI\x86
  • \CLI\x64\cli_basetypes.dll
  • \CLI\x64\cli_cppuhelper.dll
  • \CLI\x64\cli_oootypes.dll
  • \CLI\x64\cli_ure.dll
  • \CLI\x64\cli_uretypes.dll
  • \CLI\x86\cli_basetypes.dll
  • \CLI\x86\cli_cppuhelper.dll
  • \CLI\x86\cli_oootypes.dll
  • \CLI\x86\cli_ure.dll
  • \CLI\x86\cli_uretypes.dll

********************************************************************************

Default.aspx.cs

using System;

namespace WebApplication1
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            using (var converter = new OfficeConverter.Converter())
            {
                converter.Convert(@"C:\temp\2.ods", @"C:\temp\2.xlsx");
                converter.Convert(@"C:\temp\2.xlsx", @"C:\temp\3.ods");
            }
        }
    }
}



********************************************************************************


********************************************************************************

'/' 應用程式中發生伺服器錯誤。

無法載入檔案或組件 'cli_cppuhelper' 或其相依性的其中之一。 試圖載入格式錯誤的程式。

描述: 在執行目前 Web 要求的過程中發生未處理的例外狀況。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。

例外狀況詳細資訊: System.BadImageFormatException: 無法載入檔案或組件 'cli_cppuhelper' 或其相依性的其中之一。 試圖載入格式錯誤的程式。

原始程式錯誤:

在執行目前 Web 要求期間,產生未處理的例外狀況。如需有關例外狀況來源與位置的資訊,可以使用下列的例外狀況堆疊追蹤取得。


組件載入追蹤: 下列資訊在確定為何無法載入組件 'cli_cppuhelper' 時是有幫助的。

=== 繫結前狀態資訊 ===
記錄: DisplayName = cli_cppuhelper
 (Partial)
警告: 提供了組件的部分繫結資訊:
警告: 組件名稱: cli_cppuhelper | 網域 ID: 2
警告: 如果只提供部分的組件顯示名稱,就會發生部分繫結。 
警告: 這可能會使繫結器載入不正確的組件。
警告: 建議為組件提供完全指定的文字識別,
警告: 該識別是由簡單名稱、版本、文化特性和公開金鑰語彙基元組成。
警告: 如需詳細資訊和這個問題的一般解決方法,請參閱白皮書 http://go.microsoft.com/fwlink/?LinkId=109270。
記錄: Appbase = file:///C:/CodeTemp4/WebApplication1/WebApplication1/
記錄: 初始 PrivatePath = C:\CodeTemp4\WebApplication1\WebApplication1\bin
正在呼叫組件 : (Unknown)。
===
記錄: 此繫結在 default 載入內容中開始。
記錄: 正在使用應用程式組態檔: C:\CodeTemp4\WebApplication1\WebApplication1\web.config
記錄: 使用主機組態檔: C:\Users\Administrator\Documents\IISExpress\config\aspnet.config
記錄: 從 C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config 使用電腦組態檔。
記錄: 目前不會套用原則至參考 (私用、自訂、部分或以位置為主的組件繫結)。
記錄: 正在嘗試從新的 URL file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/Temporary ASP.NET Files/vs/79e525c4/a5ece37c/cli_cppuhelper.DLL 下載。
記錄: 正在嘗試從新的 URL file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/Temporary ASP.NET Files/vs/79e525c4/a5ece37c/cli_cppuhelper/cli_cppuhelper.DLL 下載。
記錄: 正在嘗試從新的 URL file:///C:/CodeTemp4/WebApplication1/WebApplication1/bin/cli_cppuhelper.DLL 下載。
錯誤: 無法完成組件的安裝 (hr = 0x8007000b)。已終止探查。


堆疊追蹤:

[BadImageFormatException: 無法載入檔案或組件 'cli_cppuhelper' 或其相依性的其中之一。 試圖載入格式錯誤的程式。]
   System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +0
   System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +37
   System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +159
   System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection) +80
   System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +22
   System.Reflection.Assembly.Load(String assemblyString) +29
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +38

[ConfigurationErrorsException: 無法載入檔案或組件 'cli_cppuhelper' 或其相依性的其中之一。 試圖載入格式錯誤的程式。]
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +726
   System.Web.Configuration.CompilationSection.LoadAllAssembliesFromAppDomainBinDirectory() +196
   System.Web.Configuration.CompilationSection.LoadAssembly(AssemblyInfo ai) +45
   System.Web.Compilation.BuildManager.GetReferencedAssemblies(CompilationSection compConfig) +172
   System.Web.Compilation.BuildManager.GetPreStartInitMethodsFromReferencedAssemblies() +91
   System.Web.Compilation.BuildManager.CallPreStartInitMethods(String preStartInitListPath, Boolean& isRefAssemblyLoaded) +111
   System.Web.Compilation.BuildManager.ExecutePreAppStart() +156
   System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException) +695

[HttpException (0x80004005): 無法載入檔案或組件 'cli_cppuhelper' 或其相依性的其中之一。 試圖載入格式錯誤的程式。]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +660
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +89
   System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +189



版本資訊: Microsoft .NET Framework 版本:4.0.30319; ASP.NET 版本:4.8.4762.0

********************************************************************************

無法載入檔案或組件 'cli_cppuhelper' 或其相依性的其中之一。 試圖載入格式錯誤的程式。

ChatGPT 說:

這個錯誤通常是由於程式或函式庫的版本不相容或安裝錯誤引起的。cli_cppuhelper 組件常與 OpenOffice 或 LibreOffice API 有關,尤其是在.NET 應用程式中。以下是一些可能的解決方案:

確認程式和函式庫版本相容:檢查 cli_cppuhelper 所屬的函式庫版本與您使用的 .NET 版本是否相容。例如,如果您使用的是 32 位元版本的函式庫,確保您的應用程式也針對 32 位元進行編譯(64 位元同理)。

安裝或重新安裝必須的函式庫:如果您在使用 LibreOffice 或 OpenOffice SDK,請確認其已安裝,並且將其路徑包含在專案的參考中。

設定正確的應用程式架構:在 Visual Studio 中,設定專案的目標架構(x86 或 x64)來符合所安裝的函式庫架構。

清除與重建專案:有時候重新清理並重建專案可以解決這類錯誤。在 Visual Studio 中,選擇 建置 -> 清除方案,然後重新建置。

若問題仍然存在,您可以檢查專案中的內部例外錯誤訊息,以獲取更多詳細的問題資訊。

********************************************************************************

過往使用 LibreOffice SDK 或 OpenOffice SDK 經驗不佳,不想測試了。

********************************************************************************

(完)

相關

[研究]ASP.NET,WebForm,使用 OfficeConverter 1.7.10 轉換 .ods 和 .xlsx
https://shaurong.blogspot.com/2024/10/aspnetwebform-officeconverter-1710-ods.html

[研究] [C#] 使用 LibreOffice 6.2.6 SDK、OpenOffice 4.1.6 SDK讀取/寫入試算表(Calc) 檔案 (.ods)
https://shaurong.blogspot.com/2019/08/c-libreoffice-626-sdk-calc-ods.html

[研究] [C#] 使用 OpenOffice 4.1.3 SDK 讀取試算表(Calc) 檔案 (.ods)
http://shaurong.blogspot.com/2016/12/c-openoffice-413-sdk-calc-ods.html

[研究] [C#] 使用 LibreOffice 5.1.6、5.3.0 SDK 讀取試算表(Calc) 檔案 (.ods)
http://shaurong.blogspot.com/2016/12/c-libreoffice-516-sdk-calc-ods.html

[研究] [C#] 讀取 LibreOffice、OpenOffice 的試算表(Calc) 檔案 (.ods)(使用 .NET 4.5 的 ZipFile)
http://shaurong.blogspot.com/2016/12/c-libreoffice-516-calc-ods-net-45.html

[研究] [C#] 使用 Apose.Cells 讀取 LibreOffice 5.1.6、OpenOffice 4.1.3 試算表(Calc) 檔案 (.ods)
http://shaurong.blogspot.com/2017/01/c-aposecells-libreoffice-516openoffice.html

[研究] [C#] 使用 GemBox.Spreadsheet 讀取LibreOffice、OpenOffice試算表(Calc) 檔案 (.ods)
http://shaurong.blogspot.com/2016/12/c-gemboxspreadsheet-libreofficeopenoffi.html

[研究] OpenOffice 4.1.3 試算表(Calc) 保護鎖定儲存格不被修改
http://shaurong.blogspot.com/2016/12/openoffice-413-calc.html

[研究] 使用OpenOffice 4.1.3試算表(Calc)建立「下拉式選單」來輸入資料
http://shaurong.blogspot.com/2016/12/openoffice-413calc.html

[研究]ASP.NET,WebForm,用 FreeDataExports 1.1.11 匯出 .ods (MIT)

[研究]ASP.NET,WebForm,用 FreeDataExports 1.1.11 匯出 .ods (MIT)

2024-03-29

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

https://www.nuget.org/packages/FreeDataExports/1.1.11/License

授權是 MIT



********************************************************************************

官方網站
https://github.com/ryankueter/FreeDataExports

官方的程式範例有問題。

Web.Config

<?xml version="1.0" encoding="utf-8"?>
<!--
  如需如何設定 ASP.NET 應用程式的詳細資訊,請前往
  https://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <connectionStrings>
    <add name="MyDBConnectionString" connectionString="Data Source=.;Initial Catalog=MyDB;User ID=sa;Password=密碼"
      providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.8" />
    <httpRuntime targetFramework="4.8" />
  </system.web>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701" />
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
    </compilers>
  </system.codedom>
</configuration>

Default.aspx.cs

using FreeDataExports;

protected void Button1_Click(object sender, EventArgs e)
{
    string path = @"C:\Temp\2.ods";
    var workbook = new DataExport().CreateODSv1_3();
    var worksheet = workbook.AddWorksheet("工作表1");

    string[] customHeaders = { "Column1", "Column2", "Column3" }; // 依需要替換為實際的列名

    // 查詢語句
    string query = "SELECT * FROM [MyDB].[dbo].[MyTable]";

    using (SqlConnection connection = new SqlConnection(
        WebConfigurationManager.ConnectionStrings["MyDBConnectionString"].ConnectionString))
    {
        using (SqlCommand command = new SqlCommand(query, connection))
        {
            using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command))
            {
                DataTable dataTable = new DataTable();
                dataAdapter.Fill(dataTable);

                // 新增自訂標題
                worksheet.AddRow();
                for (int i = 0; i < customHeaders.Length; i++)
                {
                    worksheet.AddCell(customHeaders[i], DataType.String);
                }

                // 匯出資料到.ods文件
                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    worksheet.AddRow();
                    for (int j = 0; j < dataTable.Columns.Count; j++)
                        worksheet.AddCell(dataTable.Rows[i].ItemArray[j], DataType.String);
                }
                workbook.Save(path);
            }
        }
    }
}


實際測試可以成功。

********************************************************************************

Default.aspx.cs

protected void Button2_Click(object sender, EventArgs e)
{
    var workbook = new DataExport().CreateODSv1_3();
    var worksheet = workbook.AddWorksheet("工作表1");

    string[] customHeaders = { "Column1", "Column2", "Column3" }; // 依需要替換為實際的列名

    // 查詢語句
    string query = "SELECT * FROM [MyDB].[dbo].[MyTable]";

    using (SqlConnection connection = new SqlConnection(
        WebConfigurationManager.ConnectionStrings["MyDBConnectionString"].ConnectionString))
    {
        using (SqlCommand command = new SqlCommand(query, connection))
        {
            using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command))
            {
                DataTable dataTable = new DataTable();
                dataAdapter.Fill(dataTable);

                // 新增自訂標題
                worksheet.AddRow();
                for (int i = 0; i < customHeaders.Length; i++)
                {
                    worksheet.AddCell(customHeaders[i], DataType.String);
                }

                // 匯出資料到.ods文件
                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    worksheet.AddRow();
                    for (int j = 0; j < dataTable.Columns.Count; j++)
                        worksheet.AddCell(dataTable.Rows[i].ItemArray[j], DataType.String);
                }

                // 使用 MemoryStream 將檔案直接下載
                using (MemoryStream stream = new MemoryStream())
                {
                    workbook.Save(stream);
                    stream.Position = 0;

                    // 設定回應頭,讓瀏覽器顯示下載提示
                    Response.Clear();
                    Response.ContentType = "application/vnd.oasis.opendocument.spreadsheet";
                    Response.AddHeader("Content-Disposition", "attachment; filename=ExportedData.ods");
                    Response.BinaryWrite(stream.ToArray());
                    Response.Flush();
                    Response.End();
                }
            }
        }
    }
}

編譯 workbook.Save(stream); 會出錯


個錯誤是因為 Save 方法預期的是一個檔案路徑(字串類型),而不是 MemoryStream。可以檢查 CreateODSv1_3 所使用的類別庫是否支援儲存至 MemoryStream,若無,則需要調整程式碼。

********************************************************************************

【先暫存再彈出,成功】

Default.aspx.cs

protected void Button3_Click(object sender, EventArgs e)
{
    //string tempFilePath = Server.MapPath("~/Temp/ExportedData.ods"); // 暫存檔案路徑
    string tempFilePath = @"C:\temp\ExportedData.ods"; // 暫存檔案路徑
    var workbook = new DataExport().CreateODSv1_3();
    var worksheet = workbook.AddWorksheet("工作表1");

    string[] customHeaders = { "Column1", "Column2", "Column3" }; // 依需要替換為實際的列名

    // 查詢語句
    string query = "SELECT * FROM [MyDB].[dbo].[MyTable]";

    using (SqlConnection connection = new SqlConnection(
        WebConfigurationManager.ConnectionStrings["MyDBConnectionString"].ConnectionString))
    {
        using (SqlCommand command = new SqlCommand(query, connection))
        {
            using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command))
            {
                DataTable dataTable = new DataTable();
                dataAdapter.Fill(dataTable);

                // 新增自訂標題
                worksheet.AddRow();
                for (int i = 0; i < customHeaders.Length; i++)
                {
                    worksheet.AddCell(customHeaders[i], DataType.String);
                }

                // 匯出資料到.ods文件
                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    worksheet.AddRow();
                    for (int j = 0; j < dataTable.Columns.Count; j++)
                        worksheet.AddCell(dataTable.Rows[i].ItemArray[j], DataType.String);
                }

                // 儲存至暫存路徑
                workbook.Save(tempFilePath);

                // 讀取檔案內容並下載
                byte[] fileBytes = System.IO.File.ReadAllBytes(tempFilePath);
                Response.Clear();
                Response.ContentType = "application/vnd.oasis.opendocument.spreadsheet";
                Response.AddHeader("Content-Disposition", "attachment; filename=ExportedData.ods");
                Response.BinaryWrite(fileBytes);
                Response.Flush();
                Response.End();

                // 刪除暫存檔案
                System.IO.File.Delete(tempFilePath);
            }
        }
    }
}


********************************************************************************

(完)

相關

[研究]ASP.NET,WebForm,用 FreeDataExports 1.1.11 匯出 .ods
https://shaurong.blogspot.com/2024/10/aspnetwebform-freedataexports-1111-ods.html

[研究]ASP.NET,WebForm,要傳遞 SqlDataSource1.SelectParameters 當時的值https://shaurong.blogspot.com/2024/03/aspnetwebform-sqldatasource1selectparam.html

[研究]ASP.NET,WebForm,用 FreeDataExports 1.1.9 匯出資料庫某資料表成 .ods
https://shaurong.blogspot.com/2024/03/aspnetwebform-freedataexports-119-ods_29.html

[研究]ASP.NET,WebForm,用 FreeDataExports 1.1.9 匯出 .ods
https://shaurong.blogspot.com/2024/03/aspnetwebform-freedataexports-119-ods.html

[研究]ASP.NET,WebForm, 把 OdsReadWrite.cs 從 Ionic.Zip 或 DotNetZip 改成用 System.IO.Compression
https://shaurong.blogspot.com/2024/03/aspnetwebform-odsreadwritecs-ioniczip.html

[研究]ASP.NET,WebForm,用 OdsReaderWriter + DotNetZip (Ionic.Zip) 1.16.0 共用匯出 .ods
https://shaurong.blogspot.com/2024/03/aspnetwebform-odsreaderwriter-dotnetzip_79.html

[研究]ASP.NET,WebForm,用 OdsReaderWriter + DotNetZip (Ionic.Zip) 1.16.0 匯出 .ods
https://shaurong.blogspot.com/2024/03/aspnetwebform-odsreaderwriter-dotnetzip_23.html

[研究]ASP.NET,WebForm,用 OdsReaderWriter + DotNetZip (Ionic.Zip) 1.16.0 匯入 .ods
https://shaurong.blogspot.com/2024/03/aspnetwebform-odsreaderwriter-dotnetzip_93.html

How to Read and Write ODF/ODS Files (OpenDocument Spreadsheets) - CodeProject
https://www.codeproject.com/Articles/38425/How-to-Read-and-Write-ODF-ODS-Files-OpenDocument-2

[研究][ASP.NET]讀取、匯出、寫入、匯入 Excel .xlsx .xls ODF .ods
https://shaurong.blogspot.com/2020/04/caspnetwebform-excel-xlsx-xls-odf-ods.html

[研究][ASP.NET]使用 OdsReaderWriter + DotNetZip 1.15.0 (Ionic.Zip) 匯出寫入 .ods
https://shaurong.blogspot.com/2021/02/aspnet-odsreaderwriter-dotnetzip-1150_9.html

[研究][ASP.NET]使用 OdsReaderWriter + DotNetZip 1.15.0 讀取匯入 .ods 到資料庫
https://shaurong.blogspot.com/2021/02/aspnet-odsreaderwriter-dotnetzip-1150.html

[研究][C#]用OdsReaderWrite匯出(寫入)、匯入(讀取) ODF/.ods 檔案 (使用 Ionic.Zip、DotNetZip)
https://shaurong.blogspot.com/2020/09/caspnetwebform-ioniczip-odfods.html

[研究] [C#] 用OdsReadWrite讀取 LibreOffice、OpenOffice 的試算表(Calc) 檔案 (.ods)(使用 .NET 4.5 的 ZipFile)
https://shaurong.blogspot.com/2016/12/c-libreoffice-516-calc-ods-net-45.html

[研究] [C#] 用OdsReaderWrite讀取 LibreOffice 5.1.6 的試算表(Calc) 檔案 (.ods)(使用 DotNetZip)
https://shaurong.blogspot.com/2016/12/c-libreoffice-516-calc-ods.html

NuGet Gallery | OdsReaderWriter 1.0.10
https://www.nuget.org/packages/OdsReaderWriter

sortings/OdsReadWrite at master · Luviz/sortings · GitHub
https://github.com/Luviz/sortings/tree/master/OdsReadWrite