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 = HostingEnvironment.MapPath("~/App_Data/");
var fileExt = name.Substring(name.LastIndexOf('.') + );
var outFile = Path.Combine(appData,name);
File.WriteAllBytes(outFile, body);
}
现在我们再来看看如何请求owas,也就是对应的url是怎么产生的。例如我的owas server是owas.contoso.com,那么我们在配置好owas后就可以访问http://owas.contoso.com/hosting/discovery 如图:
这里我们以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('/') + );
var accessToken = GetToken(fileName);
var fileExt = fileName.Substring(fileName.LastIndexOf('.') + );
var netzoneApp = _wopiDiscovery.netzone.app.AsEnumerable()
.Where(c => c.action.Where(d => d.ext == fileExt).Count() > ); 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={1}&access_token={2}";
//HACK:
const string s_WopiHostFormatPdf = "{0}?PdfMode=1&WOPISrc={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(, 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;
}
}
相应的配置如下:
appDiscoveryXml 是我们owas(http://owas.contoso.com/hosting/discovery)产生的数据文件,appWopiServer 表示我们的owas将要访问interface地址。updateEnabled主要是表示owas是否可以修改我们的文档,如果是true 我们上面的action 采用edit,为false采用view。appHmacKey只是数据加密的一个key。生成的url如图:
注意这里的配置是updateEnabled=true 表示owas是可以编辑文件的,如图:
当我们点击在浏览器编辑 结果如图:
修改后可以直接保存:
点击确认后就可以直接保存。 pptx的编辑模式如下:
这里的docx文件的编辑模式一直都在报错搞了很久也没搞定,错误信息如下,如果大家知道还请指导指导:
pdf是没有编辑模式的,现在再来看看excel的只读模式(view)如下:
这里的菜单中并不包含“在浏览器中编辑”,其中第15行是我刚才修改的新数据。docx和pptx的只读模式就不贴图了,在mobile的运行结果如下(我这里是用android手机访问我的站点,由于是通过wifi来访问自己的电脑上的站点,这里需要把计算机的全名改为IP地址)。
注意上面的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协议 |
通过 | 不存在edit action | 未通过 | view在http协议下通过,在https在协议下未通过,mobileview 未通过 |
这里我把问题的重心放在word的edit上面,对于pdf 在owas采用https以及在mobile上不能访问的原因未未做调查。知道这些问题的革命前辈还请不吝赐教。源码下载地址:http://download.csdn.net/detail/dz45693/7215395
Asp.net与office web apps的整合的更多相关文章
- office web apps 整合Java web项目
之前两篇文章将服务器安装好了,项目主要的就是这么讲其整合到我们的项目中,网上大部分都是asp.net的,很少有介绍Java如何整合的,经过百度,终于将其整合到了我的项目中. 首先建个servlet拦截 ...
- 整合Office Web Apps至自己的开发系统
原文出处:http://www.cnblogs.com/poissonnotes/p/3267190.html 还可参考:https://www.cnblogs.com/majiang/p/36729 ...
- 如何整合Office Web Apps至自己开发的系统(一)
在前面我的一篇博客中 Office Web Apps安装部署(一),有一张介绍Office Web Apps与其他系统的关系图, 从上述图中,可知实际上Office Web Apps也是可以接入自 ...
- 如何整合Office Web Apps至自己开发的系统(二)
WOPI项目的创建 首先用vs2012创建一个mvc4的程序.如图: 从上一篇我们可以知道,WOPI通讯主要通过两个服务: 一个是CheckFileInfo服务, 一个是GetFile服务. 所以下面 ...
- Exchange 2013与 Office Web Apps 整合
好久没写什么新文章了,这里有关Office Web Apps 的部署我就省略了,只是在创建web场我一般 会创建2个url, 如: New-OfficeWebAppsFarm -InternalUrl ...
- office web apps 整合到自己项目中(wopi实现在线预览编辑)
借助office web apps实现在线预览和在线编辑 我所有的代码都是用go语言编写,你可以直接编译后使用,不用再有其他的操作. 最近项目实在太忙,这几天才有时间,这次是重头戏,要好好琢磨一下怎么 ...
- 一、office web apps 部署
原文出处:http://www.cnblogs.com/yanweidie/p/4516164.html 原文出处:https://www.cnblogs.com/poissonnotes/p/323 ...
- 在线文档预览方案-office web apps
最近在做项目时,要在手机端实现在线文档预览的功能.于是百度了一下实现方案,大致是将文档转换成pdf,然后在通过插件实现预览.这些方案没有具体实现代码,也没有在线预览的地址,再加上项目时间紧迫.只能考虑 ...
- [转载]在线文档预览方案-Office Web Apps
最近在做项目时,要在手机端实现在线文档预览的功能.于是百度了一下实现方案,大致是将文档转换成pdf,然后在通过插件实现预览.这些方案没有具体实现代码,也没有在线预览的地址,再加上项目时间紧迫.只能考虑 ...
随机推荐
- Ionic App之国际化(2) json数组的处理
在Ionic App值国际化(1)中我们实现了对单个参数的多语言处理,下面开始如何进行数组的处理. 1.在我们的多语言文件中设置要访问的json数组,en.json和zh.json,此处就以en.js ...
- Luogu P2048 [NOI2010]超级钢琴
这道题题号很清新啊!第一次开NOI的题,因为最近考到了这道题的升级版. 我们先考虑\(O(n^2)\)大暴力,就是枚举前后端点然后开一个前缀和减一下即可. 然后引入正解,我们设一个三元组\(F(s,l ...
- POJ Remmarguts' Date
题目链接-> 题解: 次短路模板. 代码: #include<cstdio> #include<iostream> using namespace std; #defin ...
- 初识 tk.mybatis.mapper 通用mapper
在博客园发表Mybatis Dynamic Query后,一位园友问我知不知道通用mapper,仔细去找了一下,还真的有啊,比较好的就是abel533写的tk.mybatis.mapper. 本次例子 ...
- 第二次作业 对VC++6.0编译软件的评价
首先这个软件伴随着我们很长时间了,它是我们一上大学最先接触的,也是应用相当多的一个软件,其实在最初的时候,我对编译软件的理解非常有限,觉得它能实现一个代码的功能十分神奇的一件事情,虽然彼时我们写的代码 ...
- 2-Twenty Fourth Scrum Meeting-20151230
前言 因为服务器关闭,我们的开发项目也遭遇停滞一个星期.与网站开发负责人员协商之后,29号开放服务器.我们的项目也能够继续下去.比规定的开发时间(截止为2015/12/29)推迟. 事项安排 1.开发 ...
- 第三个Sprint冲刺第二天(燃尽图)
- 【转】GPS定位准确度CEP、RMS
转自:http://blog.sina.com.cn/s/blog_70f96fda0101lcb9.html CEP和RMS是GPS的定位准确度(俗称精度)单位,是误差概率单位.就拿2.5M CEP ...
- docker发现端口是tcp6的 导致无法访问前端
最近偶尔发现一个比较奇怪的现象,netstat 查看监听的服务端口时,却只显示了 tcp6 的监控, 但是服务明明是可以通过 tcp4 的 ipv4 地址访问的,那为什么没有显示 tcp4 的监听呢? ...
- Oracle的一般监听问题解决
1. 无监听的解决办法: Windows的情况下重启之后或者是一些异常状态时会造成服务没有正常启动起来, 解决办法: 打开服务 方法1 任务管理器-服务界面 或者是 运行-services.msc 打 ...