65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ASP.NET 上上传和转换 PowerPoint、Excel、Visio、Word 为 HTML

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (13投票s)

2012年12月28日

CPOL

5分钟阅读

viewsIcon

50425

downloadIcon

2982

将 Microsoft Office 的 PowerPoint、Excel、Visio 或 Word 文件上传到 Web 服务器,这些文件将被转换为 HTML 并作为文档链接托管在上传页上。

引言

这个OfficeHTMLConverter类库和OfficeToHTMLWeb ASP.NET Web项目可以将 Microsoft Office 文档(PowerPoint、Excel、Visio 或 Word)转换为 Web 服务器上的 HTML。任何绑定到提供的母版页的 ASP.NET 页面都会在页脚中呈现一个文件上传部分,允许将 Microsoft Office 文档以上传链接的形式上传到页面。Office 文档本身将被转换为 HTML(包括图像、内容和文件结构),并在上传 Office 文档的页面上动态创建指向转换后 Office 文档的链接。

必备组件

背景

最近在工作中处理一个间歇性的基于 Web 的 Office 自动化问题时,我花了一些时间来仔细研究新版 Microsoft Office 的自动化。  正如 Microsoft 警告的那样,不建议在服务器上自动化 Office 产品。Office 产品经过优化,可作为客户端应用程序运行,并使用桌面进行交互。

我有一段时间没有处理 Office 自动化了,并且这个问题仍然在我脑海中,我决定在 ASP.NET 下尝试 Office 自动化,以便更多地了解 Microsoft 建议不在共享托管环境中使用它的原因。即使这种实现方式不被 Microsoft 推荐,我也想看看 Office 自动化在负载下的表现。我有一段时间没有接触 Office 自动化了,我对大多数 Office 应用程序支持的“另存为 Web”功能印象深刻。几分钟之内,我就准备好了一个 Office 助手类(OfficeHTMLConverter)和一个简单的测试平台(OfficeToHTMLWeb)。我决定修改我的母版页,允许在任何使用此母版页的 ASP.NET 窗体上上传和转换 Office 文档。此外,我决定添加一个页面趋势功能,用于统计访问次数最多的页面。

解释

OfficeToHTMLWeb 助手程序集包含两个类,其中一个(Converter)负责 PowerPoint、Excel、Visio 和 Word 的 HTML 转换,另一个(UploadedFileInfo)负责跟踪上传的文件名及其相对 Web 路径。OfficeToHTMLWeb 项目  提供了利用母版页中的 OfficeToHTMLWeb 程序集的 ASP.NET 示例 Web 页面。母版页在页面页脚中渲染一个部分,该部分允许上传 Office 文档以及任何先前已上传并转换为 HTML 的文档链接。将鼠标悬停在现有的上传链接上将显示上传并转换为 HTML 的文档的 JavaScript 预览。

OfficeHTMLConverter.Converter 类是主要的处理者。该程序集包含对 Office Interop 程序集的引用。

...
using Word = Microsoft.Office.Interop.Word;
using Visio = Microsoft.Office.Interop.Visio;
using VisioWeb = Microsoft.Office.Interop.Visio.SaveAsWeb;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using Excel = Microsoft.Office.Interop.Excel;
using Microsoft.Office.Interop;
using Microsoft.Office.Core;
...

Converter 类提供了许多静态 List 函数,它们返回 `FileUploadInfo` 对象集合,其中包含正在上传的任何 PowerPoint、Excel、Visio 和 Word Office 文档类型的文件的名称和相对 Web 路径。`sourceFilePath` 参数是已上传的原始 Office 文档的实际路径,`targetDirectory` 参数是文档的 HTML `SaveAs` 转换应该发生的确切 Web 路径。

public static List<UploadedFileInfo> ToHTML(string sourceFilePath, string targetDirectory)

`ToHTML()` 函数将确定正在处理的文档类型,并根据上传文件的扩展名将请求转发到相应的静态函数。

switch (fileInfo.Extension.ToLower())
{
  case ".doc":
  case ".docx":
     result = WordToHTML(refSourceFilePath, refTargetDirectory);
     break;
  case ".xls":
  case ".xlsx":
     result = ExcelToHTML(refSourceFilePath.ToString(), refTargetDirectory.ToString());
     break;
  case ".ppt":
  case ".pptx":
     result = PowerPointToHTML(refSourceFilePath.ToString(), refTargetDirectory.ToString());
     break;
  case ".vsd":
  case ".vsdx":
     result = VisioToHTML(refSourceFilePath.ToString(), refTargetDirectory.ToString());
     break;
                
  default:
     throw new Exception(fileInfo.Extension.ToLower() + " files are not supported");
}

四种 Office 文档类型各自处理其相应文档类型的 HTML 转换,需要不同的转换器函数。以 `WordToHTML()` 静态函数为例,我们可以看到创建了一个 Word 应用程序实例和一个 Interop Word 文档集合接口。

...
Word._Application word = new Word.Application();
Word.Documents documents = word.Documents;
...

通过 `OpenNoRepairDialog()` 函数打开 Word 文档,并特别注意静默或抑制任何对话框或用户输入,因为这将在 Web 服务器上执行。

...
string fileName = Path.GetFileName(refSourceFileName.ToString());
Word.Document document = documents.OpenNoRepairDialog(ref refSourceFileName, ref refTrue,
  ref refFalse, ref refFalse, ref refMissing,
  ref refMissing, ref refMissing, ref refMissing,
  ref refMissing, ref refMissing, ref refMissing,
  ref refTrue, ref refFalse, ref refMissing,
  ref refMissing, ref refMissing);
