前言
附件使用的Dynamics CRM平台本身的注释表annotation存储,将附件转换成二进制字节流保存到数据库中,因自带的注释在页面中显示附件不够直观,特做了一个单独的附件管理自定义页面,通过CRM自定义按钮打开对话框的方式展示附件列表页面。同时支持下载附件模板,页面为简单的H5+Bootstrap+CSS布局设计,通过ajax调用webAPI接口实现上传、下载、删除等操作,本文一并附上后台接口代码。
注意:本文中实现上传不支持多文件同时上传,需要多文件同时上传,可找现成的前端文件上传组件,本文中通过input类型'file'传递给后台接口的文件只支持接收一个文件,多文件上传需要修改下对应的后台上传接口,增加参数HttpPostedFileBase[] files,并在处理文件的逻辑改成遍历循环处理即可,其他内容一致。
文件上传方式
html页面中一个选择文件的input,type类型为'file',再一个上传文件的button按钮,然后做一个表格用来展示已上传的附件列表。选择完文件后,点击上传按钮,获取input中选择的file,js组装new FormData()对象,赋值后台接口所需要的参数,然后ajax调用webapi接口,注意一定要设置processData: false和contentType: false,不然后台接口接收不到文件。后台接口将接受的文件转成流保存到数据库中。
其他的文件下载和删除就不介绍了,比较简单。
效果图
代码
自定义按钮打开对话框页面
1 /**
2 * 附件管理操作方法
3 */
4 function attachment() {
5 console.log("附件")
6 if (Xrm.Page.data.entity.getIsDirty()) {
7 Xrm.Utility.alertDialog("请先保存后再上传附件!")
8 return
9 }
10 let EntityId = commonUtil.delBrackets(Xrm.Page.data.entity.getId())
11 let EntityName = Xrm.Page.data.entity.getEntityName()
12
13 let params = { 'id': EntityId, 'type': EntityName}
14
15 var DialogOption = new Xrm.DialogOptions
16 DialogOption.width = 900;
17 DialogOption.height = 650;
18 // 参数一:URL,参数二:窗体配置,参数三:Json参数,参数四:--,参数五:--
19 Xrm.Internal.openDialog("/WebResources/foton_accountchannelaccess_attachment", DialogOption, params, null, function (returnValue) {
20 console.log('调用成功 返回值:' + returnValue); //这里就可以接收到弹窗上面传过来的数组
21 });
22 }
附件管理HTML
1 <!DOCTYPE html>
2
3 <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
4 <head>
5 <meta charset="utf-8" />
6 <title>附件管理</title>
7 <script src="foton_Jquery.min.js"></script>
8 <script src="ClientGlobalContext.js.aspx"></script>
9 <script src="foton_kd_base_js"></script>
10 <link href="foton_Newbootstrap.min.css" rel="stylesheet">
11 <link href="foton_componentsrounded.min.css" rel="stylesheet">
12 <link href="foton_components.min.css" rel="stylesheet">
13 <style type="text/css">
14 .fileinput-button input {
15 position: static;
16 opacity: 1;
17 filter: none;
18 font-size: inherit;
19 direction: inherit;
20 }
21
22 .fileinput-button span {
23 display: none;
24 }
25 </style>
26 </head>
27 <body style="overflow-wrap: break-word;">
28 <div class="col-md-12" style="width: 100%; height: 100%;">
29 <div class="portlet box portlet light portlet-fit bordered" style="height: 89%; margin-top: 40px;">
30 <div class="portlet-body" style="height: 15%;">
31 <div class="row">
32 <div class="col-md-8">商业计划书新签</div>
33 <div class="col-md-4" style=" float: right"><label style="color: red;" for="lb_cl1">点击下载模板</label></div>
34 </div>
35 <div class="row">
36 <div class="col-md-8">商业计划书续签</div>
37 <div class="col-md-4" style=" float: right"><label style="color: red;" for="lb_cl2">点击下载模板</label></div>
38 </div>
39 <div class="row">
40 <div class="col-md-8">渠道基本信息评价表</div>
41 <div class="col-md-4" style=" float: right"><label style="color: red;" for="lb_cl3">点击下载模板</label></div>
42 </div>
43 <div class="row">
44 <div class="col-md-8">海外网络退出要素确认表</div>
45 <div class="col-md-4" style=" float: right"><label style="color: red;" for="lb_cl4">点击下载模板</label></div>
46 </div>
47 <div class="row">
48 <div class="col-md-8">公司简介</div>
49 <div class="col-md-4"><label style="color: red;"></label></div>
50 </div>
51 </div>
52 <div class="portlet-title" style="height: 5%;">
53 <span>
54 <label style="color: red;">请先下载模板,根据模板维护数据后再上传附件!</label>
55 </span>
56 <!--<form id='fileupload' action='/Mpa/Annotation/UpLoadAttmention' method='POST' enctype='multipart/form-data'>
57 </form>-->
58 <div class='row fileupload-buttonbar'>
59 <input type='hidden' id='FileName' name='FileName' value='' />
60 <input type='hidden' id='UploadType' name='UploadType' value='' />
61 <div class='col-lg-7 btnDelete' id='btnFileUploadId' style='margin-left: 30px; float: right'>
62 <span class='btn green fileinput-button'>
63 <i class='fa fa-plus'></i>
64 <span>选择文件</span>
65 <input type='file' name='fileUpload' id='fileUpload' onchange='document.getElementById("FileName").value = this.value.substr(this.value.lastIndexOf("\\") + 1)'>
66 </span>
67 <button type='button' class='btn blue start' onclick='SaveFiles()'>
68 <i class='fa fa-upload'></i>
69 <span> 上传文件 </span>
70 </button>
71 </div>
72 </div>
73 </div>
74
75 <div class="portlet-body table-scrollable" style="height: 80%; overflow: auto; max-height: 800px; padding: 0 10px">
76 <table class="table table-bordered table-hover">
77 <thead>
78 <tr id="opp">
79 <th width="150" style='vertical-align: middle;text-align: center;'> 文件名称 </th>
80 <th width="150" style='vertical-align: middle;text-align: center;'> 文件类型 </th>
81 <th width="150" style='vertical-align: middle;text-align: center;'> 创建时间 </th>
82 <th width="200" style='vertical-align: middle;text-align: center;'> 操作 </th>
83 </tr>
84 </thead>
85 <tbody id="Dataid"></tbody>
86 </table>
87 </div>
88 </div>
89 </div>
90
91
92 <script type="text/javascript">
93 let entityId = window.getDialogArguments().id
94 let entityName = window.getDialogArguments().type
95 let queryStr = ""
96 var apiUrl = ""
97 var fileObj = document.getElementById("fileUpload")
98 var outerHTML = fileObj.outerHTML;
99 //页面加载
100 $(function () {
101 setWebAPIURL()
102 initOnload()
103 var label1 = $("label[for='lb_cl1']");
104 label1.on("click", function () {
105 console.log("你点击了label1标签");
106 downloadTemplate(1)
107 });
108 var label2 = $("label[for='lb_cl2']");
109 label2.on("click", function () {
110 console.log("你点击了label2标签");
111 downloadTemplate(2)
112 });
113 var label3 = $("label[for='lb_cl3']");
114 label3.on("click", function () {
115 console.log("你点击了label3标签");
116 downloadTemplate(3)
117 });
118 var label4 = $("label[for='lb_cl4']");
119 label4.on("click", function () {
120 console.log("你点击了label4标签");
121 downloadTemplate(4)
122 });
123 })
124 //设置webapi请求地址
125 function setWebAPIURL() {
126 if (Xrm.Page.context.getClientUrl().indexOf("Testf") >= 0)//测试环境
127 apiUrl = "http://localhost:50887/"; //测试:http://10.100.56.13:8001/ ,本地:http://localhost:50887/
128 else if (Xrm.Page.context.getClientUrl().indexOf("hwdms") >= 0)//正式环境
129 apiUrl = "https://hwapi.foton.com.cn/";
130 }
131 /**
132 * 页面初始化加载
133 */
134 function initOnload() {
135 //获取客户经销商窗体下的所有附件
136 queryStr = `/annotations?$select=annotationid,createdon,documentbody,filename,filesize,mimetype,_objectid_value,objecttypecode,subject&$filter=_objectid_value eq ${entityId}&$orderby=createdon desc`
137 commonUtil.queryWithUrl(queryStr, result => {
138 $("#Dataid").empty();
139 if (!result.success || !result.data || result.data.length < 1) {
140 console.log("当前客户尚未上传附件!")
141 return
142 }
143 console.log(result.data)
144 for (var i = 0; i < result.data.length; i++) {
145 var html = "<tr class='success'>"
146 + "<td style='width: 5px;display:none;'> <input type='hidden' name='annotation_id"+ i+"' value='" + result.data[i]["annotationid"] + "'/> </td>";
147 //文件名称
148 if (!!result.data[i]["filename"]) {
149 html += "<td width='150px;' align='center' valign='middle' title='" + result.data[i]["filename"] + "'> " + result.data[i]["filename"] + " </td>";
150 } else {
151 html += "<td width='150px;'></td>";
152 }
153 //文件类型
154 if (!!result.data[i]["mimetype"]) {
155 html += "<td width='150px;' align='center' valign='middle' title='" + result.data[i]["mimetype"] + "'> " + result.data[i].filename.substr(result.data[i].filename.lastIndexOf(".") + 1) + " </td>";
156 } else {
157 html += "<td width='150px;'></td>";
158 }
159 //创建时间
160 if (!!result.data[i]["createdon"]) {
161 html += "<td width='150px;' align='center' valign='middle' title='" + result.data[i]["createdon"] + "'> " + result.data[i]["createdon@OData.Community.Display.V1.FormattedValue"] + " </td>";
162 } else {
163 html += "<td width='150px;'></td>";
164 }
165 //操作
166 html += "<td width='200px;' align='center' valign='middle'>"
167 + "<button class='btn blue start' type='button' onclick=DownloadFile('" + result.data[i].annotationid + "');>"
168 + "<i class='fa fa-download'></i><span>下载</span>"
169 + "</button> "
170 + "<button class='btn red cancel obsbtnDelete' onclick= \"DeleteFile('" + result.data[i].annotationid + "')\"><i class='fa fa-trash'></i><span>删除</span></button>"
171 + "</td> ";
172
173 html += "</tr>";
174
175 $("#Dataid").append(html + "<br/>");
176 }
177
178 }, false)
179
180 }
181 /*
182 * 调用接口上传文件
183 */
184 function SaveFiles(callback) {
185 var files = document.getElementById("fileUpload").files[0]
186 if (files.length < 1) {
187 Xrm.Utility.alertDialog("请先选择文件!")
188 return
189 }
190 if (!callback) {
191 overflowLayer.open("上传附件中....", SaveFiles)
192 return
193 }
194 var formFile = new FormData();
195 formFile.append("entityId", entityId);//实体数据id
196 formFile.append("entityName", entityName);//实体名
197 formFile.append("files", files); //加入文件对象
198 $.ajax({
199 url: apiUrl + "AccountChannelAccess/SaveAnnotation",
200 type: "post",
201 data: formFile,
202 dataType: 'json',
203 //mimeType: "multipart/form-data",
204 async: true, //使用同步的方式,true为异步方式
205 processData: false,
206 contentType: false,
207 success: function (data, textStatus, xhr) {
208 overflowLayer.close();
209 if (data.code == 0) {
210 Xrm.Utility.alertDialog(data.msg);
211 } else {
212 Xrm.Utility.alertDialog("上传成功");
213 //刷新页面
214 initOnload()
215 //清除选择input里已上传的文件
216 fileObj.outerHTML = outerHTML
217 }
218 },
219 error: function (xhr, textStatus, errorThrown) {
220 Xrm.Utility.alertDialog("请求接口【" + apiUrl + "】失败!请联系管理员!");
221 overflowLayer.close();
222 }
223 });
224 }
225 /**
226 * 删除已上传的文件
227 * @param {any} annotationId 附件id
228 */
229 function DeleteFile(annotationId) {
230 Xrm.Utility.confirmDialog("您确认要删除此附件吗?", function () {
231 $.ajax({
232 url: apiUrl + "AccountChannelAccess/DelAnnotation",
233 type: "post",
234 data: { "": annotationId },
235 dataType: 'json',
236 async: false, //使用同步的方式,true为异步方式
237 success: function (data, textStatus, xhr) {
238 if (data.code == 0) {
239 Xrm.Utility.alertDialog("删除失败!" + data.msg);
240 }
241 Xrm.Utility.alertDialog("删除成功!");
242 initOnload()
243 },
244 error: function (xhr, textStatus, errorThrown) {
245 Xrm.Utility.alertDialog("请求接口【" + apiUrl + "】失败!请联系管理员!")
246 }
247 });
248 });
249 }
250 /*
251 * 下载文件
252 * @param {any} annotationId 附件id
253 */
254 function DownloadFile(annotationId) {
255 console.log(annotationId);
256 location.href = apiUrl + 'AccountChannelAccess/DownloadAnnotation?id=' + annotationId;
257 }
258 /**
259 * 下载附件模板
260 * @param {any} type 1商业计划书新签,2商业计划书续签,3渠道基本信息评价表,4海外网络退出要素确认表
261 */
262 function downloadTemplate(type) {
263 //请求webAPI接口下载模板文件
264 location.href = apiUrl + 'AccountChannelAccess/DownloadFileTemplate?type=' + type;
265 }
266 </script>
267 </body>
268 </html>
HTML
WebAPI接口代码
1 using Microsoft.Xrm.Sdk;
2 using Microsoft.Xrm.Sdk.Query;
3 using Newtonsoft.Json;
4 using NPOI.OpenXml4Net.OPC.Internal;
5 using System;
6 using System.Collections.Generic;
7 using System.Data.Entity.Core.Objects.DataClasses;
8 using System.IO;
9 using System.Linq;
10 using System.Net;
11 using System.Net.Http;
12 using System.Net.Http.Headers;
13 using System.Reflection;
14 using System.Text;
15 using System.Threading.Tasks;
16 using System.Web;
17 using System.Web.Http;
18 using ZZ_Common_API.Crm;
19 using ZZ_Common_API.Models.QDRWModels;
20 using EntityReference = Microsoft.Xrm.Sdk.EntityReference;
21
22 namespace ZZ_Common_API.Controllers.QDRWControllers
23 {
24 /// <summary>
25 /// 附件相关WebAPI接口
26 /// </summary>
27 [RoutePrefix("AccountChannelAccess")]
28 public class AccountChannelAccessController : ApiController
29 {
30 #region 下载模板文件 strat
31 /// <summary>
32 /// 下载附件
33 /// </summary>
34 /// <param name="type">1商业计划书新签,2商业计划书续签,3渠道基本信息评价表,4海外网络退出要素确认表</param>
35 /// <returns></returns>
36 [Route("DownloadFileTemplate")]
37 [HttpGet]
38 public async Task<dynamic> DownloadFileTemplate(int type)
39 {
40 HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
41 string fileName = string.Empty;
42 switch (type)
43 {
44 case 1:
45 fileName = "附件1:商业计划书新签(可下载模版).pptx";
46 break;
47 case 2:
48 fileName = "附件2:商业计划书续签(可下载模版).pptx";
49 break;
50 case 3:
51 fileName = "附件3:渠道基本信息评价表(可下载模版).docx";
52 break;
53 case 4:
54 fileName = "附件4:海外网络退出要素确认表(可下载模板).docx";
55 break;
56 default:
57 fileName = "附件1:商业计划书新签(可下载模版).pptx";
58 break;
59 }
60
61 var filePath = AppDomain.CurrentDomain.BaseDirectory + @"\Files\Template\" + fileName;
62 if (!File.Exists(filePath))
63 {
64 return ResponseMessage(new HttpResponseMessage()
65 {
66 Content =
67 new StringContent(JsonConvert.SerializeObject(Json(new { code = 0, msg = $"下载失败,未能找到文件-{fileName}的路径" })),
68 Encoding.GetEncoding("UTF-8"), "application/json"),
69 StatusCode = HttpStatusCode.NoContent
70 });
71 }
72 var stream = new FileStream(filePath, FileMode.Open);
73 responseMessage.Content = new StreamContent(stream);
74 responseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
75 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlPathEncode(fileName));
76 return ResponseMessage(responseMessage);
77 }
78
79
80 #endregion 下载模板文件 end
81
82 #region 上传附件 start
83 /// <summary>
84 /// 使用系统的注释Annotation 添加附件
85 /// </summary>
86 /// <returns></returns>
87 [Route("SaveAnnotation")]
88 [HttpPost]
89 public object SaveAnnotation()
90 {
91 try
92 {
93 HttpFileCollection fileCollection = HttpContext.Current.Request.Files;
94 if (fileCollection.Count <= 0)
95 {
96 return Json(new { code = 0, msg = $"请先选择文件后点击上传" });
97 }
98 var formData = HttpContext.Current.Request.Form;
99 var entityId = formData["entityId"];
100 var entityName = formData["entityName"];
101
102 Guid objId = Guid.Empty;
103 if (!Guid.TryParse(entityId, out objId)) //检验实体id是否合法
104 {
105 return Json(new { code = 0, msg = $"上传失败,entityId是不合法的GUID:{entityId}" });
106 }
107 HttpPostedFile formFile = fileCollection[0];
108 if (formFile.ContentLength > 1048576000)//检查文件大小
109 {
110 return Json(new { code = 0, msg = $"{formFile.FileName}文件大小不得超过{1048576000 / (1024f * 1024f)}M" });//请求体过大,文件大小超标
111 }
112 var suffix = Path.GetExtension(formFile.FileName);//提取上传的文件文件后缀
113 if (".js;.bat;.exe;.sh".IndexOf(suffix) > 0) //检查文件格式
114 {
115 return Json(new { code = 0, msg = $"不支持此文件类型-{suffix}" });//类型不正确
116 }
117
118 AnnotationModel model = new AnnotationModel();
119 model.Subject = Path.GetFileName(formFile.FileName).Substring(1);
120 model.NoteText = "";
121 model.ObjectId = objId;
122 model.ObjectIdName = entityName;
123 model.MimeType = formFile.ContentType;
124 model.FileSize = formFile.ContentLength;
125 model.FileName = Path.GetFileName(formFile.FileName);
126 model.DocumentBody = Convert.ToBase64String(GetFileByte(formFile));
127 //保存到Annotation中
128 CreateAnnotation(model);
129
130 return Json(new { code = 1, msg = "上传成功" });
131 }
132 catch (Exception ex)
133 {
134 return Json(new { code = 0, msg = $"上传失败 + {ex.Message}" });
135 }
136 }
137 #endregion 上传附件 end
138
139 #region 下载附件 start
140 /// <summary>
141 /// 下载附件
142 /// </summary>
143 /// <param name="id">附件id</param>
144 /// <returns></returns>
145 [Route("DownloadAnnotation")]
146 [AcceptVerbs("GET")]
147 public IHttpActionResult DownloadAnnotation(string id)
148 {
149 //通过附件id 找到附件 然后转化附件字节流 填入到响应中
150 HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
151 try
152 {
153 if (string.IsNullOrEmpty(id))
154 {
155 return ResponseMessage(new HttpResponseMessage(HttpStatusCode.Gone));
156 }
157 Tuple<string, Stream> tuple = GetAnnotationStream(id);
158 if (tuple.Item1 == "未能获取到字节流")
159 {
160 return ResponseMessage(new HttpResponseMessage(HttpStatusCode.Gone));
161 }
162 responseMessage.Content = new StreamContent(tuple.Item2);
163 responseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
164 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlPathEncode(tuple.Item1));
165 }
166 catch (Exception ex)
167 {
168 return ResponseMessage(new HttpResponseMessage()
169 {
170 Content =
171 new StringContent(JsonConvert.SerializeObject(Json(new { code = 0, msg = $"下载失败-{ex.Message}" })),
172 Encoding.GetEncoding("UTF-8"), "application/json"),
173 StatusCode = HttpStatusCode.NoContent
174 });
175 }
176 return ResponseMessage(responseMessage);
177 }
178 #endregion 下载附件 end
179
180 #region 根据实体id获取实体数据下相关所有附件,打包成zip文件下载 start
181 /// <summary>
182 /// 下载实体数据下所有的附件zip
183 /// 根据实体id获取实体数据下相关所有附件,打包成zip文件下载
184 /// </summary>
185 /// <param name="id"></param>
186 /// <returns></returns>
187 [Route("DownloadAnnotationAll")]
188 [AcceptVerbs("GET")]
189 public IHttpActionResult DownloadAnnotationAll(string id)
190 {
191 HttpResponseMessage responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
192 try
193 {
194 if (string.IsNullOrEmpty(id))
195 {
196 return ResponseMessage(new HttpResponseMessage(HttpStatusCode.Gone));
197 }
198 //通过模块id 找到相关的所有附件 然后将所有的附件打包成zip文件 将zip文件转化字节流 填入到响应流中
199 if (string.IsNullOrEmpty(id))
200 {
201 return ResponseMessage(new HttpResponseMessage(HttpStatusCode.Gone));
202 }
203 Tuple<string, Stream> tuple = GetAllAnnotationStream(id);
204 if (tuple.Item1 == "未能获取到字节流")
205 {
206 return ResponseMessage(new HttpResponseMessage(HttpStatusCode.Gone));
207 }
208 responseMessage.Content = new StreamContent(tuple.Item2);
209 responseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
210 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlPathEncode(tuple.Item1));
211 }
212 catch (Exception ex)
213 {
214 return ResponseMessage(new HttpResponseMessage()
215 {
216 Content =
217 new StringContent(JsonConvert.SerializeObject(Json(new { code = 0, msg = $"下载失败-{ex.Message}" })),
218 Encoding.GetEncoding("UTF-8"), "application/json"),
219 StatusCode = HttpStatusCode.NoContent
220 });
221 }
222 return ResponseMessage(responseMessage);
223 }
224
225 #endregion 根据实体id获取实体数据下相关所有附件,打包成zip文件下载 end
226
227 #region API专用 删除附件
228 /// <summary>
229 /// 删除附件
230 /// </summary>
231 /// <param name="id">附件ids</param>
232 /// <returns></returns>
233 [Route("DelAnnotation")]
234 [HttpPost]
235 public object DelAnnotation([FromBody] string id)
236 {
237 try
238 {
239 if (string.IsNullOrEmpty(id))
240 {
241 return Json(new { code = 0, msg = $"删除附件时id不能为空" });
242 }
243 DeleteAnnotation(id);
244 return Json(new { code = 1, msg = "删除成功" }); ;
245 }
246 catch (Exception ex)
247 {
248 return Json(new { code = 0, msg = $"删除失败:{ex.Message}" });
249 }
250 }
251 #endregion API专用 删除附件
252
253 #region 内部方法 start
254
255 #region 上传附件存到Annotation中 start
256 /// <summary>
257 /// 将上传文件对象转化成byte字节流
258 /// </summary>
259 /// <param name="httpPostedFile">上传文件</param>
260 /// <returns></returns>
261 private byte[] GetFileByte(HttpPostedFile httpPostedFile)
262 {
263 byte[] bytes = new byte[httpPostedFile.ContentLength];
264 using (BinaryReader reader = new BinaryReader(httpPostedFile.InputStream, Encoding.UTF8))
265 {
266 bytes = reader.ReadBytes(bytes.Length);
267 }
268 return bytes;
269 }
270 /// <summary>
271 /// 创建附件数据
272 /// </summary>
273 /// <param name="annotation"></param>
274 /// <returns></returns>
275 private Guid CreateAnnotation(AnnotationModel annotation)
276 {
277 Guid guid = Guid.Empty;
278 IOrganizationService orgService = OrgServiceUtil.Client;
279 Entity entity = new Entity("annotation");
280 entity["filename"] = annotation.FileName;
281 entity["subject"] = annotation.Subject;
282 entity["mimetype"] = annotation.MimeType;
283 entity["filesize"] = annotation.FileSize;
284 entity["documentbody"] = annotation.DocumentBody;
285 entity["objectid"] = new EntityReference(annotation.ObjectIdName, annotation.ObjectId);
286 guid = orgService.Create(entity);
287 return guid;
288 }
289 #endregion 上传附件存到Annotation中 end
290
291
292 #region 根据附件id获取附件字节流 start
293 /// <summary>
294 /// 根据附件id获取附件字节流
295 /// </summary>
296 /// <param name="annotationid">annotationid</param>
297 /// <returns></returns>
298 public Tuple<string, Stream> GetAnnotationStream(string annotationid)
299 {
300 Tuple<string, Stream> rr = new Tuple<string, Stream>("未能获取到字节流", null);
301 try
302 {
303 IOrganizationService orgService = OrgServiceUtil.Client;
304 ColumnSet cols = new ColumnSet("filename", "documentbody");
305 Entity entity = orgService.Retrieve("annotation", new Guid(annotationid), cols);
306 string documentbody = entity.GetAttributeValue<string>("documentbody");
307 string filename = entity.GetAttributeValue<string>("filename");
308 byte[] fileContent = Convert.FromBase64String(documentbody);
309 Stream fileStream = new MemoryStream(fileContent);
310 rr = new Tuple<string, Stream>(filename, fileStream);
311 }
312 catch (Exception)
313 {
314 return rr;
315 }
316 return rr;
317 }
318 #endregion 根据附件id获取附件字节流 end
319
320 #region 根据实体数据id获取所有附件并打包成zip文件,然后转换成字节流 start
321 /// <summary>
322 /// 根据实体数据id获取所有附件达成zip包后转换成字节流
323 /// </summary>
324 /// <param name="entityId">实体数据id</param>
325 /// <returns></returns>
326 public Tuple<string, Stream> GetAllAnnotationStream(string entityId)
327 {
328 Tuple<string, Stream> rr = new Tuple<string, Stream>("未能获取到字节流", null);
329 try
330 {
331 IOrganizationService orgService = OrgServiceUtil.Client;
332 //1.根据实体数据id查询出所有相关得附件
333 var dbList = GetDbFileByEntityId(orgService,new Guid(entityId));
334 //2.遍历所有相关得附件 将各个附件流转化存放到内存字典中
335 Dictionary<string, byte[]> dic = new Dictionary<string, byte[]>();
336 foreach (var cc in dbList)
337 {
338 string documentbody = cc.GetAttributeValue<string>("documentbody");
339 string filename = cc.GetAttributeValue<string>("filename");
340 byte[] fileContent = Convert.FromBase64String(documentbody);
341 Tuple<string, byte[]> tt = new Tuple<string, byte[]>(filename, fileContent);
342 if (tt.Item2 == null)
343 {
344 continue;
345 }
346 dic.Add(tt.Item1, tt.Item2);
347 }
348 if (dic.Count > 0)
349 {
350 //3.将多个字节流从字典压缩成zip文件并转成一个字节流
351 Stream stream = ZipByteHelper.SetbytesToZipStream2(dic);
352 rr = new Tuple<string, Stream>("附件.zip", stream);
353 }
354 }
355 catch (Exception)
356 {
357 return rr;
358 }
359 return rr;
360 }
361
362 private List<Entity> GetDbFileByEntityId(IOrganizationService orgService,Guid entityId)
363 {
364 var list = new List<Entity>();
365 QueryExpression query = new QueryExpression("annotation");
366 query.ColumnSet = new ColumnSet(true);
367 query.Criteria.AddCondition(new ConditionExpression("objectid", ConditionOperator.Equal, entityId));
368 var datas = orgService.RetrieveMultiple(query);
369 list = datas.Entities.ToArray().ToList();
370 return list;
371 }
372 #endregion 根据实体数据id获取所有附件并打包成zip文件,然后转化称字节流 end
373
374 #region 删除附件 start
375 /// <summary>
376 /// 删除附件注释
377 /// </summary>
378 /// <param name="annotationid">附件id</param>
379 /// <returns></returns>
380 /// <exception cref="Exception"></exception>
381 public bool DeleteAnnotation(string annotationid)
382 {
383 bool result = true;
384 if (string.IsNullOrEmpty(annotationid))
385 {
386 result = false;
387 }
388 IOrganizationService orgService = OrgServiceUtil.Client;
389 orgService.Delete("annotation", Guid.Parse(annotationid));
390 return result;
391 }
392 #endregion 删除附件 end
393 #endregion 内部方法 end
394 }
395 }
webAPI接口
拓展Zip流压缩帮助类
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Web;
6
7 namespace ZZ_Common_API.Utilities
8 {
9 /// <summary>
10 /// 压缩、解压帮助类
11 /// </summary>
12 public static class ZipByteHelper
13 {
14 /// <summary>
15 /// 将多个文件流转化成zip文件流
16 /// </summary>
17 /// <param name="dic"></param>
18 /// <returns></returns>
19 public static Stream SetbytesToZipStream2(Dictionary<string, byte[]> dic)
20 {
21 byte[] buffer = new byte[6500];
22 MemoryStream returnStream = new MemoryStream();
23 var zipMs = new MemoryStream();
24 using (ICSharpCode.SharpZipLib.Zip.ZipOutputStream zipStream = new ICSharpCode.SharpZipLib.Zip.ZipOutputStream(zipMs))
25 {
26 zipStream.SetLevel(9);//设置 压缩等级 (9级 500KB 压缩成了96KB)
27 foreach (var kv in dic)
28 {
29 string fileName = kv.Key;
30 using (var streamInput = new MemoryStream(kv.Value))
31 {
32 zipStream.PutNextEntry(new ICSharpCode.SharpZipLib.Zip.ZipEntry(fileName));
33 while (true)
34 {
35 var readCount = streamInput.Read(buffer, 0, buffer.Length);
36 if (readCount > 0)
37 {
38 zipStream.Write(buffer, 0, readCount);
39 }
40 else
41 {
42 break;
43 }
44 }
45 zipStream.Flush();
46 }
47 }
48 zipStream.Finish();
49 zipMs.Position = 0;
50 zipMs.CopyTo(returnStream, 5600);
51 }
52 returnStream.Position = 0;
53
54 return returnStream;
55 }
56 }
57 }
ZIP帮助类