外贸网站建设网站开发,郑州网站app开发的,鄂州网站推广优化技巧,中国建设银行手机app2016年10月我参加了在北京举行的DevDays Asia 2016 - Office 365应用开发”48小时黑客马拉松“#xff0c;我开发的一个Word Add-In Demo——WordTemplateHelper获得了二等奖。在会场有幸结识了陈希章老师#xff0c;在与陈老师的交流中受益良多#xff0c;得知陈老师在准备…2016年10月我参加了在北京举行的DevDays Asia 2016 - Office 365应用开发”48小时黑客马拉松“我开发的一个Word Add-In Demo——WordTemplateHelper获得了二等奖。在会场有幸结识了陈希章老师在与陈老师的交流中受益良多得知陈老师在准备一个Office解决方案系列后我想把这个Demo的开发过程简要介绍给大家以支持陈老师的无私奉献也希望更多的开发者参与到Office365的开发中来。
Office相关开发主要可以参考这个地址https://dev.office.com/getting-started
本篇文章主要介绍其中的Office加载项开发即Office Add-inshttps://msdn.microsoft.com/ZH-CN/library/office/jj220082.aspx
一、什么是Office Add-Ins
什么是Office Add-ins呢在陈老师的上一篇文章中对整个Office发展历史都进行了梳理我个人的理解就是开发者可以在Office提供的平台上对Office做出一定的扩展以实现各种功能比如之前录制的宏写的VBS的脚本某种意义上都可以看做是Office的Add-ins。当然这只是个人理解不一定准确。目前的Office Add-Ins只支持Office2013以后的版本开发方式也和以前的VBS有了很大的区别。
现在的Office Add-ins结构是这样的 一个Office Add-in其实是一个Web App可以将其部署在任意位置它可以在一个Office应用程序中运行。有一个manifest.xml清单文件用来指定该Web App如何来呈现包括定义Web App 的URL。当Office加载这个Add-in时实际上是提供了一个浏览器的环境来运行指定的Web App。也就是说现在开发一个Office Add-in其实跟开发网页程序差不多这对熟悉htmlJavaScriptcss的前端开发人员是非常容易上手的。微软提供了丰富的JavaScript API来对Office进行操作能实现什么就取决于开发者的想象力了。
一个Word Add-In的实例 二、Word Template Helper需求分析
我在得知有这个活动时并没有想好要做什么一直到坐上赴京的高铁才慢慢有了一个想法这个想法也是来自平时的工作需要。在工作中经常要撰写大量的文档如各种软件需求规格说明书、公函、文书、操作手册等这些文档都有规定的格式一般情况下我是将一些已经写好的Word文档保存在一个文件夹里当做模板下次写这种文档的时候复制一份删删减减的再改。为何不自己写个程序将这些具有固定模式的文档作为Word模板呢虽然Word也有自己的模板但实际上是非常有限的并不能完全满足我们的需要。如果这个功能做成一个模板商店大家可以自由上传、分享各自的模板也许会方便许多。
Word自带的模板是这样的 这些通用模板对专业性比较强的工作来说是远远不够的。Word Template Helper的效果是这样的 主意有了那么就来看一下如何实现。我参加活动时的项目托管在码云上为了写这篇文章我重新梳理了这个小demo在Github上建了一个项目并尝试使用最新的.NET Core来实现后台API部分。接下来就跟我一起动手吧。
三、项目架构
首先分析一下该项目的结构。文档的模板数据如模板标题、属性等需要保存在数据库里还需要一个Web API项目提供数据Office Add-in为一个纯前端项目使用Angular2框架采用异步调用Web API的数据实现搜索、加载模板等功能。插件的UI使用微软提供的Fabric UI。整个项目的技术栈如下所示 至于文档的实体——Word文档是以Word格式文件存储还是直接保存在数据库中呢如果是正式项目的话当然是保存在云存储中是最合适的但对于一个sample来说直接保存在数据库中也未尝不可。因为是参加开发马拉松怎么快怎么来吧。包括ORM框架也是只是为了快速实现采用的方式不是最佳实践。
这个sample的开发环境配置如下
Windows 10 x64,
VS 2017请确保安装了Office开发工具
VS Code
Node.js v7.10.0
NPM v4.2.0
ASP.NET Core 1.1 四、Web API开发
VS2017已经正式发布了我使用最新的.NET Core来实现Web API层。
1.新建项目
新建一个空白解决方案命名为WordTemplateHelpe然后在其中添加一个ASP.NET Core项目 选择Web API 2.安装EF Core
在nuget管理器中搜索安装一下几个Nuget包
Microsoft.EntityFrameworkCore.SqlServerEF Core SQL Server
Microsoft.EntityFrameworkCore.ToolsEF命令行工具
Microsoft.EntityFrameworkCore.Tools.DotNetEF Core命令行工具 3.建立Models
目前最新的EF都推荐使用Code First模式即直接写ModelEF框架会自动创建所需的数据库。如果习惯DB First的话也有一个很好的工具推荐EntityFramework-Reverse-POCO-Code-First-Generatorhttps://visualstudiogallery.msdn.microsoft.com/ee4fcff9-0c4c-4179-afd9-7a2fb90f5838 可以直接在VS的扩展与更新里下载。这个工具可以很方便的根据数据库生成所需的实体类。
首先添加一个模板类型的枚举 /// summary/// 类型 /// /summarypublic enum TemplateType{ /// summary/// Private /// /summary[Description(Private)]Private 0, /// summary/// Public /// /summary[Description(Public)]Public 1, /// summary/// Organization /// /summary[Description(Organization)]Organization 2,}
添加一个模板类 public class PrivateTemplateInfo{ ///summary/// Id ////summarypublic string Id { get; set; } ///summary/// User Id ////summarypublic string UserId { get; set; } ///summary/// Template Id ////summarypublic string TemplateId { get; set; } ///summary/// Create Time ////summarypublic DateTime CreateTime { get; set; }} 因为还需要组织机构模板、用户收藏等几个表这里就不写了可参考Github上的示例。
4.创建数据库上下文
有了Model后需要指定哪些实体包含在数据模型中。添加一个Data文件夹在其中创建一个名为WordTemplateContext.cs的文件 public class WordTemplateContext:DbContext{ public WordTemplateContext(DbContextOptionsWordTemplateContext options) : base(options){} public DbSetWordTemplateInfo WordTemplateInfoes { get; set; } public DbSetUserFavoriteInfo UserFavoriteInfoes { get; set; } public DbSetPrivateTemplateInfo PrivateTemplateInfoes { get; set; } public DbSetOrganizationTemplateInfo OrganizationTemplateInfoes { get; set; }} 这样就为每个实体创建了一个DbSet对应数据库中的表实体对应表中的行。 5.使用依赖注入注册上下文
ASP.NET Core默认实现了依赖注入。要把刚才建立的WordTemplateContext注册成服务需要在Startup.cs中添加以下代码 public void ConfigureServices(IServiceCollection services){ // Add framework services.services.AddDbContextWordTemplateContext(options options.UseSqlServer(Configuration.GetConnectionString(DefaultConnection)));services.AddMvc();} 注意要添加using Microsoft.EntityFrameworkCore;不然会找不到UseSqlServer方法。
数据库连接字符串在appsettings.json中配置
{ ConnectionStrings: { DefaultConnection: Server.;User IDsa;Password12QWasZX;Initial CatalogWordTemplate;}, Logging: { IncludeScopes: false, LogLevel: { Default: Warning}}
} 这里使用了LocalDb用于测试。当需要正式部署时这里需要更改为正式数据库服务器的地址及用户名密码。
6.初始化数据库
下面使用命令行初始化数据库。在Data目录下新建一个DbInitializer类输入以下方法 public static class DbInitializer{ public static void Initialize(WordTemplateContext context){context.Database.EnsureCreated(); //TODO context.SaveChanges();}} 确保数据被创建。然后修改Startup.cs文件中的Configure方法 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, WordTemplateContext context){loggerFactory.AddConsole(Configuration.GetSection(Logging));loggerFactory.AddDebug();app.UseMvc();DbInitializer.Initialize(context);} 7.创建API接口
现在写个Controller看看。在Controller文件夹中添加一个控制器 这里可以使用依赖注入将数据库上下文注入进来 [Produces(application/json)][Route(api/WordTemplate/[action])] public class WordTemplateController : Controller{ private readonly WordTemplateContext _context; public WordTemplateController(WordTemplateContext context){_context context;} 我们以一个搜索模板的api为例 [HttpGet] public async TaskResponseResultInfoListWordTemplateInfo SearchWordTemplateList(string keyword){ResponseResultInfoListWordTemplateInfo respResult new ResponseResultInfoListWordTemplateInfo(); try{ListWordTemplateInfo list await _context.WordTemplateInfoes.Where(x x.Type TemplateType.Public x.Name.Contains(keyword)).OrderByDescending(x x.CreateTime).ToListAsync();respResult.IsSuccess true;respResult.Result list; return respResult;} catch (Exception ex){ //LogHelper.ErrorWriteLine(Something wrong. The exception message:{0}, ex);respResult.IsSuccess false;respResult.Message string.Format(Something wrong. The exception message:{0}, ex.Message); return respResult;}} 命令行转到项目目录运行以下命令
dotnet run 可以使用前端调试利器Postman来测试 API项目运行的具体地址需要记一下后面做Add-In的时候要用到。具体代码请参考Github。
8.允许跨域访问
为了支持Add-in能够跨域访问我们的接口还需要安装以下的库 然后在Startup.cs的ConfigureServices方法中添加以下代码
#region 跨域services.AddCors(options options.AddPolicy(AllowCrossDomain,builder builder.WithOrigins().AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin().AllowCredentials())); #endregion 在需要跨域的WordTemplateController上添加一行
[EnableCors(AllowCrossDomain )] 这样api就可以支持跨域访问了。 五、Word Add-In开发
有了API就可以开发Add-In部分了。开篇说到Add-In实际上是一个Web App通过JavaScript操作Office文档对象具体到这个项目来说就是使用异步的js去查询、上传、搜索存在服务器上的模板文件并动态的对当前Word文档进行操作。
微软在Github上开源了这个JavaScript APIhttps://github.com/Microsoft/Office-js-docs_zh-cn相关文档https://msdn.microsoft.com/zh-cn/library/office/fp142185.aspx
开发步骤可参考https://github.com/Microsoft/Office-js-docs_zh-cn/blob/master/docs/get-started/create-and-debug-office-add-ins-in-visual-studio.md
下面来开发Add-In部分。
1.新建Add-In项目
在解决方案上点击右键添加一个Word Web外接程序 添加完成后多了两个项目 其中一个是清单文件带Web后缀的就是Web App了。
2.设置manifest.xml
清单文件是非常重要的一个文件描述加载项的所有设置。这个文件是自动生成的但需要我们手动修改一些地方。好在文件中都有注释所以修改还比较容易 最重要的是修改SourceLocation这个节点这个地址设置的是Web App托管的位置。在Web端开发并部署后要将这个节点改为正确的位置才能发布。下面这个节点也要改掉。 3.Web App分析
可以先运行一下这个模板试试直接F5 点击此处就可以调出这个插件 会自动打开Word并加载这个插件文档中的文本就是插件插入的。那么是哪里的代码起作用的呢
打开Home.js文件找到如下代码 function loadSampleData() { // Run a batch operation against the Word object model.Word.run(function (context) { // Create a proxy object for the document body.var body context.document.body; // Queue a commmand to clear the contents of the body. body.clear(); // Queue a command to insert text into the end of the Word document body. body.insertText( This is a sample text inserted in the document,Word.InsertLocation.end); // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion.return context.sync();}).catch(errorHandler);} 这里的Word就是JavaScript API提供的对象可以方便的对当前文档内容进行操作。这样思路就有了可以通过JavaScript动态去调用Web API获取查询结果将查询到的文档内容插入到当前文档中就实现了最初的目的。同时还可以将当前文档的内容保存为模板上传到服务器上进行分享一个完整功能的sample已经呼之欲出了。
4.使用Angular
我们使用最新的Angular4来开发前端页面。当然如果使用JQuery的话也可以但现在已经有点out了不是吗使用Angular可以快速开发一个MVVM架构的单页面WebApp非常适合这个需求。
这个demo的部分代码参考微软开源的一个项目https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code
Angular上手曲线还是有点陡的官方给出了Angular CLI工具可以快速搭建一个Angular应用。首先安装TypeScript:
npm install -g typescript 然后安装Angular CLIhttps://github.com/angular/angular-cli
npm install -g angular/cli 运行以下命令创建一个Angular项目
ng new WordTemplateHelperSource 然后使用cd WordTemplateHelperSource 命令转到项目目录运行以下命令
npm install 这个命令会安装ng项目所需的依赖如果安装不成功建议切换成淘宝npm镜像进行安装。
使用以下命令运行ng项目
ng serve 可以在Chorme浏览器中浏览http://localhost:4200来查看效果 注意如果在IE中浏览是不正常的这个问题我们到最后一节再给出解决办法。
为什么不直接在WordTemplateHelperWeb建呢因为Angular应用还要进行打包会在项目目录下生成dist目录这才是正式要运行的部分。所以等开发完成后将生成的dist目录内的文件拷到WordTemplateHelperWeb就可以了。
在开发Angular的过程中推荐使用VS Code对TypeScript和Angular的支持都非常好。
因为本篇文章不是Angular的开发教程所以Angular的具体知识这里就不展开详述了感兴趣的话可以自行下载Github代码运行即可。
5.添加操作Word文件的service
为了操作Word文件我们需要将其封装成服务。使用以下命令添加一个service
ng g service services\word-document\WordDocument 这样会在app目录中的相应路径中生成一个名为WordDocumentService的服务。与此类似生成其他的几个service。其中主要的几个方法如下
查询搜索的方法
/*** search* * param {string} keyword* returns {PromiseResponseResultInfoArrayWordTemplateInfo}* * memberOf WordTemplateApiService */searchWordTemplateList(keyword: string): PromiseResponseResultInfoArrayWordTemplateInfo {let url ${AppGlobal.getInstance().server}/SearchWordTemplateList?keyword${keyword};let promise this.httpService.get4JsonResponseResultInfoArrayWordTemplateInfo(url); return promise;} 这样可以得到服务器上存储的文档模板实际是以Ooxml格式保存的string。
对于这个sample来说使用Office JavaScript API并没有太难的东西主要用到了两个方法getOoxml()和insertOoxml()前者可以读取当前word文档的Ooxml格式后者可以设置当前word文档的Ooxml格式。Ooxml就是Office2007之后版本使用的格式如docx这种。
原API提供的都是callback函数为了使用方便我将其封装成Promise /*** get the ooxml of the doc* * * memberOf WordDocumentService */getOoxml() { // Run a batch operation against the Word object model.return Word.run(function (context) { // Create a proxy object for the document body.var body context.document.body; // Queue a commmand to get the HTML contents of the body.var bodyOOXML body.getOoxml(); // Synchronize the document state by executing the queued commands, // and return a promise to indicate task completion.// return context.sync().then(function () {// console.log(Body HTML contents: bodyHTML.value);// return bodyHTML.value;// });return context.sync().then(() { return bodyOOXML.value });}).catch(function (error) {console.log(Error: JSON.stringify(error)); if (error instanceof OfficeExtension.Error) {console.log(Debug info: JSON.stringify(error.debugInfo));} return ;});} /*** set the ooxml of the doc* * param {string} ooxml * * memberOf WordDocumentService */setOoxml(ooxml: string) { // Run a batch operation against the Word object model.Word.run(function (context) { // Create a proxy object for the document body.var body context.document.body; // Queue a commmand to insert OOXML in to the beginning of the body. body.insertOoxml(ooxml, Word.InsertLocation.replace); // Synchronize the document state by executing the queued commands, // and return a promise to indicate task completion.return context.sync().then(function () {console.log(OOXML added to the beginning of the document body.);});}).catch(function (error) {console.log(Error: JSON.stringify(error)); if (error instanceof OfficeExtension.Error) {console.log(Debug info: JSON.stringify(error.debugInfo));}});} 当搜索到合适的模板后可以单击按钮调用setOoxml()方法将其插入到当前word文档中
applyTemplate(template: WordTemplateInfo) { this.wordDocument.setOoxml(template.TemplateContent);} 这样就完成了应用模板的功能。 如果要实现将当前文档的内容保存为模板上传到服务器上就可以调用getOoxml()方法得到当前文档的Ooxml格式文本上传到服务器保存即可。至于其他的加为收藏、添加为机构模板、设置为个人模板等都是设置模板属性更新了具体代码不再赘述。
还有一点需要注意的是开发的时候这里的服务器地址要写刚才我们开发的ASP.NET Core的地址。
6.使用Fabric UI
对于一个Office Add-in来说具有简洁美观、与Office统一的UI是必须的。微软推荐使用Fabric UI来实现统一的界面样式详见https://dev.office.com/fabric
这里提供了样式、图标、设计规范等很多资源甚至还提供了React版的组件如果使用React开发的话直接拿来用就可以了。这个demo是直接引用的style文件配置在.angular-cli.json文件中 应用后就变成这样子 7.打包Add-in
刚才只是在一个新项目里开发了一个静态Web App还要将其打包复制到WordTemplateHelperWeb项目中。使用ng build –prod来打包Angular应用。打包后的文件会输出到dist目录下 注意还有一个需要注意的地方如果仅这样打包的话是不支持IE浏览器的但Office Add-In实际上内置的浏览器就是IE内核所以我们需要做如下修改找到src目录中的polyfills.ts文件将下面部分的注释取消 还要根据提示运行npm install命令安装几个必须的依赖。这样才能在IE系列浏览器中正常运行。再次运行ng build –prod进行打包。--prod参数的意义是以生产模式进行build这样生成的代码体积更小运行速度更快。
将WordTemplateHelperWeb项目中的原文件除了Web.config外全部删除。把dist目录中的文件复制过来。
虽然本机开发时可以直接调试运行但为了模拟真实的使用情况我们把这个Web App也正式发布一下。如果我们有Azure或其他主机的话就直接部署到服务器上现在只用本机IIS来承载这个Web App 这样该Add-In的地址就是http://localhost/WordTemplateHelperWeb
下面把api运行起来进入WordTemplateHelperApi目录运行dotnet run命令 这样API项目的地址是http://localhost:5000/api/
这两个地址不要混淆。刚才在打包WebApp的时候也要注意在common\app-global.ts文件中的api地址也要改成和实际api地址一样的才可以: /*** api url* * type {string}* memberOf AppGlobal */public server: string http://localhost:5000/api/WordTemplate; 现在打开WordTemplateHelperManifest清单文件修改如下位置 这里填的是Add-In的地址一定不要搞错了。
6.运行测试
现在可以重新运行Add-In项目了将启动项目设置为WordTemplateHelper运行 我们可以粘贴一个模板并上传到服务器上 点击Upload按钮即可将当前文档作为模板上传到服务器上分享。 搜索到相应的模板后点击apply按钮即可将模板内容插入到当前文档。
我们可以搜索模板添加自己的模板并将模板内容应用到当前文档中。针对组织和个人还可以分别进行管理我的设想是这个小插件能够做成一个模板商店之类的平台用户可以自由的交换彼此的文档模板并可以收藏、添加到本人组织的模板库中等等。稍加扩展就可以做成一个正式产品了。
7.载入加载动画
在页面加载时可以加一个载入提示使用户体验更加友好。具体代码可参考index.html中的css样式。
六、小结
这篇文章拖了很久去年的比赛今年才把过程整理出来实在很想对陈老师说一声抱歉^_^。Office Add-In是一个比较新的开发领域跟以前的开发方式有所不同但熟悉前端的同学可以迅速进入这个领域实际上就是写网页。这个实例从后端接口到前台实现是一个比较完整的项目希望对Office开发有兴趣的同学下载代码研究一下开发出更加实用的Add-In。因为这个项目并没有实际部署所以没有上传到商店中。下载代码的用户请勿用于商业用途。特此说明。
Github地址https://github.com/yanxiaodi/WordTemplateHelper
原文地址http://www.cnblogs.com/yanxiaodi/p/7192280.html .NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注