├── HTML
├── .DS_Store
├── README.md
├── index.html
└── jwps.js
├── Readme.md
└── WPSApi
├── Controllers
└── WPSController.cs
├── Core
└── LogMiddlware.cs
├── Helper
├── TimestampHelper.cs
└── WPSSignatureHelper.cs
├── Model
├── CreateWPSFileModel.cs
├── FileInfoResult.cs
├── GenarateModel.cs
├── GetFileByVersionModel.cs
├── GetHistoryModel.cs
├── GetUserInfoModel.cs
├── RenameFileModel.cs
├── RequestParam.cs
├── SaveFileResult.cs
├── UserModel.cs
├── WPSBaseModel.cs
├── WPSEnum.cs
└── WPSNotifyRequest.cs
├── Program.cs
├── Properties
├── PublishProfiles
│ ├── FolderProfile.pubxml
│ └── FolderProfile.pubxml.user
└── launchSettings.json
├── Startup.cs
├── WPSApi.csproj
├── WPSApi.sln
├── appsettings.Development.json
├── appsettings.json
└── log4net.config
/HTML/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/guolaopi/WPSOnlineDemo/bb70910f900ebb811debfa82a10649fdcb0ee29c/HTML/.DS_Store
--------------------------------------------------------------------------------
/HTML/README.md:
--------------------------------------------------------------------------------
1 | # WPS Web Office JS-SDK 说明文档
2 |
3 | ## 概述
4 |
5 | WPS Web Office JS-SDK 是[WPS开放平台](https://open.wps.cn/) 面向网页开发者提供的网页开发工具包。
6 |
7 | 通过使用 JS-SDK,网页开发者可以为 WPS Web Office 自定义菜单、分享等能力,同时可以直接使用高级 API 来操作文档,为用户提供更优质的网页体验。
8 |
9 | 此文档面向网页开发者介绍 WPS Web Office JS-SDK 如何使用及相关注意事项。
10 |
11 | ## JSSDK 使用
12 |
13 | ### 引入 JS 文件
14 |
15 | 在需要调用的页面引入如下 JS 文件(jwps-1.0.0.js)
16 |
17 | 备注:支持使用 AMD/CMD 标准模块加载方法加载
18 |
19 | ### 接入 WPS Web Office
20 |
21 | ```js
22 | WPS.config({
23 | wpsUrl: 'https://wwo.wps.cn/office/w/66858743377433009?_w_appid=xxx&_w_id=xxx&_w_type=1&_w_userid=xxx&_w_timestamp=xxx&_w_permission=write&_w_tokentype=1&&_w_signature=xxx' // 如文字(Word)接入地址
24 | })
25 | ```
26 | JS-SDK 会自动创建 iframe(#wps-iframe),它默认会挂载到 body 下。
27 |
28 | ### 设置 token
29 |
30 | > url参数带上_w_tokentype=1(此参数同样需要签名)
31 | ```js
32 | wps = WPS.config({
33 | wpsUrl: 'https://wwo.wps.cn/office/w/66858743377433009?_w_appid=xxx&_w_id=xxx&_w_type=1&_w_userid=xxx&_w_timestamp=xxx&_w_permission=write&_w_tokentype=1&_w_signature=xxx'
34 | })
35 |
36 | // 获取到 token 后,设置
37 | wps.setToken({token: 'your-token'})
38 | ```
39 |
40 | ### 自定义 Web Office(iframe) 挂载点
41 |
42 | ```js
43 | WPS.config({
44 | mount: document.querySelector('#container'),
45 | wpsUrl: 'https://wwo.wps.cn/office/w/66858743377433009?xxx'
46 | })
47 | ```
48 |
49 | ### 头部配置
50 |
51 | #### 分享按钮
52 |
53 | ```js
54 | WPS.config({
55 | wpsUrl: 'https://wwo.wps.cn/office/w/66858743377433009?xxx',
56 | headers: {
57 | shareBtn: {
58 | tooltip: '分享',
59 | subscribe(wps) {
60 | console.log(wps)
61 | }
62 | }
63 | }
64 | })
65 | ```
66 |
67 | #### 左边其他按钮(配置自定义菜单)
68 |
69 | ```js
70 | WPS.config({
71 | wpsUrl: 'https://wwo.wps.cn/office/w/66858743377433009?xxx',
72 | headers: {
73 | otherMenuBtn: {
74 | tooltip: '更多菜单',
75 | items: [
76 | {
77 | type: 'custom',
78 | icon: 'http://ep.wps.cn/index/images/logo_white2.png', // 移动端显示 Icon
79 | text: '自定义菜单',
80 | subscribe(wps) {
81 | console.log(wps)
82 | }
83 | }
84 | ]
85 | }
86 | }
87 | })
88 | ```
89 |
90 | ### 高级 API
91 |
92 | #### 导出 PDF
93 |
94 | ```js
95 | // 文字
96 | wps.WpsApplication().ActiveDocument.ExportAsFixedFormatAsync() // 导出所有
97 |
98 | // 表格
99 | wps.EtApplication().ActiveWorkbook.ExportAsFixedFormatAsync() // 导出所有工作表
100 | wps.EtApplication().ActiveWorkbook.ActiveSheet.ExportAsFixedFormatAsync() // 导出当前工作表
101 |
102 | // 演示
103 | wps.WppApplication().ActivePresentation.ExportAsFixedFormatAsync() // 导出所有
104 | ```
105 |
106 | 示例:自定义菜单中使用高级 API
107 |
108 | ```js
109 | WPS.config({
110 | wpsUrl: 'https://wwo.wps.cn/office/w/66858743377433009?xxx',
111 | headers: {
112 | otherMenuBtn: {
113 | tooltip: '更多菜单',
114 | items: [
115 | {
116 | type: 'custom',
117 | icon: 'http://ep.wps.cn/index/images/logo_white2.png',// 移动端显示的 Icon
118 | text: 'API 导出 PDF',
119 | async subscribe(wps) {
120 | let result = ""
121 | if (wps.WpsApplication) { // 文字
122 | result = await wps.WpsApplication().ActiveDocument.ExportAsFixedFormatAsync()
123 | console.table(result)
124 | }
125 | if (wps.EtApplication) { // 表格
126 | result = await wps.EtApplication().ActiveWorkbook.ExportAsFixedFormatAsync()
127 | console.table(result)
128 | result = await wps.EtApplication().ActiveWorkbook.ActiveSheet.ExportAsFixedFormatAsync()
129 | console.table(result)
130 | }
131 | if (wps.WppApplication) { // 演示
132 | result = await wps.WppApplication().ActivePresentation.ExportAsFixedFormatAsync()
133 | console.table(result)
134 | }
135 | }
136 | }
137 | ]
138 | }
139 | }
140 | })
141 | ```
142 |
143 | 示例:配置完直接测试高级 API
144 | ```js
145 | WPS.config({
146 | wpsUrl: 'https://wwo.wps.cn/office/w/66858743377433009?xxx',
147 | })
148 |
149 | await wps.ready() // 需要等待 web office 内核初始化完成
150 |
151 | let result = ""
152 | if (wps.WpsApplication) { // 文字
153 | result = await wps.WpsApplication().ActiveDocument.ExportAsFixedFormatAsync()
154 | console.table(result)
155 | }
156 | if (wps.EtApplication) { // 表格
157 | result = await wps.EtApplication().ActiveWorkbook.ExportAsFixedFormatAsync()
158 | console.table(result)
159 | result = await wps.EtApplication().ActiveWorkbook.ActiveSheet.ExportAsFixedFormatAsync()
160 | console.table(result)
161 | }
162 | if (wps.WppApplication) { // 演示
163 | result = await wps.WppApplication().ActivePresentation.ExportAsFixedFormatAsync()
164 | console.table(result)
165 | }
166 | ```
167 |
168 | #### 保存版本
169 |
170 | ```js
171 | WPS.config({
172 | wpsUrl: 'https://wwo.wps.cn/office/w/66858743377433009?xxx',
173 | })
174 |
175 | await wps.ready() // 需要等待 web office 内核初始化完成
176 |
177 | await wps.save() // 保存版本
178 | ```
179 |
180 |
--------------------------------------------------------------------------------
/HTML/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 | WPS Web Office(iframe)接入指南
12 |
32 |
33 |
34 |
35 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/HTML/jwps.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).WPS={})}(this,function(e){"use strict";var t,n,o=function(){return(o=Object.assign||function(e){for(var t,n=1,o=arguments.length;n=0&&e._handleList.splice(n,1),window.removeEventListener("message",t,!1)},e.empty=function(){for(;e._handleList.length;)window.removeEventListener("message",e._handleList.shift(),!1)},e.parse=function(e){return"object"==typeof e?e:JSON.parse(e)},e._handleList=[],e}();!function(e){e.unknown="unknown",e.spreadsheet="s",e.writer="w",e.presentation="p",e.pdf="f"}(t||(t={})),function(e){e.wps="w",e.et="s",e.presentation="p",e.pdf="f"}(n||(n={}));var i,a,p,s,c,u,d,f=(i=0,function(){return++i}),l=(a=null,function(e,t){if(!a){a=document.createElement("iframe");var n={id:"wps-iframe",src:e,scrolling:"no",frameborder:"0",allowfullscreen:"allowfullscreen",webkitallowfullscreen:"true",mozallowfullscreen:"true"};for(var o in n)a.setAttribute(o,n[o]);t?t.appendChild(a):document.body.appendChild(a),a.destroy=function(){a.parentNode.removeChild(a),a=null}}return a}),m=function(e){l().contentWindow.postMessage(JSON.stringify(e),"*")},v=function(e){return new Promise(function(t){var n=f();e.type=w();var o=function(e){var i=r.parse(e.data);"wps.api.reply"===i.eventName&&i.msgId===n&&(t(i.data),r.remove(o))};r.add(o),m({eventName:"wps.jssdk.api",data:e,msgId:n})})},y=function(e){var t=o({},e),n=t.headers,r=void 0===n?{}:n,i=t.subscriptions,a=void 0===i?{}:i,p=(t.wpsUrl,r.backBtn),s=void 0===p?{}:p,c=r.shareBtn,u=void 0===c?{}:c,d=r.otherMenuBtn,f=void 0===d?{}:d,l=function(e,t){e.subscribe&&"function"==typeof e.subscribe&&(e.callback=t,a[t]=e.subscribe,delete e.subscribe)};if(l(s,"wpsconfig_back_btn"),l(u,"wpsconfig_share_btn"),l(f,"wpsconfig_other_menu_btn"),f.items&&Array.isArray(f.items)){var m=[];f.items.forEach(function(e,t){switch(void 0===e&&(e={}),e.type){case"export_img":e.type=1,e.callback="export_img";break;case"export_pdf":e.type=1,e.callback="export_pdf";break;case"save_version":e.type=1,e.callback="save_version";break;case"about_wps":e.type=1,e.callback="about_wps";break;case"split_line":e.type=2;break;case"custom":e.type=3,l(e,"wpsconfig_other_menu_btn_"+t),m.push(e)}}),m.length&&(b||F)&&(f.items=m)}if("object"==typeof a.print){var v="wpsconfig_print";"function"==typeof a.print.subscribe&&(a[v]=a.print.subscribe,t.print={callback:v},void 0!==a.print.custom&&(t.print.custom=a.print.custom)),delete a.print}"function"==typeof a.exportPdf&&(a[v="wpsconfig_export_pdf"]=a.exportPdf,t.exportPdf={callback:v},delete a.exportPdf);return o({},t,{subscriptions:a})},w=(p="",function(e){if(void 0===e&&(e=""),!p&&e){var o=e.toLowerCase();-1!==o.indexOf("/office/s/")&&(p=t.spreadsheet),-1!==o.indexOf("/office/w/")&&(p=t.writer),-1!==o.indexOf("/office/p/")&&(p=t.presentation),-1!==o.indexOf("/office/f/")&&(p=t.pdf)}if(!p){var r=e.match(/[\?&]type=([a-z]+)/)||[];p=n[r[1]]||""}return p}),x=window.navigator.userAgent.toLowerCase(),b=/Android|webOS|iPhone|iPod|BlackBerry|iPad/i.test(x),F=function(){try{return-1!==window._parent.location.search.indexOf("from=wxminiprogram")}catch(e){return!1}}();!function(e){e[e.wdExportFormatPDF=17]="wdExportFormatPDF",e[e.wdExportFormatXPS=18]="wdExportFormatXPS"}(s||(s={})),function(e){e[e.wdExportAllDocument=0]="wdExportAllDocument",e[e.wdExportSelection=1]="wdExportSelection",e[e.wdExportCurrentPage=2]="wdExportCurrentPage",e[e.wdExportFromTo=3]="wdExportFromTo"}(c||(c={})),function(e){e[e.wdExportDocumentContent=0]="wdExportDocumentContent",e[e.wdExportDocumentWithMarkup=7]="wdExportDocumentWithMarkup"}(u||(u={})),function(e){e[e.title=1]="title",e[e.tag=2]="tag"}(d||(d={}));var A;!function(e){e[e.xlTypePDF=0]="xlTypePDF",e[e.xlTypeXPS=1]="xlTypeXPS"}(A||(A={}));var P,E,h;!function(e){e[e.ppFixedFormatTypePDF=2]="ppFixedFormatTypePDF",e[e.ppFixedFormatTypeXPS=1]="ppFixedFormatTypeXPS"}(P||(P={})),function(e){e[e.ppPrintAll=1]="ppPrintAll",e[e.ppPrintCurrent=3]="ppPrintCurrent"}(E||(E={})),function(e){e[e.msoFalse=0]="msoFalse",e[e.msoTrue=-1]="msoTrue"}(h||(h={}));var g,k,D=function(){return new Promise(function(e){return k=e})},_=function(e){return"wps.advanced.api.ready"===e||"web_loaded"===e},T=function(e,t){void 0===e&&(e={});r.add(function(n){var o=r.parse(n.data),i=o.eventName,a=void 0===i?"":i,p=o.data,s=void 0===p?null:p,c=o.url,u=void 0===c?null:c;-1===["wps.jssdk.api"].indexOf(a)&&("ready"===a&&(m({eventName:"setConfig",data:e}),g.tokenData&&m({eventName:"setToken",data:g.tokenData}),k(),g.iframeReady=!0),_(a)&&S(),"function"==typeof t[a]&&t[a](g,u||s))})},S=function(){var e=w(g.url);e===t.writer&&function(e){e.WpsApplication=function(){return{ActiveDocument:{ExportAsFixedFormatAsync:function(e){var t={api:"WpsApplication().ActiveDocument.ExportAsFixedFormatAsync",args:o({ExportFormat:s.wdExportFormatPDF,Range:c.wdExportAllDocument,From:1,To:1,Item:u.wdExportDocumentWithMarkup,IncludeDocProps:!0},"object"==typeof e?e:{})};return v(t)},ImportDataIntoFieldsAsync:function(e){var t={api:"WpsApplication().ActiveDocument.ImportDataIntoFieldsAsync",args:{Data:e.Data,Options:e.Options}};return v(t)}},Enum:o({},s,c,u)}}}(g),e===t.spreadsheet&&function(e){e.EtApplication=function(){return{ActiveWorkbook:{ExportAsFixedFormatAsync:function(e){var t={api:"EtApplication().ActiveWorkbook.ExportAsFixedFormatAsync",args:o({Type:A.xlTypePDF,IncludeDocProps:!0},"object"==typeof e?e:{})};return v(t)},ActiveSheet:{ExportAsFixedFormatAsync:function(e){var t={api:"EtApplication().ActiveWorkbook.ActiveSheet.ExportAsFixedFormatAsync",args:o({Type:A.xlTypePDF,IncludeDocProps:!0},"object"==typeof e?e:{})};return v(t)}}},Enum:o({},A)}}}(g),e===t.presentation&&function(e){e.WppApplication=function(){return{ActivePresentation:{ExportAsFixedFormatAsync:function(e){var t={api:"WppApplication().ActivePresentation.ExportAsFixedFormatAsync",args:o({FixedFormatType:P.ppFixedFormatTypePDF,RangeType:E.ppPrintAll,FrameSlides:h.msoTrue},"object"==typeof e?e:{})};return v(t)}},Enum:o({},P,E)}}}(g)};console.log("WPS WebOffice JS-SDK V1.0.9"),e.config=function(e){void 0===e&&(e={}),g&&g.destroy();try{var t,n=y(e),i=n.wpsUrl,a=n.subscriptions,p=void 0===a?{}:a,s=n.mount,c=l(i,void 0===s?null:s);return delete n.mount,delete n.wpsUrl,delete n.subscriptions,D(),g={url:i,version:"1.0.9",iframe:c,Enum:o({},h),iframeReady:!1,tokenData:null,setToken:function(e){g.tokenData=e,g.iframeReady&&m({eventName:"setToken",data:e})},ready:function(){return t||(t=new Promise(function(e){var t=function(n){var o=r.parse(n.data).eventName;_(o)&&(e(),r.remove(t))};r.add(t)}))},destroy:function(){c.destroy(),r.empty(),g=null},save:function(){return v({api:"save"})}},T(n,p),g.ready(),g}catch(e){console.error(e)}},Object.defineProperty(e,"__esModule",{value:!0})});
2 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | ## 这是个 WPS 在线编辑服务的.NET CORE 版的 demo
2 |
3 | ## 注意如果部署在 IIS 上,需要在 IIS-网站-模块中移除 WebDAVModule 来允许 put 请求
4 |
5 | ## WPS 开放平台文档 [链接](https://open.wps.cn/docs/wwo/access/api-list)
6 |
7 | 在 appsettings.json 中配置 WPSConfig 的 AppId 以及 AppSecret 即可使用
8 |
9 | 简单测试方式:
10 | 1. 配置好AppId以及AppSecret
11 | 2. 在 WPSApi/Controllers/WPSController 的 FileInfo 方法返回值中将“download_url”属性设为你要在线预览的文件的**外网下载地址**
12 | 3. 生成并部署WPSApi
13 | 4. 在 HTML/index.html中调用WPSApi的GenarateWPSUrl接口即可看到效果
--------------------------------------------------------------------------------
/WPSApi/Controllers/WPSController.cs:
--------------------------------------------------------------------------------
1 | using log4net;
2 | using Microsoft.AspNetCore.Http;
3 | using Microsoft.AspNetCore.Mvc;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 | using WPSApi.Helper;
9 | using WPSApi.Model;
10 |
11 | namespace WPSApi.Controllers
12 | {
13 | [ApiController]
14 | public class WPSController : ControllerBase
15 | {
16 | private ILog _logger = LogManager.GetLogger("wps", "");
17 |
18 | ///
19 | /// 简单过滤一下HttpRequest参数
20 | ///
21 | ///
22 | ///
23 | private RequestParam FilterRequestForWPS(HttpRequest Request)
24 | {
25 | var result = new RequestParam();
26 | result.FileId = Request.Headers["x-weboffice-file-id"].ToString();
27 | var queryStr = Request.QueryString.ToString();
28 | queryStr = queryStr.StartsWith("?") ? queryStr.Substring(1) : queryStr;
29 | if (string.IsNullOrEmpty(queryStr) || string.IsNullOrEmpty(result.FileId))
30 | {
31 | return new RequestParam
32 | {
33 | code = 403,
34 | msg = "参数错误,无法打开文件",
35 | Status = false
36 | };
37 | }
38 |
39 | // url参数序列化成Dictionary
40 | result.Params = queryStr.Split("&", StringSplitOptions.RemoveEmptyEntries).ToDictionary(p => p.Split("=")[0], p => p.Split("=")[1]);
41 |
42 | // 此处判断是否传递了自定义的 _w_userId 参数,如果不需要此参数的话可以注释该判断
43 | if (!result.Params.ContainsKey("_w_userId"))
44 | {
45 | return new RequestParam
46 | {
47 | code = 403,
48 | msg = "用户异常",
49 | Status = false
50 | };
51 | }
52 | return result;
53 | }
54 |
55 | ///
56 | /// 生成iframe用的url(此方法非WPS官方的,主要是为了签名,也可以自己实现)
57 | ///
58 | ///
59 | ///
60 | [Route("api/wps/genarate")]
61 | [HttpPost]
62 | public Task GenarateWPSUrl(GenarateRequest request)
63 | {
64 | return Task.Run(() =>
65 | {
66 | var url = WPSSignatureHelper.GenarateUrl(request.FileId,
67 | request.FileType,
68 | new Dictionary {
69 | { "_w_userId", request.UserId },
70 | { "_w_fileName", request.FileName }
71 | });
72 | // 上面的写法是在生成的url中带了两个自定义参数 _w_userId 和 _w_fileName,可以根据业务自己扩展,生成url是这样的:
73 | // https://wwo.wps.cn/office/w/123?_w_appid=123456&_w_fileName=x.docx&_w_userId=5024&_w_signature=xxxxx
74 |
75 |
76 | // 也可以不写自定义参数,这样生成的url会只有 _w_appId 和 _w_ signatrue,例如:https://wwo.wps.cn/office/w/123?_w_appid=123456&_w_signature=xxxxx
77 | //var url = WPSHelper.GenarateUrl(request.FileId,request.FileType);
78 |
79 | return new GenarateResult { Url = url };
80 | });
81 | }
82 |
83 | #region WPS官方要求实现的回调接口
84 |
85 | ///
86 | /// 获取文件元数据
87 | ///
88 | ///
89 | [Route("v1/3rd/file/info")]
90 | [HttpGet]
91 | public Task FileInfo()
92 | {
93 | return Task.Run(() =>
94 | {
95 | // 简单的过滤下不合理的请求,可注释,以下接口基本上都有此过滤
96 | var request = FilterRequestForWPS(Request);
97 | if (!request.Status)
98 | {
99 | return new FileInfoResult { code = request.code, msg = request.msg };
100 | }
101 |
102 | // 获取自定义参数
103 | var userId = request.Params["_w_userId"].ToString();
104 |
105 | // 从数据库查询用户名、文件 等信息......
106 |
107 | // 创建时间和修改时间默认全是现在,可更改,但是注意时间戳是11位的(秒)
108 | var now = TimestampHelper.GetCurrentTimestamp();
109 |
110 | var result = new FileInfoResult
111 | {
112 | file = new Model.WPSFile
113 | {
114 | id = request.FileId,
115 | name = "文件名",
116 | version = 1,
117 | size = 1024, // WPS单位是B
118 | create_time = now,
119 | creator = "创建者用户名",
120 | modify_time = now,
121 | modifier = "修改者用户名",
122 | download_url = "文件下载链接",
123 | user_acl = new User_acl
124 | {
125 | history = 1, // 允许查看历史版本
126 | rename = 1, // 允许重命名
127 | copy = 1 // 允许复制
128 | },
129 | watermark = new Watermark
130 | {
131 | type = 0, // 1为有水印
132 | value = "水印文字"
133 | }
134 | },
135 | user = new UserForFile()
136 | {
137 | id = userId,
138 | name = "用户名",
139 | //permission = "read",
140 | permission = "write", // write为允许编辑,read为只能查看
141 | avatar_url = "用户头像url",
142 | }
143 | };
144 | return result;
145 | });
146 | }
147 |
148 | ///
149 | /// 获取用户信息
150 | ///
151 | /// 包含一个名为ids的字符串数组,里面是用户id
152 | ///
153 | [Route("v1/3rd/user/info")]
154 | [HttpPost]
155 | public Task GetUserInfo(GetUserInfoRequest body)
156 | {
157 | return Task.Run(() =>
158 | {
159 | var request = FilterRequestForWPS(Request);
160 | if (!request.Status)
161 | {
162 | return new UserModel();
163 | }
164 |
165 | var result = new UserModel
166 | {
167 | id = "用户ID",
168 | name = "用户名",
169 | avatar_url = "用户头像url"
170 | };
171 | return result;
172 | });
173 | }
174 |
175 | ///
176 | /// 通知此文件目前有哪些人正在协作
177 | ///
178 | ///
179 | ///
180 | [Route("v1/3rd/file/online")]
181 | [HttpPost]
182 | public Task Online(GetUserInfoRequest body)
183 | {
184 | return Task.Run(() =>
185 | {
186 | var result = new WPSBaseModel
187 | {
188 | code = 200,
189 | msg = "success"
190 | };
191 | return result;
192 | });
193 | }
194 |
195 | ///
196 | /// 上传文件新版本(保存文件)
197 | ///
198 | /// 传来的文件流
199 | ///
200 | [Route("v1/3rd/file/save")]
201 | [HttpPost]
202 | public Task SaveFile(IFormFile file)
203 | {
204 | return Task.Run(async () =>
205 | {
206 | try
207 | {
208 | var request = FilterRequestForWPS(Request);
209 | if (!request.Status)
210 | {
211 | return new SaveFileResult { code = request.code, msg = request.msg };
212 | }
213 |
214 | using (var stream = System.IO.File.Create("保存的文件名"))
215 | {
216 | await file.CopyToAsync(stream);
217 | }
218 |
219 | var result = new SaveFileResult
220 | {
221 | file = new WPSFileModel
222 | {
223 | download_url = "新的文件下载链接",
224 | id = request.FileId,
225 | name = request.Params["_w_fileName"].ToString()
226 | }
227 | };
228 | return result;
229 | }
230 | catch (Exception ex)
231 | {
232 | _logger.Error("save file failed: ", ex);
233 | return new SaveFileResult { code = 403, msg = "保存出现异常" };
234 | }
235 | });
236 | }
237 |
238 | ///
239 | /// 获取特定版本的文件信息
240 | ///
241 | /// 版本号
242 | ///
243 | [Route("/v1/3rd/file/version")]
244 | [HttpGet]
245 | public Task Version(int version)
246 | {
247 | return Task.Run(() =>
248 | {
249 | var request = FilterRequestForWPS(Request);
250 | if (!request.Status)
251 | {
252 | return new GetFileByVersionResult { code = request.code, msg = request.msg };
253 | }
254 |
255 | // 从数据库查询文件信息......
256 |
257 | // 创建时间和修改时间默认全是现在
258 | var now = TimestampHelper.GetCurrentTimestamp();
259 | var result = new GetFileByVersionResult
260 | {
261 | id = request.FileId,
262 | name = "文件名",
263 | version = 1,
264 | size = 1024,
265 | create_time = now,
266 | creator = "创建者用户名",
267 | modify_time = now,
268 | modifier = "修改者用户名",
269 | download_url = "文件下载url"
270 | };
271 | return result;
272 | });
273 | }
274 |
275 | ///
276 | /// 文件重命名
277 | ///
278 | /// 包含一个name的字符串属性,值为保存的新文件名
279 | ///
280 | [Route("v1/3rd/file/rename")]
281 | [HttpPut]
282 | public Task RenameFile(RenameFileRequest body)
283 | {
284 | return Task.Run(() =>
285 | {
286 | var request = FilterRequestForWPS(Request);
287 | if (!request.Status)
288 | {
289 | return new WPSBaseModel { code = request.code, msg = request.msg };
290 | }
291 |
292 | var result = new WPSBaseModel
293 | {
294 | code = 200,
295 | msg = "success"
296 | };
297 | return result;
298 | });
299 | }
300 |
301 | ///
302 | /// 获取所有历史版本文件信息
303 | ///
304 | ///
305 | ///
306 | [Route("v1/3rd/file/history")]
307 | [HttpPost]
308 | public Task GetHistory(GetHistoryRequest body)
309 | {
310 | return Task.Run(() =>
311 | {
312 | var request = FilterRequestForWPS(Request);
313 | if (!request.Status)
314 | {
315 | return new GetHistoryResult { code = request.code, msg = request.msg };
316 | }
317 | // 从数据库查询用户、文件信息等......
318 |
319 | // 创建时间和修改时间默认全是现在
320 | var now = TimestampHelper.GetCurrentTimestamp();
321 |
322 | // 不需要使用历史版本功能的此处也请返回,如果此接口不通时,文档加载会报错:“GetFileInfoFailed”
323 | var result = new GetHistoryResult
324 | {
325 | histories = new List
326 | {
327 | new HistroyModel
328 | {
329 | id=request.FileId,
330 | name="文件名",
331 | size=1024, // 单位B
332 | version=1,
333 | download_url="文件下载链接",
334 | create_time=now,
335 | modify_time=now,
336 | creator=new UserModel
337 | {
338 | id="创建者ID",
339 | name="创建者名",
340 | avatar_url = "创建者头像url"
341 | },
342 | modifier=new UserModel
343 | {
344 | id="修改者ID",
345 | name="修改者名",
346 | avatar_url = "修改者头像url"
347 | }
348 | }
349 | }
350 | };
351 | return result;
352 | });
353 | }
354 |
355 | ///
356 | /// 新建文件
357 | ///
358 | ///
359 | [Route("v1/3rd/file/new")]
360 | [HttpPost]
361 | public Task NewFile(CreateWPSFileRequest request)
362 | {
363 | return Task.Run(async () =>
364 | {
365 | try
366 | {
367 | var filterRequest = FilterRequestForWPS(Request);
368 | if (!filterRequest.Status)
369 | {
370 | return new CreateWPSFileResult { code = filterRequest.code, msg = filterRequest.msg };
371 | }
372 |
373 | using (var stream = System.IO.File.Create("保存的文件名"))
374 | {
375 | await request.file.CopyToAsync(stream);
376 | }
377 |
378 | var result = new CreateWPSFileResult
379 | {
380 | redirect_url = "新的文件访问链接",
381 | user_id = "创建人id"
382 | };
383 | return result;
384 | }
385 | catch (Exception ex)
386 | {
387 | _logger.Error("save file failed: ", ex);
388 | return new CreateWPSFileResult { code = 403, msg = "新建文件出现异常" };
389 | }
390 | });
391 | }
392 |
393 | ///
394 | /// 回调通知
395 | ///
396 | ///
397 | ///
398 | [Route("v1/3rd/onnotify")]
399 | [HttpPost]
400 | public Task WPSNotify(WPSNotifyRequest body)
401 | {
402 | return Task.Run(() =>
403 | {
404 | var result = new WPSBaseModel
405 | {
406 | code = 200,
407 | msg = "success"
408 | };
409 | return result;
410 | });
411 | }
412 |
413 | #endregion
414 | }
415 | }
416 |
--------------------------------------------------------------------------------
/WPSApi/Core/LogMiddlware.cs:
--------------------------------------------------------------------------------
1 | using log4net;
2 | using Microsoft.AspNetCore.Http;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace WPSApi.Core
9 | {
10 | ///
11 | /// 日志中间件,记录访问信息
12 | ///
13 | public class LogMiddlware
14 | {
15 | private ILog _logger = LogManager.GetLogger("wps", "");
16 | private RequestDelegate _next;
17 | public LogMiddlware(RequestDelegate next)
18 | {
19 | _next = next;
20 | }
21 | public async Task Invoke(HttpContext context)
22 | {
23 | _logger.Debug($"被访问,访问路径为:{(context.Request.Path.HasValue ? context.Request.Path.Value : "无")}");
24 | await _next(context);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/WPSApi/Helper/TimestampHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace WPSApi.Helper
4 | {
5 | ///
6 | /// 时间戳帮助类
7 | ///
8 | public class TimestampHelper
9 | {
10 | ///
11 | /// 日期转换为时间戳(时间戳单位秒)
12 | ///
13 | ///
14 | ///
15 | public static int GetCurrentTimestamp()
16 | {
17 | DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
18 | return (int)(DateTime.Now.AddHours(-8) - Jan1st1970).TotalSeconds;
19 | }
20 |
21 | ///
22 | /// 日期转换为时间戳(时间戳单位秒)
23 | ///
24 | ///
25 | ///
26 | public static int ConvertToTimeStamp(DateTime time)
27 | {
28 | DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
29 | return (int)(time.AddHours(-8) - Jan1st1970).TotalSeconds;
30 | }
31 |
32 | ///
33 | /// 时间戳转换为日期(时间戳单位秒)
34 | ///
35 | ///
36 | ///
37 | public static DateTime ConvertToDateTime(long timeStamp)
38 | {
39 | var start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
40 | return start.AddSeconds(timeStamp).AddHours(8);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/WPSApi/Helper/WPSSignatureHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Web;
6 | using WPSApi.Model;
7 |
8 | namespace WPSApi.Helper
9 | {
10 | ///
11 | /// WPS生成签名的帮助类
12 | ///
13 | public class WPSSignatureHelper
14 | {
15 | // url示例: https://wwo.wps.cn/office/w/999888777?_w_appid=d2a400fa455e42208c74a3de41d3cb3b&_w_myName=self&_w_signature=G8lG%2Bf0A%2BSbqrVFoMpmuLVOE8tM%3D
16 |
17 | ///
18 | /// AppId
19 | ///
20 | private static string AppId = string.Empty;
21 |
22 | ///
23 | /// AppKey
24 | ///
25 | private static string AppSecretKey = string.Empty;
26 |
27 | ///
28 | /// 配置AppId和Appkey
29 | ///
30 | ///
31 | ///
32 | public static void Config(string appId, string appSecretKey)
33 | {
34 | AppId = appId;
35 | AppSecretKey = appSecretKey;
36 | }
37 |
38 | ///
39 | /// 对字符串进行HMACSH1加密
40 | ///
41 | ///
42 | ///
43 | public static string ToHMACSHA1(string encryptText)
44 | {
45 | HMACSHA1 hmacsha1 = new HMACSHA1();
46 | hmacsha1.Key = System.Text.Encoding.Default.GetBytes(AppSecretKey);
47 | byte[] dataBuffer = System.Text.Encoding.Default.GetBytes(encryptText);
48 | byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);
49 | return Convert.ToBase64String(hashBytes);
50 | }
51 |
52 | ///
53 | /// 对参数签名
54 | ///
55 | ///
56 | /// 签名后的字符串
57 | public static string Signature(Dictionary paramDic)
58 | {
59 | var sortParam = paramDic.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value);
60 | sortParam.Add("_w_secretkey", AppSecretKey);
61 | var paramStr = string.Join("", sortParam.Select(p => $"{p.Key}={p.Value}").ToArray());
62 | var signature = ToHMACSHA1(paramStr);
63 | sortParam.Remove("_w_secretkey");
64 | sortParam.Add("_w_signature", HttpUtility.UrlEncode(signature));
65 | return string.Join("&", sortParam.Select(p => $"{p.Key}={p.Value}").ToArray());
66 | }
67 |
68 | ///
69 | /// 生成签名后iframe用的url
70 | ///
71 | ///
72 | ///
73 | ///
74 | ///
75 | // 此处直接读取了配置的appid,所以生成url时不用传递appid
76 | public static string GenarateUrl(string fileId, FileType fileType, Dictionary paramDic = null)
77 | {
78 | if (string.IsNullOrEmpty(AppId) || string.IsNullOrEmpty(AppSecretKey))
79 | {
80 | throw new ArgumentException("未配置 AppId 和 AppSecretKey,请在 Startup.cs 的 Startup() 构造函数中进行配置。");
81 | }
82 | if (paramDic == null)
83 | {
84 | paramDic = new Dictionary();
85 | }
86 |
87 | paramDic.Add("_w_appid", AppId);
88 | var paramStr = Signature(paramDic);
89 | return $"https://wwo.wps.cn/office/{fileType.ToString()}/{fileId}?{paramStr}";
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/WPSApi/Model/CreateWPSFileModel.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Http;
2 |
3 | namespace WPSApi.Model
4 | {
5 | ///
6 | /// 新建文件 入参
7 | ///
8 | public class CreateWPSFileRequest
9 | {
10 | ///
11 | /// 新建文件名
12 | ///
13 | public string name { get; set; }
14 |
15 | ///
16 | /// 新的文件
17 | ///
18 | public IFormFile file { get; set; }
19 | }
20 |
21 | ///
22 | /// 新建文件出参
23 | ///
24 | public class CreateWPSFileResult : WPSBaseModel
25 | {
26 | ///
27 | /// 一个可以访问到新创建文档的url
28 | ///
29 | // 官方给出的url样例是这样的:http://wwo.wps.cn/office/w/<:fileid>?_w_fname=example.doc&_w_userid=1000&_w_appid=xxx&_w_signature=xxx 需要签名
30 | public string redirect_url { get; set; }
31 |
32 | ///
33 | /// 创建人id
34 | ///
35 | public string user_id { get; set; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/WPSApi/Model/FileInfoResult.cs:
--------------------------------------------------------------------------------
1 | namespace WPSApi.Model
2 | {
3 | ///
4 | /// 获取文件元数据 出参
5 | ///
6 | public class FileInfoResult : WPSBaseModel
7 | {
8 | ///
9 | /// 文件
10 | ///
11 | public WPSFile file { get; set; }
12 |
13 | ///
14 | /// 用户信息
15 | ///
16 | public UserForFile user { get; set; }
17 | }
18 |
19 | ///
20 | /// 用户权限控制
21 | ///
22 | public class User_acl
23 | {
24 | ///
25 | /// 是否允许重命名,1:是 0:否
26 | ///
27 | public int rename { get; set; }
28 |
29 | ///
30 | /// 是否允许查看历史记录,1:是 0:否
31 | ///
32 | public int history { get; set; }
33 |
34 | ///
35 | /// 是否允许复制,1:是 0:否
36 | ///
37 | public int copy { get; set; }
38 | }
39 |
40 | ///
41 | /// 水印,只实现了简单的水印显示,如需配置水印的字体透明度等样式需要自己添加属性,参见:https://open.wps.cn/docs/wwo/access/api-list#des2 watermark部分
42 | ///
43 | public class Watermark
44 | {
45 | ///
46 | /// 是否有水印, 1:有 0:无
47 | ///
48 | public int type { get; set; }
49 |
50 | ///
51 | /// 水印字符串
52 | ///
53 | public string value { get; set; }
54 | }
55 |
56 | ///
57 | /// 文件model
58 | ///
59 | public class WPSFile
60 | {
61 | ///
62 | /// 文件id
63 | ///
64 | public string id { get; set; }
65 |
66 | ///
67 | /// 文件名
68 | ///
69 | public string name { get; set; }
70 |
71 | ///
72 | /// 版本号
73 | ///
74 | public int version { get; set; }
75 |
76 | ///
77 | /// 文件大小,单位B
78 | ///
79 | public int size { get; set; }
80 |
81 | ///
82 | /// 创建者用户名
83 | ///
84 | public string creator { get; set; }
85 |
86 | ///
87 | /// 创建时间的时间戳,单位秒
88 | ///
89 | public int create_time { get; set; }
90 |
91 | ///
92 | /// 修改者的用户名
93 | ///
94 | public string modifier { get; set; }
95 |
96 | ///
97 | /// 修改时间的时间戳,单位秒
98 | ///
99 | public int modify_time { get; set; }
100 |
101 | ///
102 | /// 文件下载url
103 | ///
104 | public string download_url { get; set; }
105 |
106 | ///
107 | /// 用户权限控制配置
108 | ///
109 | public User_acl user_acl { get; set; }
110 |
111 | ///
112 | /// 水印配置
113 | ///
114 | public Watermark watermark { get; set; }
115 | }
116 |
117 | ///
118 | /// 用户对于此文件的信息
119 | ///
120 | public class UserForFile
121 | {
122 | ///
123 | /// 用户id
124 | ///
125 | public string id { get; set; }
126 |
127 | ///
128 | /// 用户名
129 | ///
130 | public string name { get; set; }
131 |
132 | ///
133 | /// 用户对文件的权限,只能取 “read” 和 “write” 两个字符串,表示只读和可修改
134 | ///
135 | public string permission { get; set; }
136 |
137 | ///
138 | /// 用户头像url
139 | ///
140 | public string avatar_url { get; set; }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/WPSApi/Model/GenarateModel.cs:
--------------------------------------------------------------------------------
1 | namespace WPSApi.Model
2 | {
3 | ///
4 | /// 生成WPS的iframe url的入参,可以自己扩展参数,然后放到DIctionary中进行签名,参见写好的例子
5 | ///
6 | public class GenarateRequest
7 | {
8 | ///
9 | /// 用户id
10 | ///
11 | public string UserId { get; set; }
12 |
13 | ///
14 | /// 文件id
15 | ///
16 | public string FileId { get; set; }
17 |
18 | ///
19 | /// 文件名
20 | ///
21 | public string FileName { get; set; }
22 |
23 | ///
24 | /// 文件类型
25 | ///
26 | public FileType FileType { get; set; }
27 |
28 | ///
29 | /// 是否只读
30 | ///
31 | public string ReadOnly { get; set; }
32 | }
33 |
34 | ///
35 | ///
36 | ///
37 | public class GenarateResult
38 | {
39 | public string Url { get; set; }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/WPSApi/Model/GetFileByVersionModel.cs:
--------------------------------------------------------------------------------
1 | namespace WPSApi.Model
2 | {
3 | ///
4 | /// 获取特定版本的文件信息 出参
5 | ///
6 | public class GetFileByVersionResult : WPSBaseModel
7 | {
8 | ///
9 | /// 文件id
10 | ///
11 | public string id { get; set; }
12 |
13 | ///
14 | /// 文件名
15 | ///
16 | public string name { get; set; }
17 |
18 | ///
19 | /// 版本号
20 | ///
21 | public int version { get; set; }
22 |
23 | ///
24 | /// 文件大小,单位B
25 | ///
26 | public int size { get; set; }
27 |
28 | ///
29 | /// 创建者用户名
30 | ///
31 | public string creator { get; set; }
32 |
33 | ///
34 | /// 创建时间的时间戳(单位秒)
35 | ///
36 | public int create_time { get; set; }
37 |
38 | ///
39 | /// 修改者用户名
40 | ///
41 | public string modifier { get; set; }
42 |
43 | ///
44 | /// 修改时间的时间戳(单位秒)
45 | ///
46 | public int modify_time { get; set; }
47 |
48 | ///
49 | /// 下载链接
50 | ///
51 | public string download_url { get; set; }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/WPSApi/Model/GetHistoryModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace WPSApi.Model
4 | {
5 | ///
6 | /// 获取历史版本入参
7 | ///
8 | public class GetHistoryRequest
9 | {
10 | ///
11 | /// 文件id
12 | ///
13 | public string id { get; set; }
14 |
15 | ///
16 | /// 记录偏移量
17 | ///
18 | public int offset { get; set; }
19 |
20 | ///
21 | /// 记录总数
22 | ///
23 | public int count { get; set; }
24 | }
25 |
26 | ///
27 | /// 获取历史版本出参
28 | ///
29 | public class GetHistoryResult : WPSBaseModel
30 | {
31 | ///
32 | /// 历史记录列表
33 | ///
34 | public List histories { get; set; }
35 | }
36 |
37 | ///
38 | /// 文件历史记录model
39 | ///
40 | public class HistroyModel
41 | {
42 | ///
43 | /// 文件id
44 | ///
45 | public string id { get; set; }
46 |
47 | ///
48 | /// 文件名
49 | ///
50 | public string name { get; set; }
51 |
52 | ///
53 | /// 版本号
54 | ///
55 | public int version { get; set; }
56 |
57 | ///
58 | /// 文件大小,单位是B
59 | ///
60 | public int size { get; set; }
61 |
62 | ///
63 | /// 下载链接
64 | ///
65 | public string download_url { get; set; }
66 |
67 | ///
68 | /// 创建时间的时间戳(单位秒)
69 | ///
70 | public int create_time { get; set; }
71 |
72 | ///
73 | /// 修改时间的时间戳(单位秒)
74 | ///
75 | public int modify_time { get; set; }
76 |
77 | ///
78 | /// 创建人
79 | ///
80 | public UserModel creator { get; set; }
81 |
82 | ///
83 | /// 修改人
84 | ///
85 | public UserModel modifier { get; set; }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/WPSApi/Model/GetUserInfoModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace WPSApi.Model
4 | {
5 | ///
6 | /// 获取用户信息 入参model
7 | /// 通知此文件目前有那些人正在协作 入参model
8 | ///
9 | public class GetUserInfoRequest
10 | {
11 | ///
12 | /// 用户id数组
13 | ///
14 | public List ids { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/WPSApi/Model/RenameFileModel.cs:
--------------------------------------------------------------------------------
1 | namespace WPSApi.Model
2 | {
3 | ///
4 | /// 文件重命名 入参
5 | ///
6 | public class RenameFileRequest
7 | {
8 | ///
9 | /// 新的文件名
10 | ///
11 | public string name { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/WPSApi/Model/RequestParam.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace WPSApi.Model
4 | {
5 | ///
6 | /// 用来过滤下WPS回调的参数(包含url参数/headers)
7 | /// 继承了ErrorModel,如果请求参数不正常可直接返回error信息
8 | ///
9 | public class RequestParam : WPSBaseModel
10 | {
11 | ///
12 | /// 请求参数是否正常
13 | ///
14 | public bool Status { get; set; } = true;
15 |
16 | ///
17 | /// 文件ID
18 | ///
19 | public string FileId { get; set; }
20 |
21 | ///
22 | /// url参数
23 | ///
24 | public Dictionary Params { get; set; }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/WPSApi/Model/SaveFileResult.cs:
--------------------------------------------------------------------------------
1 | namespace WPSApi.Model
2 | {
3 | ///
4 | /// 上传文件新版本 出参
5 | ///
6 | public class SaveFileResult : WPSBaseModel
7 | {
8 | ///
9 | /// 文件信息
10 | ///
11 | public WPSFileModel file { get; set; }
12 | }
13 |
14 | ///
15 | /// 文件model
16 | ///
17 | public class WPSFileModel
18 | {
19 | ///
20 | /// 文件id
21 | ///
22 | public string id { get; set; }
23 |
24 | ///
25 | /// 文件名
26 | ///
27 | public string name { get; set; }
28 |
29 | ///
30 | /// 下载链接
31 | ///
32 | public string download_url { get; set; }
33 |
34 | ///
35 | /// 版本号
36 | ///
37 | public int version { get; set; }
38 |
39 | ///
40 | /// 文件大小,单位B
41 | ///
42 | public int size { get; set; }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/WPSApi/Model/UserModel.cs:
--------------------------------------------------------------------------------
1 | namespace WPSApi.Model
2 | {
3 | ///
4 | /// 用户信息model
5 | ///
6 | public class UserModel
7 | {
8 | ///
9 | /// 用户id
10 | ///
11 | public string id { get; set; }
12 |
13 | ///
14 | /// 用户名
15 | ///
16 | public string name { get; set; }
17 |
18 | ///
19 | /// 用户头像地址
20 | ///
21 | public string avatar_url { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/WPSApi/Model/WPSBaseModel.cs:
--------------------------------------------------------------------------------
1 | namespace WPSApi.Model
2 | {
3 | ///
4 | /// 基础model,包含了code和msg,基本上wps回调接口的出参都继承了它,方便出错的时候直接返回错误信息
5 | ///
6 | public class WPSBaseModel
7 | {
8 | public int code { get; set; } = 200;
9 | public string msg { get; set; } = "success";
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/WPSApi/Model/WPSEnum.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace WPSApi.Model
7 | {
8 | ///
9 | /// 文件类型枚举
10 | ///
11 | public enum FileType
12 | {
13 | ///
14 | /// 表格文件
15 | ///
16 | s = 0,
17 |
18 | ///
19 | /// 文字文件
20 | ///
21 | w = 1,
22 |
23 | ///
24 | /// 演示文件
25 | ///
26 | p = 2,
27 |
28 | ///
29 | /// PDF文件
30 | ///
31 | f = 3
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/WPSApi/Model/WPSNotifyRequest.cs:
--------------------------------------------------------------------------------
1 | namespace WPSApi.Model
2 | {
3 | ///
4 | /// 回调通知 入参
5 | ///
6 | public class WPSNotifyRequest
7 | {
8 | ///
9 | /// 回调命令的参数
10 | ///
11 | public string cmd { get; set; }
12 |
13 | ///
14 | /// 回调命令的内容 由于官方给的示例中body内容不固定,所以此处使用了object,可参考文档根据自己需求进行修改
15 | ///
16 | public object body { get; set; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/WPSApi/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace WPSApi
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | CreateWebHostBuilder(args).Build().Run();
18 | }
19 |
20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseStartup();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/WPSApi/Properties/PublishProfiles/FolderProfile.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | FileSystem
9 | FileSystem
10 | Release
11 | Any CPU
12 |
13 | True
14 | False
15 | netcoreapp2.1
16 | b98b5653-3584-405e-a67e-71bac1681546
17 | false
18 | bin\Release\netcoreapp2.1\publish\
19 | True
20 |
21 |
--------------------------------------------------------------------------------
/WPSApi/Properties/PublishProfiles/FolderProfile.pubxml.user:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 | <_PublishTargetUrl>E:\项目\GWQ\WPSApi\bin\Release\netcoreapp2.1\publish\
10 |
11 |
--------------------------------------------------------------------------------
/WPSApi/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:59182",
8 | "sslPort": 0
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "v1/3rd/file/info",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "WPSApi": {
21 | "commandName": "Project",
22 | "launchBrowser": true,
23 | "launchUrl": "v1/3rd/file/info",
24 | "applicationUrl": "http://localhost:5000",
25 | "environmentVariables": {
26 | "ASPNETCORE_ENVIRONMENT": "Development"
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/WPSApi/Startup.cs:
--------------------------------------------------------------------------------
1 | using log4net;
2 | using log4net.Config;
3 | using log4net.Repository;
4 | using Microsoft.AspNetCore.Builder;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.Extensions.Configuration;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using System.IO;
10 | using WPSApi.Core;
11 | using WPSApi.Helper;
12 |
13 | namespace WPSApi
14 | {
15 | public class Startup
16 | {
17 | public ILoggerRepository LoggerRepository;
18 | public Startup(IConfiguration configuration)
19 | {
20 | Configuration = configuration;
21 | // 配置日志
22 | LoggerRepository = LogManager.CreateRepository("wps");
23 | XmlConfigurator.Configure(LoggerRepository, new FileInfo("log4net.config"));
24 |
25 | // 配置WPS的 AppId 和 AppSecretKey
26 | WPSSignatureHelper.Config(configuration["WPSConfig:AppId"], configuration["WPSConfig:AppSecretKey"]);
27 | }
28 |
29 | public IConfiguration Configuration { get; }
30 |
31 | // This method gets called by the runtime. Use this method to add services to the container.
32 | public void ConfigureServices(IServiceCollection services)
33 | {
34 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
35 | services.AddCors(p =>
36 | {
37 | p.AddPolicy("wps", policy =>
38 | {
39 | policy.AllowAnyOrigin()
40 | .AllowAnyMethod()
41 | .AllowAnyHeader()
42 | .AllowCredentials();
43 | });
44 | });
45 | }
46 |
47 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
48 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
49 | {
50 | if (env.IsDevelopment())
51 | {
52 | app.UseDeveloperExceptionPage();
53 | }
54 | app.UseCors("wps");
55 | app.UseMiddleware();
56 | app.UseMvc();
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/WPSApi/WPSApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/WPSApi/WPSApi.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29806.167
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WPSApi", "WPSApi.csproj", "{B98B5653-3584-405E-A67E-71BAC1681546}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {B98B5653-3584-405E-A67E-71BAC1681546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {B98B5653-3584-405E-A67E-71BAC1681546}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {B98B5653-3584-405E-A67E-71BAC1681546}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {B98B5653-3584-405E-A67E-71BAC1681546}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {E7342BD3-ADF1-4139-B6E5-23870B63516B}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/WPSApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/WPSApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Warning"
5 | }
6 | },
7 | "AllowedHosts": "*",
8 | "WPSConfig": {
9 | "AppId": "123456",
10 | "AppSecretKey": "123456"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/WPSApi/log4net.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------