...

实际的 HTML 转换由 Word 自动化对象通过其 `SaveAs()` 函数处理。

...
object newRefTargetDirectory = Path.Combine(refTargetDirectory.ToString(), fileName + ".htm");
word.ActiveDocument.SaveAs(ref newRefTargetDirectory, ref wdFormatHTML,
  ref refMissing, ref refMissing, ref refMissing,
  ref refMissing, ref refMissing, ref refMissing,
  ref refMissing, ref refMissing, ref refMissing,
  ref refMissing, ref refMissing, ref refMissing,
  ref refMissing, ref refMissing);
...

Microsoft 定义 `SaveAs()` 参数如下

void SaveAs
(
        [In, Optional] ref object FileName, 
        [In, Optional] ref object FileFormat, 
        [In, Optional] ref object LockComments, 
        [In, Optional] ref object Password, 
        [In, Optional] ref object AddToRecentFiles, 
        [In, Optional] ref object WritePassword, 
        [In, Optional] ref object ReadOnlyRecommended, 
        [In, Optional] ref object EmbedTrueTypeFonts, 
        [In, Optional] ref object SaveNativePictureFormat, 
        [In, Optional] ref object SaveFormsData, 
        [In, Optional] ref object SaveAsAOCELetter, 
        [In, Optional] ref object Encoding, 
        [In, Optional] ref object InsertLineBreaks, 
        [In, Optional] ref object AllowSubstitutions, 
        [In, Optional] ref object LineEnding, 
        [In, Optional] ref object AddBiDiMarks
);

Site.Master.cs 类通过 ImportFile 函数处理实际的文件上传。每当单击“上传”按钮并且 `System.Web.UI.WebControls.FileUpload` 控件包含数据时,都会调用此函数。

public void ImportFile(string fileName, byte[] fileData)

`ImportFile()` 函数确定哪个页面负责上传并确定文件的存储位置。如果目标目录尚不存在,`ImportFile()` 函数会创建它。然后打开文件并读取到 `FileStream` 对象中。

...
//  Save the raw file to local webserver storage
string pageName = Path.GetFileNameWithoutExtension(Page.AppRelativeVirtualPath);
string rawDirectory = Path.Combine(ConfigurationManager.AppSettings["TargetDirectory"], pageName);
string rawFilePath = Path.Combine(rawDirectory, fileName);

//  Ensure the local storage directory path exists
Directory.CreateDirectory(rawDirectory);

//  Write the file byte array to local storage as the original file name
FileStream stream = new FileStream(rawFilePath, FileMode.Create);
...

打开后,`ImportFile()` 将确保创建将用于保存正在上传的文件的 HTML 转换的目标目录。`OfficeHTMLConverter.Converter.ToHTML()` 静态函数被调用来处理转换过程。

...
//  Save the raw file as HTML to the web directory
List<UploadedFileInfo> results = OfficeHTMLConverter.Converter.ToHTML(rawFilePath, webDirectory);
...

此时,Office 文档已转换为 HTML 并存储。剩下的就是存储有关此新 Web 目录的信息:它在哪里、何时创建、要在其中显示 Web 路径链接的页面名称以及谁创建了上传。我选择不使用数据库,而是使用本地 XML 数据集。此 XML 文件存储在 `/Resources/OfficeUploads.xml` 文件中,并由名为 `BusinessObjectFramework.DLL` 的辅助程序集管理,该程序集是我几年前编写的。此 DLL 已包含在 OfficeToHTMLWeb ASP.NET Web 项目的 `/Resources/bin` 项目文件夹中。

...
//  Read in the page visits data file
DataSet dataSet = DataAccess.ReadXMLDataSet(resources + @"\Resources\OfficeUploads.xml");
...

当渲染绑定到母版页的页面时,`DisplayUploadDocuments()` 函数在页面的 `OnLoad()` 函数中被调用。`DisplayUploadDocuments()` 收集正在渲染的页面的名称,并确定 XML 序列化数据集 `/Resources/OfficeUploads.xml` 中是否存在该页面的已转换上传。先前的上传被呈现为 HTML 锚点,其 `onMouseOver` 和 `onMouseOut` 事件分别连接到 `previewURL` 和 `closePreview` JavaScript 函数。每当单击已转换的文档链接时,都会调用 JavaScript 函数 `viewLink()`。

...
//  Read database and display file links for this page
string pageName = Path.GetFileNameWithoutExtension(Page.AppRelativeVirtualPath);
//  Update OfficeUploads
string resources = Server.MapPath("~");
if (File.Exists(resources + @"\Resources\OfficeUploads.xml"))
{
  //  Read in the page visits data file
  DataSet dataSet = DataAccess.ReadXMLDataSet(resources + @"\Resources\OfficeUploads.xml");
...

结论

正如您所见,这是 ASP.NET 下 Office 自动化的一种相对简单的实现。我没有花很多时间来妥善处理异常,因为我更感兴趣的是了解当前 Office 自动化与早期版本相比的性能。请记住,Microsoft 不建议在共享 Web 服务器环境中使用 Office 自动化,并且我遇到了以下 Microsoft 支持链接 中讨论的几乎所有问题。

历史

·         2012 年 12 月 28 日:初始版本。

© . All rights reserved.