摘要
在使用office web apps实现office文档在线预览的时候,需要注意的地方。
web api
web api作为owa在线预览服务回调的接口,这里面核心代码片段如下:
using H5.Business;
using H5.Business.Log;
using H5.Enums;
using H5.Model;
using H5.Utility;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Hosting;
using System.Web.Http;
using WebSite.OfficeViewerService.Helpers;
namespace WebSite.OfficeViewerService.Controllers.Api
{
[RoutePrefix("api/wopi")]
public class FilesController : ApiController
{
IFileHelper _fileHelper;
HttpResponseMessage _response;
ILog _log;
/// <summary>
/// Base constructor
/// </summary>
public FilesController()
{
_fileHelper = new FileHelper();
_response = new HttpResponseMessage(HttpStatusCode.OK);
_log = new DbLog(LogSource.WebLog, AppNameType.office_view);
}
/// <summary>
/// Required for WOPI interface - on initial view
/// </summary>
/// <param name="name">file name</param>
/// <returns></returns>
[HttpGet]
[Route("files/{name}")]
public CheckFileInfo Get(string name)
{
_log.Info(new LogModel { Content = "get fileinfo by name", Op = "get_fileinfo" });
return _fileHelper.GetFileInfo(name);
}
/// <summary>
/// Required for WOPI interface - on initial view
/// </summary>
/// <param name="name">file name</param>
/// <param name="access_token">token that WOPI server will know</param>
/// <returns></returns>
[HttpGet]
[Route("files/{name}")]
public CheckFileInfo Get(string name, string access_token)
{
_log.Info(new LogModel { Content = "get fileinfo by name&access_token", Op = "get_fileinfo" });
return _fileHelper.GetFileInfo(name);
}
/// <summary>
/// Required for View WOPI interface - returns stream of document.
/// </summary>
/// <param name="name">file name</param>
/// <param name="access_token">token that WOPI server will know</param>
/// <returns></returns>
[HttpGet]
[Route("files/{name}/contents")]
public HttpResponseMessage GetFile(string name, string access_token)
{
_log.Info(new LogModel { Content = "get file contents by name&access_token", Op = "get_fileinfo" });
return DownLoadFileStream(name, access_token);
}
/// <summary>
/// get owa file
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
[Route("files/{name}/contents")]
public HttpResponseMessage GetFile(string name)
{
_log.Info(new LogModel { Content = "get file contents by name", Op = "get_fileinfo" });
return DownLoadFileStream(name, string.Empty);
}
private HttpResponseMessage DownLoadFileStream(string name, string access_token)
{
try
{
_log.InfoAsync(new LogModel { Content = name + "_" + access_token, Itcode = string.Empty,
Op = "Office_View_GetFile" }); FastDFSFileBusiness fastDFSFileBusiness = new FastDFSFileBusiness();
var file = fastDFSFileBusiness.FindFastDFSFileByMD5(name);
if (file != null)
{
using (WebClient webClient = new WebClient())
{
byte[] buffer = webClient.DownloadData(file.Url);
_log.Info(new LogModel { Content = "download file success", Op = "get_fileinfo" });
MemoryStream stream = new MemoryStream(buffer);
_response.Content = new StreamContent(stream);
_response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
}
}
return _response;
}
catch (Exception ex)
{
_log.Error(new LogModel { Ex = ex, Op = "Office_View_GetFile_err" });
_response.StatusCode = HttpStatusCode.InternalServerError;
var stream = new MemoryStream(UTF8Encoding.Default.GetBytes(ex.Message ?? ""));
_response.Content = new StreamContent(stream);
return _response;
}
}
}
}
需要注意:在获取文件流的时候,不要是否文件流,不然会造成有的文件预览正常,有的预览报错。
fileHelper用来获取文件信息,这里文件统一上传到文件服务器fastdfs上,通过下载文件流设置文件信息,在传递文件的时候,使用文件md5进行传递,避免因为文件名出现中文名或者空格造成编码问题。
构造owa预览地址
using H5.Utility;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Xml.Serialization;
namespace WebSite.OfficeViewerService.Helpers
{
/// <summary>
///
/// </summary>
public class WopiAppHelper
{
public WopiAppHelper() { }
/// <summary>
/// 获取office在线预览的链接
/// </summary>
/// <param name="fileMD5"></param>
/// <param name="ext"></param>
/// <param name="fileUrl"></param>
/// <returns></returns>
public string GetDocumentLink(string fileMD5, string ext, string fileUrl)
{
string apiUrl = string.Format(ConfigManager.OWA_MY_VIEW_URL, fileMD5);
string findUrl = FindUrlByExtenstion(ext);
if (!string.IsNullOrEmpty(findUrl))
{
return string.Format("{0}{1}{2}&access_token={3}", ConfigManager.OWA_URL, findUrl, apiUrl, fileMD5);
}
else
{
return fileUrl;
}
}
/// <summary>
/// 根据文件扩展名获取预览url
/// </summary>
/// <param name="ext"></param>
/// <returns></returns>
private string FindUrlByExtenstion(string ext)
{
if (string.IsNullOrEmpty(ext))
{
throw new ArgumentNullException("extension is empty.");
}
if (ext.IndexOf(".") >= 0)
{
//如果包含.则进行过滤
ext = ext.TrimStart('.').ToLower();
}
string url = string.Empty;
switch (ext)
{
case "ods":
case "xls":
case "xlsb":
case "xlsm":
case "xlsx":
url = "/x/_layouts/xlviewerinternal.aspx?WOPISrc=";
break;
case "one":
case "onetoc2":
url = "/o/onenoteframe.aspx?WOPISrc=";
break;
case "odp":
case "pot":
case "potm":
case "potx":
case "pps":
case "ppsm":
case "ppsx":
case "ppt":
case "pptm":
case "pptx":
url = "/p/PowerPointFrame.aspx?WOPISrc=";
break;
case "doc":
case "docm":
case "docx":
case "dot":
case "dotm":
case "dotx":
url = "/wv/wordviewerframe.aspx?WOPISrc=";
break;
default:
break;
}
return url;
}
}
}
总结
在开发中因为涉及到回调,最好找一个代理的工具,比如ngrok将机器代理到外网,方便调试开发。