Asp.net与office web apps的整合

智者不为愚者谋,勇者不为怯者死。这篇文章主要讲述Asp.net与office web apps的整合相关的知识,希望能为你提供帮助。
事实上网上有关office  web  app的整合已经有相关的文章了,典型的是怎样整合Office Web Apps至自己开发的系统(一)  和怎样整合Office Web Apps至自己开发的系统(二),微软官网也有对应的demo。
这里在简单描写叙述一下原理吧:office  web  apps(owas)扮演者一个客服端,它会訪问我们asp.net  网站的文件然后呈现出来。而我们经常使用的API主要有例如以下3个:
GET api/wopi/files/{name}?access_token={access_token}      
GET api/wopi/files/{name}/contents?
access_token={access_token}      
POST api/wopi/files/{name}/contents?access_token={access_token}
至于每一个API做什么  这里就不多说。第一个是owas  检查文件,传递的信息是json数据格式,第二个是owas获取文件流,第三个是owas  post的文件流(保存改动文件)。首先我们来看看第一个API的实现:

[Route("files/{name}/")] public CheckFileInfo GetFileInfo(string name, string access_token) { Validate(name, access_token); var fileInfo = _fileHelper.GetFileInfo(name); bool updateEnabled = false; if (bool.TryParse(WebConfigurationManager.AppSettings["updateEnabled"].ToString(), out updateEnabled)) { fileInfo.SupportsUpdate = updateEnabled; fileInfo.UserCanWrite = updateEnabled; fileInfo.SupportsLocks = updateEnabled; } return fileInfo; }

这里的 Validate(name, access_token)  方法主要是验证请求的文件名称name与參数access_token是否一致。主要是验证是否是非法訪问。返回一个CheckFileInfo对象。CheckFileInfo的定义例如以下:

public class CheckFileInfo { public CheckFileInfo() { this.SupportsUpdate = false; this.UserCanWrite = false; } public string BaseFileName { get; set; } public string OwnerId { get; set; } public long Size { get; set; } //in bytes public string SHA256 { get; set; } //SHA256: A 256 bit SHA-2-encoded [FIPS180-2] hash of the file contents public string Version { get; set; }//changes when file changes. public bool SupportsUpdate { get; set; } public bool UserCanWrite { get; set; } public bool SupportsLocks { get; set; } }


如今在来看看第二个api的实现。主要返回相应文件的数据流:

[Route("files/{name}/contents")] public HttpResponseMessage Get(string name, string access_token) { try { Validate(name, access_token); var file = HostingEnvironment.MapPath("~/App_Data/" + name); var responseMessage = new HttpResponseMessage(HttpStatusCode.OK); var stream = new FileStream(file, FileMode.Open, FileAccess.Read); responseMessage.Content = new StreamContent(stream); responseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); return responseMessage; } catch (Exception ex) { var errorResponseMessage = new HttpResponseMessage(HttpStatusCode.InternalServerError); var stream = new MemoryStream(UTF8Encoding.Default.GetBytes(ex.Message ?? "")); errorResponseMessage.Content = new StreamContent(stream); return errorResponseMessage; } }


而第三个api是将返回的数据流保存到物理文件:

