web office apps 在线预览实践

摘要

在一些项目中需要在线预览office文档,包括word,excel,ppt等。达到预览文档的目的有很多方法,可以看我之前总结,在线预览的n种方案:

[Asp.net]常见word,excel,ppt,pdf在线预览方案,有图有真相,总有一款适合你!

,由于客户那里有安装web office apps服务,调用该服务就可以实现文档的在线预览,所以在项目中就采用了这种方式,下面列出了实践步骤。

步骤

定义文件信息:

 该信息用来调用web office apps服务回调查找文件信息时用到。

    public class CheckFileInfo
    {
        public CheckFileInfo();

        public string BaseFileName { get; set; }
        public string OwnerId { get; set; }
        public long Size { get; set; }
        public string SHA256 { get; set; }
        public string Version { get; set; }
    }

获取文件信息的接口

    public interface IFileHelper
    {
        Task<CheckFileInfo> GetFileInfo(string fileMD5);
        Task<string> GetSHA256Async(string url);
        string GetSHA256Async(byte[] buffer);
    }

接口实现

   public class FileHelper : IFileHelper
    {
        FileBusiness _FileBusiness;
        public FileHelper()
        {
            _FileBusiness = new FileBusiness();
        }
        /// <summary>
        /// 获取文件信息
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public async Task<CheckFileInfo> GetFileInfo(string fileMD5)
        {
            var fileInfo = _FileBusiness.FindFileByMD5(fileMD5);
            if (fileInfo != null)
            {
                var rv = new CheckFileInfo
                {
                    Version = DateTime.Now.ToString("s"),
                    Size = Convert.ToInt64(fileInfo.FileSize),
                    OwnerId = fileInfo.Itcode,
                    BaseFileName = fileInfo.FileName,
                    SHA256 = fileInfo.SHA256
                };
                if (string.IsNullOrEmpty(fileInfo.SHA256))
                {
                    rv.SHA256 = await GetSHA256Async(fileInfo.Url);
                    fileInfo.SHA256 = rv.SHA256;
                    await _FileBusiness.UpldateAsyncByUrl(fileInfo);
                }
                return rv;
            }
            else
            {
                return null;
            }
        }
        public async Task<string> GetSHA256Async(string url)
        {
            string sha256 = string.Empty;
            using (var sha = SHA256.Create())
            {
                WebClient webClient = new WebClient();
                byte[] buffer = await webClient.DownloadDataTaskAsync(url);
                byte[] checksum = sha.ComputeHash(buffer);
                sha256 = Convert.ToBase64String(checksum);
            }
            return sha256;
        }


        public string GetSHA256Async(byte[] buffer)
        {
            string sha256 = string.Empty;
            using (var sha = SHA256.Create())
            {
                WebClient webClient = new WebClient();
                byte[] checksum = sha.ComputeHash(buffer);
                sha256 = Convert.ToBase64String(checksum);
            }
            return sha256;
        }
    }

这里用到了文件分布式存储,要预览的放在了另外的文件服务器上面,所以这里使用webclient下载,获取到文件信息,保存在数据库中,如果存在则直接返回。当然,你可以使用FileStream来读取文件的响应信息。

获取文件预览的地址

根据web office apps服务的地址,文件扩展名获取预览的link

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>
        /// <returns></returns>
        public string GetDocumentLink(string fileMD5, string ext)
        {
            string apiUrl = string.Format(ConfigManager.OWA_MY_VIEW_URL, fileMD5);
            return string.Format("{0}{1}{2}&access_token={3}", ConfigManager.OWA_URL, FindUrlByExtenstion(ext), apiUrl, fileMD5);
        }
        /// <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('.');
            }
            Dictionary<string, string> dic = new Dictionary<string, string>() 
            { 
            {"ods","/x/_layouts/xlviewerinternal.aspx?WOPISrc="},
            {"xls", "/x/_layouts/xlviewerinternal.aspx?WOPISrc="},
            {"xlsb", "/x/_layouts/xlviewerinternal.aspx?WOPISrc="},
            {"xlsm", "/x/_layouts/xlviewerinternal.aspx?WOPISrc="},
            {"xlsx", "/x/_layouts/xlviewerinternal.aspx?WOPISrc="},
            {"one", "/o/onenoteframe.aspx?WOPISrc="},
            {"onetoc2", "/o/onenoteframe.aspx?WOPISrc="},
            {"odp", "/p/PowerPointFrame.aspx?WOPISrc="},
            {"pot", "/p/PowerPointFrame.aspx?WOPISrc="},
            {"potm", "/p/PowerPointFrame.aspx?WOPISrc="},
            {"potx", "/p/PowerPointFrame.aspx?WOPISrc="},
            {"pps", "/p/PowerPointFrame.aspx?WOPISrc="},
            {"ppsm", "/p/PowerPointFrame.aspx?WOPISrc="},
            {"ppsx", "/p/PowerPointFrame.aspx?WOPISrc="},
            {"ppt", "/p/PowerPointFrame.aspx?WOPISrc="},
            {"pptm", "/p/PowerPointFrame.aspx?WOPISrc="},
            {"pptx", "/p/PowerPointFrame.aspx?WOPISrc="},
            {"doc", "/wv/wordviewerframe.aspx?WOPISrc="},
            {"docm", "/wv/wordviewerframe.aspx?WOPISrc="},
            {"docx", "/wv/wordviewerframe.aspx?WOPISrc="},
            {"dot", "/wv/wordviewerframe.aspx?WOPISrc="},
            {"dotm", "/wv/wordviewerframe.aspx?WOPISrc="},
            {"dotx", "/wv/wordviewerframe.aspx?WOPISrc="},
            {"pdf", "/wv/wordviewerframe.aspx?WOPISrc="}
            };
            return dic[ext];
        }
    }
}

