Dynamics CRM中自定义页面实现附件管理包含下载模板、上传、下载、删除

前言
附件使用的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帮助类

相关推荐
陈逸子风2 天前
(系列十一)Vue3框架中路由守卫及请求拦截(实现前后端交互)
vue3·webapi·权限·流程·表单
csdn_aspnet14 天前
.NET 8 Web API 中的身份验证和授权
webapi·.net8.0
csdn_aspnet14 天前
在 .NET 8 Web API 中实现 Entity Framework 的 Code First 方法
webapi·.net8.0
csdn_aspnet17 天前
.NET 8 中的 Mini WebApi
webapi·.net8.0
csdn_aspnet19 天前
使用 ASP.NET Core 8.0 创建最小 API
webapi·.net8.0
陈逸子风1 个月前
(系列五).net8 中使用Dapper搭建底层仓储连接数据库(附源码)
vue3·webapi·权限·流程
陈逸子风2 个月前
从0到1搭建权限管理系统系列四 .net8 中Autofac的使用(附源码)
vue3·webapi·权限·流程·表单
陈逸子风2 个月前
从0到1搭建权限管理系统系列三 .net8 JWT创建Token并使用
vue3·webapi·权限·流程
陈逸子风2 个月前
.net core8 使用JWT鉴权(附当前源码)
vue3·webapi·权限·流程
gc_22992 个月前
测试ASP.NET Core的WebApi项目调用WebService
webapi·vs2022·webservice