[Route("files/{name}/contents")] public async void Post(string name, [FromUri] string access_token) { var body = await Request.Content.ReadAsByteArrayAsync(); var appData = https://www.songbingjia.com/android/HostingEnvironment.MapPath("~/App_Data/"); var fileExt = name.Substring(name.LastIndexOf(\'.\') + 1); var outFile = Path.Combine(appData,name); File.WriteAllBytes(outFile, body); }


如今我们再来看看怎样请求owas。也就是相应的url是怎么产生的。
比如我的owas  server是owas.contoso.com。那么我们在配置好owas后就能够訪问http://owas.contoso.com/hosting/discovery 如图:
Asp.net与office web apps的整合

文章图片

  这里我们以excel为例    大家看到上面有view、edit、mobileview三个action。这里的app是一个excel。我们知道我们物理文件的后缀找到相应的app。在依据我们系统的配置採用edit还是view  action,假设是pdf  我们仅仅能採用相应的view。假设请求是mobile发起的话, 那么我们仅仅能用mobileview。  找到相应的action后我们就获取到相应的urlsrc属性,这里我们实际须要的url地址是 http://owas.contoso.com/x/_layouts/xlviewerinternal.aspx这个东东。那么获取这个url的代码例如以下:
public class LinkController : ApiController { /// < summary> /// Provides a link that can be used to Open a document in the relative viewer /// from the Office Web Apps server /// < /summary> /// < param name="fileRequest"> indicates the request type< /param> /// < returns> A link usable for HREF< /returns> public Link GetLink([FromUri] FileRequest fileRequest) { if (ModelState.IsValid) { var xml = WebConfigurationManager.AppSettings["appDiscoveryXml"]; var wopiServer = WebConfigurationManager.AppSettings["appWopiServer"]; bool updateEnabled = false; bool.TryParse(WebConfigurationManager.AppSettings["updateEnabled"], out updateEnabled); WopiAppHelper wopiHelper = new WopiAppHelper(HostingEnvironment.MapPath(xml), updateEnabled); var result = wopiHelper.GetDocumentLink(wopiServer + fileRequest.name); var rv = new Link { Url = result }; return rv; }throw new ApplicationException("Invalid ModelState"); } }public class WopiAppHelper { string _discoveryFile; bool _updateEnabled = false; WopiHost.wopidiscovery _wopiDiscovery; public WopiAppHelper(string discoveryXml) { _discoveryFile = discoveryXml; using (StreamReader file = new StreamReader(discoveryXml)) { XmlSerializer reader = new XmlSerializer(typeof(WopiHost.wopidiscovery)); var wopiDiscovery = reader.Deserialize(file) as WopiHost.wopidiscovery; _wopiDiscovery = wopiDiscovery; } }public WopiAppHelper(string discoveryXml, bool updateEnabled) : this(discoveryXml) { _updateEnabled = updateEnabled; }public WopiHost.wopidiscoveryNetzoneApp GetZone(string AppName) { var rv = _wopiDiscovery.netzone.app.Where(c => c.name == AppName).FirstOrDefault(); return rv; }public string GetDocumentLink(string wopiHostandFile) { var fileName = wopiHostandFile.Substring(wopiHostandFile.LastIndexOf(\'/\') + 1); var accessToken = GetToken(fileName); var fileExt = fileName.Substring(fileName.LastIndexOf(\'.\') + 1); var netzoneApp = _wopiDiscovery.netzone.app.AsEnumerable() .Where(c => c.action.Where(d => d.ext == fileExt).Count() > 0); var appName = netzoneApp.FirstOrDefault(); if (null == appName) throw new ArgumentException("invalid file extension " + fileExt); var rv = GetDocumentLink(appName.name, fileExt, wopiHostandFile, accessToken); return rv; }string GetToken(string fileName) { KeyGen keyGen = new KeyGen(); var rv = keyGen.GetHash(fileName); return HttpUtility.UrlEncode(rv); }const string s_WopiHostFormat = "{0}?WOPISrc=https://www.songbingjia.com/android/{1}& access_token={2}"; //HACK: const string s_WopiHostFormatPdf = "{0}?PdfMode=1& WOPISrc=https://www.songbingjia.com/android/{1}& access_token={2}"; public string GetDocumentLink(string appName, string fileExtension, string wopiHostAndFile, string accessToken) { var wopiHostUrlsafe = HttpUtility.UrlEncode(wopiHostAndFile.Replace(" ", "%20")); var appStuff = _wopiDiscovery.netzone.app.Where(c => c.name == appName).FirstOrDefault(); if (null == appStuff) throw new ApplicationException("Can\'t locate App: " + appName); var action = _updateEnabled ? "edit" : "view"; if (appName.Equals("WordPdf")) { action = "view"; } if (HttpContext.Current.Request.Browser.IsMobileDevice) { action = "mobileView"; } var appAction = appStuff.action.Where(c => c.ext == fileExtension & & c.name == action).FirstOrDefault(); if (null == appAction) throw new ApplicationException("Can\'t locate UrlSrc for : " + appName); var endPoint = appAction.urlsrc.IndexOf(\'?\'); var endAction = appAction.urlsrc.Substring(0, endPoint); string fullPath = null; ////HACK: for PDF now just append WordPdf option... if (fileExtension.Contains("pdf")) { fullPath = string.Format( s_WopiHostFormatPdf, endAction, wopiHostUrlsafe, accessToken); } else { fullPath = string.Format(s_WopiHostFormat, endAction,wopiHostUrlsafe, accessToken); }return fullPath; } }

对应的配置例如以下:
Asp.net与office web apps的整合

文章图片

appDiscoveryXml  是我们owas(http://owas.contoso.com/hosting/discovery)产生的数据文件。appWopiServer  表示我们的owas将要訪问interface地址。updateEnabled主要是表示owas能否够改动我们的文档,假设是true 我们上面的action 採用edit,为false採用view。
appHmacKey仅仅是数据加密的一个key。生成的url如图:
Asp.net与office web apps的整合

文章图片

注意这里的配置是updateEnabled=true  表示owas是能够编辑文件的,如图:
Asp.net与office web apps的整合

文章图片

当我们点击在浏览器编辑  结果如图:
Asp.net与office web apps的整合

文章图片

改动后能够直接保存:
Asp.net与office web apps的整合

文章图片

Asp.net与office web apps的整合

文章图片

点击确认后就能够直接保存。  pptx的编辑模式例如以下:
Asp.net与office web apps的整合

文章图片

这里的docx文件的编辑模式一直都在报错搞了非常久也没搞定。错误信息例如以下,假设大家知道还请指导指导:
Asp.net与office web apps的整合

文章图片

pdf是没有编辑模式的,如今再来看看excel的仅仅读模式(view)例如以下:
Asp.net与office web apps的整合

文章图片

这里的菜单中并不包括“在浏览器中编辑”。当中第15行是我刚才改动的新数据。
docx和pptx的仅仅读模式就不贴图了,在mobile的执行结果例如以下(我这里是用android手机訪问我的网站,因为是通过wifi来訪问自己的电脑上的网站,这里须要把计算机的全名改为IP地址)。
 
Asp.net与office web apps的整合

文章图片

注意上面的url是192.168.1.25XXX,这里的ip是owas.contoso.com的IP。这里总结一下的測试结果例如以下:
  view edit mobileview remark
word 通过 未通过 通过 在http和https协议下view都通过。edit  view没有通过。mobileview仅仅測试了http协议
excel 通过 通过 通过 在http和https协议下view和edit都通过,mobileview仅仅測试了http协议
ppt 通过 通过 通过 在http和https协议下view和edit都通过,mobileview仅仅測试了http协议
pdf 通过 不存在edit action 未通过 view在http协议下通过,在https在协议下未通过,mobileview 未通过
  这里我把问题的重心放在word的edit上面,对于pdf  在owas採用https以及在mobile上不能訪问的原因未未做调查。知道这些问题的革命前辈还请指教。
源代码下载地址:http://download.csdn.net/detail/dz45693/7215395
【Asp.net与office web apps的整合】https://code.msdn.microsoft.com/office/Building-an-Office-Web-f98650d6


    推荐阅读