web office apps 预览接口回调使用的api时,需要注意尽量传递id之类,如果传递name,文件名涉及到了中文,会有编码的问题,所以我这里传递的是文件的md5值。

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
{
    /// <summary>
    /// Primary class for WOPI interface.  Supporting the 2 minimal API calls
    /// requred for base level View
    /// </summary>
    public class FilesController : ApiController
    {
        IFileHelper _fileHelper;
        HttpResponseMessage _response;
        /// <summary>
        /// Base constructor
        /// </summary>
        public FilesController()
        {
            _fileHelper = new FileHelper();
            _response = new HttpResponseMessage(HttpStatusCode.Accepted);
            //允许哪些url可以跨域请求到本域
            _response.Headers.Add("Access-Control-Allow-Origin", "*");
            //允许的请求方法,一般是GET,POST,PUT,DELETE,OPTIONS
            _response.Headers.Add("Access-Control-Allow-Methods", "POST");
            //允许哪些请求头可以跨域
            _response.Headers.Add("Access-Control-Allow-Headers", "x-requested-with,content-type");
        }
        /// <summary>
        /// Required for WOPI interface - on initial view
        /// </summary>
        /// <param name="name">file name</param>
        /// <returns></returns>        
        public async Task<CheckFileInfo> Get(string name)
        {
            return await _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>
        public async Task<CheckFileInfo> Get(string name, string access_token)
        {
            return await _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>
        public async Task<HttpResponseMessage> GetFile(string name, string access_token)
        {
            try
            {
                _response.StatusCode = HttpStatusCode.OK;
                FileBusiness FileBusiness = new FileBusiness();
                var file = FileBusiness.FindFileByMD5(name);
                if (file != null)
                {
                    WebClient webClient = new WebClient();
                    byte[] buffer = await webClient.DownloadDataTaskAsync(file.Url);
                    MemoryStream stream = new MemoryStream(buffer);
                    _response.Content = new StreamContent(stream);
                    _response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
                }
                return _response;
            }
            catch (Exception ex)
            {
                _response.StatusCode = HttpStatusCode.InternalServerError;
                var stream = new MemoryStream(UTF8Encoding.Default.GetBytes(ex.Message ?? ""));
                _response.Content = new StreamContent(stream);
                return _response;
            }
        }
    }
}

路由配置

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace WebSite.OfficeViewerService
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务
            // Web API 路由
            config.Routes.MapHttpRoute(
                 name: "Contents",
                 routeTemplate: "api/wopi/files/{name}/contents",
                 defaults: new { controller = "files", action = "GetFile" }
                 );
            config.Routes.MapHttpRoute(
                name: "FileInfo",
                routeTemplate: "api/wopi/files/{name}",
                defaults: new { controller = "Files", action = "Get" }
                );
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { controller = "Files", id = RouteParameter.Optional }
            );
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Web.Mvc;
using WebSite.OfficeViewerService.Helpers;

namespace WebSite.OfficeViewerService.Controllers
{
    public class HomeController : Controller
    {
        IFileHelper _fileHelper = new FileHelper();
        public ActionResult Index()
        {
            return View();
        }
        public async Task<ActionResult> Viewer(string url, string name)
        {
            string itcode = string.Empty;
            try
            {
                if (string.IsNullOrEmpty(url))
                {
                    throw new ArgumentNullException("Sorry,Url is errr,the file is not found");
                }
string fileExt = url.Substring(url.LastIndexOf('.')); WopiAppHelper wopiHelper = new WopiAppHelper(); FileBusiness FileBusiness = new FileBusiness(); var file = FileBusiness.FindFileByUrl(url); string fileMD5 = string.Empty; if (file == null) { WebClient webClient = new WebClient(); byte[] buffer = await webClient.DownloadDataTaskAsync(url); fileMD5 = MD5Helper.GetMD5FromFile(buffer);string sha256 = _fileHelper.GetSHA256Async(buffer); await fastDFSFileBusiness.SaveAsync(new FastDFSFile { Dt = DateTime.Now, FileMd5 = fileMD5, FileName = name, FileSize = buffer.Length, Itcode = itcode, Url = url, SHA256 = sha256 }); } else { fileMD5 = file.FileMd5; } var result = wopiHelper.GetDocumentLink(fileMD5, fileExt); return Redirect(result); } catch (Exception ex) { ViewBag.Message = ex.Message; } return View(); } } }

包装预览接口,其它应用通过传递文件的url和文件名称,然后跳转到实际的预览界面。简单粗暴,不用每个应用都在实现上面的方法。

原文地址:https://www.cnblogs.com/wolf-sun/p/6646309.html