.net mvc 站点自带简易SSL加密传输

 

因项目需要,传输数据需要加密,因此有了一些经验,现简易抽出来分享!

请求:
前端cryptojs用rsa/aes 或 rsa/des加密,后端.net 解密
返回
后端.net用rsa/aes 或 rsa/des加密,前端cryptojs解密

图示:

数据发送加密:

返回数据加密:

开源代码分享:https://github.com/guandy/NetSSL

现只是简易抽出,如果后续需求量大可考虑做成组件

Word报告自动生成(例如 导出数据库结构)

 

将很早之前写的一个小组件重新整理优化一下,做成一个通用的功能。适用于导出数据库的结构(表、字段等)到Word或将体检数据自动生成Word版的体检报告等。代码:Github

一、主要需要完成功能:

1. 灵活的配置规则及word样式设置(文本、表格、图表、颜色等).

2. 支持表格.

3. 支持图表.

4. 支持章节内容循环生成.

5. 支持目录.

6.支持文档结构图

7.更新指定位置的文字

8.支持pdf导出.

最后结果如下:

图一

图二

图三

二、需求分析与实现方式

   功能主要涉及3个比较重要的部分:数据源、Word样式、配置规则。

为了简单,数据源决定采用一个存储过程返回Dataset的方式, 整张报告的数据来源于此Dataset的多个Datatable.

  样式与配置:首先想到的是写一个config文件,所有配置都放到一个文件里,然后将数据按照这个规则生成word。但无疑这样的配置项太多了,关键是“样式”问题,比如字体、颜色、表格宽度.....想想就头大。而且没有“所见即所得”的效果,配置完都不知道啥样。

后来决定采取修改的方式, 先以一个word文件作为模板,在模板中定义好上面提到的“样式”,然后在模板中做一个个标记,然后将数据按照规则更新到对应的标记。

图四

而这个标记我们用到了word的一个叫【书签】的功能,打开word按ctrl+shift+F5, 打开书签功能,如下图:

图五

这样将【规则】通过一系列规则的【书签】定义到word模板中。

三、规则配置

  思路确定了,那就开始设计如何通过【书签】将规则定义到word模板中去,这里决定将所有规则都通过【书签】实现,而放弃config文件的方式,这个更统一而且直观一些。

A.循环

以图四为例,数据库有多少张表是不固定的,我们在制作模板的时候不可能先画好N(N为表的总数)个表格等待数据填充, 这里就会需要遍历数据源中提供的所有表结构数据,然后逐一形成表格。这里就需要将图四中的表格循环一下,自动复制生成多个这样的表格。当然,这只是一种情况,还有可能会出现循环嵌套循环的情况,那么我将这个循环定义成一个书签的时候按照这样的格式:

 loop_级别_表序号_filter_名称

含义如下:

loop:代表这是一个循环。

级别:默认文档级别为0,出现的第一层循环为1,其内部若再次嵌套循环则级别为2,依次类推。

表序号:取Dataset中的第几张表(从1开始)

filter:循环的时候可能会用到对datatable的查找过滤,在此写出,多个字段用XX隔开(因为此处不允许有下划线外其他特殊字符, 就用这个XX吧 )

名称:loop名称,方便与其他 loop区别

B.更新指定位置的文字

如图四中的【服务器名】、【表总数】等,只需要替换对应的文字即可:

label_级别_名称

含义如下:

label:代表这是一个label。

级别:默认文档级别为0,出现的第一层循环为1,其内部若再次嵌套循环则级别为2,依次类推。

名称:label名称

注意这里省略了表序号,当级别为0的时候 ,自动取最后一个datatable中的数据,因为这个label经常会用到其他表汇总的数据,可能会用到之前几张表的数据,所以放在其他表都处理好后。当级别为1的时候,自然取该级别循环的行数据。

C.表格

表格的配置原本也想对表格添加书签,后来发现有个表格属性, 觉得写在这里更好一些。

如上图所示,【标题】格式为:table_级别_取Dataset中的第几张表(从1开始)_filter字段多个用XX隔开(此处不允许有下划线外其他特殊字符, 就用这个XX吧 )_名称

【说明】为可选项,若需要合计行, 则需要标识, summary或缩写s: [合计]行是模板中表格的第几行   summaryfilter或缩写sf:数据集进一步filter到summary行的条件(因为一个表格只取一个Datatable,通过一个标识指定了哪些datarow是用来作为合计的)

D.图表

同样为了方便将配置写在了【标题】,图表生成后会将名称修改过来。

配置格式为:chart_级别_取Dataset中的第几张表(从1开始)_filter字段多个用XX隔开(此处不允许有下划线外其他特殊字符, 就用这个XX吧 )_chart名称_是否将Datatable的columnName作为第一行_从datatable第几列开始(列起始为1)_截止列,

如下图所示配置即可。

E.目录

无需标识, 模板中添加目录, 当内容处理完成之后, 会根据处理后的结果动态更新目录.

四、主要代码

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Data;
  4 using System.Diagnostics;
  5 using System.IO;
  6 using System.Linq;
  7 using System.Reflection;
  8 using Excel = Microsoft.Office.Interop.Excel;
  9 using Word = Microsoft.Office.Interop.Word;
 10
 11 namespace FlyLolo.WordReport.Demo
 12 {
 13     public class WordReportHelper
 14     {
 15         private Word.Application wordApp = null;
 16         private Word.Document wordDoc = null;
 17         private DataSet dataSource = null;
 18         private object line = Word.WdUnits.wdLine;
 19         private string errorMsg = "";
 20
 21         /// <summary>
 22         /// 根据模板文件,创建数据报告
 23         /// </summary>
 24         /// <param name="templateFile">模板文件名(含路径)</param>
 25         /// <param name="newFilePath">新文件路径)</param>
 26         /// <param name="dataSource">数据源,包含多个datatable</param>
 27         /// <param name="saveFormat">新文件格式:</param>
 28         public bool CreateReport(string templateFile, DataSet dataSource, out string errorMsg, string newFilePath, ref string newFileName, int saveFormat = 16)
 29         {
 30             this.dataSource = dataSource;
 31             errorMsg = this.errorMsg;
 32             bool rtn = OpenTemplate(templateFile)
 33                 && SetContent(new WordElement(wordDoc.Range(), dataRow: dataSource.Tables[dataSource.Tables.Count - 1].Rows[0]))
 34                 && UpdateTablesOfContents()
 35                 && SaveFile(newFilePath, ref newFileName, saveFormat);
 36
 37             CloseAndClear();
 38             return rtn;
 39         }
 40
 41         /// <summary>
 42         /// 打开模板文件
 43         /// </summary>
 44         /// <param name="templateFile"></param>
 45         /// <returns></returns>
 46         private bool OpenTemplate(string templateFile)
 47         {
 48             if (!File.Exists(templateFile))
 49             {
 50                 return false;
 51             }
 52
 53             wordApp = new Word.Application();
 54             wordApp.Visible = true;//使文档可见,调试用
 55             wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
 56             object file = templateFile;
 57             wordDoc = wordApp.Documents.Open(ref file, ReadOnly: false);
 58             return true;
 59         }
 60
 61         /// <summary>
 62         /// 为指定区域写入数据
 63         /// </summary>
 64         /// <param name="element"></param>
 65         /// <returns></returns>
 66         private bool SetContent(WordElement element)
 67         {
 68             string currBookMarkName = string.Empty;
 69             string startWith = "loop_" + (element.Level + 1).ToString() + "_";
 70             foreach (Word.Bookmark item in element.Range.Bookmarks)
 71             {
 72                 currBookMarkName = item.Name;
 73
 74                 if (currBookMarkName.StartsWith(startWith) && (!currBookMarkName.Equals(element.ElementName)))
 75                 {
 76                     SetLoop(new WordElement(item.Range, currBookMarkName, element.DataRow, element.GroupBy));
 77                 }
 78
 79             }
 80
 81             SetLabel(element);
 82
 83             SetTable(element);
 84
 85             SetChart(element);
 86
 87             return true;
 88         }
 89
 90         /// <summary>
 91         /// 处理循环
 92         /// </summary>
 93         /// <param name="element"></param>
 94         /// <returns></returns>
 95         private bool SetLoop(WordElement element)
 96         {
 97             DataRow[] dataRows = dataSource.Tables[element.TableIndex].Select(element.GroupByString);
 98             int count = dataRows.Count();
 99             element.Range.Select();
100
101             //第0行作为模板  先从1开始  循环后处理0行;
102             for (int i = 0; i < count; i++)
103             {
104
105                 element.Range.Copy();  //模板loop复制
106                 wordApp.Selection.InsertParagraphAfter();//换行 不会清除选中的内容,TypeParagraph 等同于回车,若当前有选中内容会被清除. TypeParagraph 会跳到下一行,InsertParagraphAfter不会, 所以movedown一下.
107                 wordApp.Selection.MoveDown(ref line, Missing.Value, Missing.Value);
108                 wordApp.Selection.Paste(); //换行后粘贴复制内容
109                 int offset = wordApp.Selection.Range.End - element.Range.End; //计算偏移量
110
111                 //复制书签,书签名 = 模板书签名 + 复制次数
112                 foreach (Word.Bookmark subBook in element.Range.Bookmarks)
113                 {
114                     if (subBook.Name.Equals(element.ElementName))
115                     {
116                         continue;
117                     }
118
119                     wordApp.Selection.Bookmarks.Add(subBook.Name + "_" + i.ToString(), wordDoc.Range(subBook.Start + offset, subBook.End + offset));
120                 }
121
122                 SetContent(new WordElement(wordDoc.Range(wordApp.Selection.Range.End - (element.Range.End - element.Range.Start), wordApp.Selection.Range.End), element.ElementName + "_" + i.ToString(), dataRows[i], element.GroupBy));
123             }
124
125             element.Range.Delete();
126
127             return true;
128         }
129
130         /// <summary>
131         /// 处理简单Label
132         /// </summary>
133         /// <param name="element"></param>
134         /// <returns></returns>
135         private bool SetLabel(WordElement element)
136         {
137             if (element.Range.Bookmarks != null && element.Range.Bookmarks.Count > 0)
138             {
139                 string startWith = "label_" + element.Level.ToString() + "_";
140                 string bookMarkName = string.Empty;
141                 foreach (Word.Bookmark item in element.Range.Bookmarks)
142                 {
143                     bookMarkName = item.Name;
144
145                     if (bookMarkName.StartsWith(startWith))
146                     {
147                         bookMarkName = WordElement.GetName(bookMarkName);
148
149                         item.Range.Text = element.DataRow[bookMarkName].ToString();
150                     }
151                 }
152             }
153
154             return true;
155         }
156
157         /// <summary>
158         /// 填充Table
159         /// </summary>
160         /// <param name="element"></param>
161         /// <returns></returns>
162         private bool SetTable(WordElement element)
163         {
164             if (element.Range.Tables != null && element.Range.Tables.Count > 0)
165             {
166                 string startWith = "table_" + element.Level.ToString() + "_";
167                 foreach (Word.Table table in element.Range.Tables)
168                 {
169                     if (!string.IsNullOrEmpty(table.Title) && table.Title.StartsWith(startWith))
170                     {
171                         WordElement tableElement = new WordElement(null, table.Title, element.DataRow);
172
173                         TableConfig config = new TableConfig(table.Descr);
174
175                         object dataRowTemplate = table.Rows[config.DataRow];
176                         Word.Row SummaryRow = null;
177                         DataRow SummaryDataRow = null;
178                         DataTable dt = dataSource.Tables[tableElement.TableIndex];
179                         DataRow[] dataRows = dataSource.Tables[tableElement.TableIndex].Select(tableElement.GroupByString); ;
180
181                         if (config.SummaryRow > 0)
182                         {
183                             SummaryRow = table.Rows[config.SummaryRow];
184                             SummaryDataRow = dt.Select(string.IsNullOrEmpty(tableElement.GroupByString) ? config.SummaryFilter : tableElement.GroupByString + " and  " + config.SummaryFilter).FirstOrDefault();
185                         }
186
187                         foreach (DataRow row in dataRows)
188                         {
189                             if (row == SummaryDataRow)
190                             {
191                                 continue;
192                             }
193
194                             Word.Row newRow = table.Rows.Add(ref dataRowTemplate);
195                             for (int j = 0; j < table.Columns.Count; j++)
196                             {
197                                 newRow.Cells[j + 1].Range.Text = row[j].ToString(); ;
198                             }
199
200                         }
201
202                         ((Word.Row)dataRowTemplate).Delete();
203
204                         if (config.SummaryRow > 0 && SummaryDataRow != null)
205                         {
206                             for (int j = 0; j < SummaryRow.Cells.Count; j++)
207                             {
208                                 string temp = SummaryRow.Cells[j + 1].Range.Text.Trim().Replace("\r\a", "");
209
210                                 if (!string.IsNullOrEmpty(temp) && temp.Length > 2 && dt.Columns.Contains(temp.Substring(1, temp.Length - 2)))
211                                 {
212                                     SummaryRow.Cells[j + 1].Range.Text = SummaryDataRow[temp.Substring(1, temp.Length - 2)].ToString();
213                                 }
214                             }
215                         }
216
217                         table.Title = tableElement.Name;
218                     }
219
220
221                 }
222             }
223
224             return true;
225         }
226
227         /// <summary>
228         /// 处理图表
229         /// </summary>
230         /// <param name="element"></param>
231         /// <returns></returns>
232         private bool SetChart(WordElement element)
233         {
234             if (element.Range.InlineShapes != null && element.Range.InlineShapes.Count > 0)
235             {
236                 List<Word.InlineShape> chartList = element.Range.InlineShapes.Cast<Word.InlineShape>().Where(m => m.Type == Word.WdInlineShapeType.wdInlineShapeChart).ToList();
237                 string startWith = "chart_" + element.Level.ToString() + "_";
238                 foreach (Word.InlineShape item in chartList)
239                 {
240                     Word.Chart chart = item.Chart;
241                     if (!string.IsNullOrEmpty(chart.ChartTitle.Text) && chart.ChartTitle.Text.StartsWith(startWith))
242                     {
243                         WordElement chartElement = new WordElement(null, chart.ChartTitle.Text, element.DataRow);
244
245                         DataTable dataTable = dataSource.Tables[chartElement.TableIndex];
246                         DataRow[] dataRows = dataTable.Select(chartElement.GroupByString);
247
248                         int columnCount = dataTable.Columns.Count;
249                         List<int> columns = new List<int>();
250
251                         foreach (var dr in dataRows)
252                         {
253                             for (int i = chartElement.ColumnStart == -1 ? 0 : chartElement.ColumnStart - 1; i < (chartElement.ColumnEnd == -1 ? columnCount : chartElement.ColumnEnd); i++)
254                             {
255                                 if (columns.Contains(i) || dr[i] == null || string.IsNullOrEmpty(dr[i].ToString()))
256                                 {
257
258                                 }
259                                 else
260                                 {
261                                     columns.Add(i);
262                                 }
263                             }
264                         }
265                         columns.Sort();
266                         columnCount = columns.Count;
267                         int rowsCount = dataRows.Length;
268
269                         Word.ChartData chartData = chart.ChartData;
270
271                         //chartData.Activate();
272                         //此处有个比较疑惑的问题, 不执行此条,生成的报告中的图表无法再次右键编辑数据. 执行后可以, 但有两个问题就是第一会弹出Excel框, 处理完后会自动关闭. 第二部分chart的数据range设置总不对
273                         //不知道是不是版本的问题, 谁解决了分享一下,谢谢
274
275                         Excel.Workbook dataWorkbook = (Excel.Workbook)chartData.Workbook;
276                         dataWorkbook.Application.Visible = false;
277
278                         Excel.Worksheet dataSheet = (Excel.Worksheet)dataWorkbook.Worksheets[1];
279                         //设定范围
280                         string a = (chartElement.ColumnNameForHead ? rowsCount + 1 : rowsCount) + "|" + columnCount;
281                         Console.WriteLine(a);
282
283                         Excel.Range tRange = dataSheet.Range["A1", dataSheet.Cells[(chartElement.ColumnNameForHead ? rowsCount + 1 : rowsCount), columnCount]];
284                         Excel.ListObject tbl1 = dataSheet.ListObjects[1];
285                         //dataSheet.ListObjects[1].Delete(); //想过重新删除再添加  这样 原有数据清掉了, 但觉得性能应该会有所下降
286                         //Excel.ListObject tbl1 = dataSheet.ListObjects.AddEx();
287                         tbl1.Resize(tRange);
288                         for (int j = 0; j < rowsCount; j++)
289                         {
290                             DataRow row = dataRows[j];
291                             for (int k = 0; k < columnCount; k++)
292                             {
293                                 dataSheet.Cells[j + 2, k + 1].FormulaR1C1 = row[columns[k]];
294                             }
295                         }
296
297                         if (chartElement.ColumnNameForHead)
298                         {
299                             for (int k = 0; k < columns.Count; k++)
300                             {
301                                 dataSheet.Cells[1, k + 1].FormulaR1C1 = dataTable.Columns[columns[k]].ColumnName;
302                             }
303                         }
304                         chart.ChartTitle.Text = chartElement.Name;
305                         //dataSheet.Application.Quit();
306                     }
307                 }
308             }
309
310             return true;
311         }
312
313         /// <summary>
314         /// 更新目录
315         /// </summary>
316         /// <returns></returns>
317         private bool UpdateTablesOfContents()
318         {
319             foreach (Word.TableOfContents item in wordDoc.TablesOfContents)
320             {
321                 item.Update();
322             }
323
324             return true;
325         }
326
327         /// <summary>
328         /// 保存文件
329         /// </summary>
330         /// <param name="newFilePath"></param>
331         /// <param name="newFileName"></param>
332         /// <param name="saveFormat"></param>
333         /// <returns></returns>
334         private bool SaveFile(string newFilePath, ref string newFileName, int saveFormat = 16)
335         {
336             if (string.IsNullOrEmpty(newFileName))
337             {
338                 newFileName = DateTime.Now.ToString("yyyyMMddHHmmss");
339
340                 switch (saveFormat)
341                 {
342                     case 0:// Word.WdSaveFormat.wdFormatDocument
343                         newFileName += ".doc";
344                         break;
345                     case 16:// Word.WdSaveFormat.wdFormatDocumentDefault
346                         newFileName += ".docx";
347                         break;
348                     case 17:// Word.WdSaveFormat.wdFormatPDF
349                         newFileName += ".pdf";
350                         break;
351                     default:
352                         break;
353                 }
354             }
355
356             object newfile = Path.Combine(newFilePath, newFileName);
357             object wdSaveFormat = saveFormat;
358             wordDoc.SaveAs(ref newfile, ref wdSaveFormat);
359             return true;
360         }
361
362         /// <summary>
363         /// 清理
364         /// </summary>
365         private void CloseAndClear()
366         {
367             if (wordApp == null)
368             {
369                 return;
370             }
371             wordDoc.Close(Word.WdSaveOptions.wdDoNotSaveChanges);
372             wordApp.Quit(Word.WdSaveOptions.wdDoNotSaveChanges);
373             System.Runtime.InteropServices.Marshal.ReleaseComObject(wordDoc);
374             System.Runtime.InteropServices.Marshal.ReleaseComObject(wordApp);
375             wordDoc = null;
376             wordApp = null;
377             GC.Collect();
378             KillProcess("Excel", "WINWORD");
379         }
380
381         /// <summary>
382         /// 杀进程..
383         /// </summary>
384         /// <param name="processNames"></param>
385         private void KillProcess(params string[] processNames)
386         {
387             //Process myproc = new Process();
388             //得到所有打开的进程
389             try
390             {
391                 foreach (string name in processNames)
392                 {
393                     foreach (Process thisproc in Process.GetProcessesByName(name))
394                     {
395                         if (!thisproc.CloseMainWindow())
396                         {
397                             if (thisproc != null)
398                                 thisproc.Kill();
399                         }
400                     }
401                 }
402             }
403             catch (Exception)
404             {
405                 //throw Exc;
406                 // msg.Text+=  "杀死"  +  processName  +  "失败!";
407             }
408         }
409     }
410
411     /// <summary>
412     /// 封装的Word元素
413     /// </summary>
414     public class WordElement
415     {
416         public WordElement(Word.Range range, string elementName = "", DataRow dataRow = null, Dictionary<string, string> groupBy = null, int tableIndex = 0)
417         {
418             this.Range = range;
419             this.ElementName = elementName;
420             this.GroupBy = groupBy;
421             this.DataRow = dataRow;
422             if (string.IsNullOrEmpty(elementName))
423             {
424                 this.Level = 0;
425                 this.TableIndex = tableIndex;
426                 this.Name = string.Empty;
427                 this.ColumnNameForHead = false;
428             }
429             else
430             {
431                 string[] element = elementName.Split('_');
432                 this.Level = int.Parse(element[1]);
433                 this.ColumnNameForHead = false;
434                 this.ColumnStart = -1;
435                 this.ColumnEnd = -1;
436
437                 if (element[0].Equals("label"))
438                 {
439                     this.Name = element[2];
440                     this.TableIndex = 0;
441                 }
442                 else
443                 {
444                     this.Name = element[4];
445                     this.TableIndex = int.Parse(element[2]) - 1;
446
447                     if (!string.IsNullOrEmpty(element[3]))
448                     {
449                         string[] filters = element[3].Split(new string[] { "XX" }, StringSplitOptions.RemoveEmptyEntries);
450                         if (this.GroupBy == null)
451                         {
452                             this.GroupBy = new Dictionary<string, string>();
453                         }
454                         foreach (string item in filters)
455                         {
456                             if (!this.GroupBy.Keys.Contains(item))
457                             {
458                                 this.GroupBy.Add(item, dataRow[item].ToString());
459                             }
460
461                         }
462                     }
463
464                     if (element[0].Equals("chart") && element.Count() > 5)
465                     {
466                         this.ColumnNameForHead = element[5].Equals("1");
467                         this.ColumnStart = string.IsNullOrEmpty(element[6]) ? -1 : int.Parse(element[6]);
468                         this.ColumnEnd = string.IsNullOrEmpty(element[7]) ? -1 : int.Parse(element[7]);
469                     }
470                 }
471             }
472         }
473
474         public Word.Range Range { get; set; }
475         public int Level { get; set; }
476         public int TableIndex { get; set; }
477         public string ElementName { get; set; }
478
479         public DataRow DataRow { get; set; }
480         public Dictionary<string, string> GroupBy { get; set; }
481
482         public string Name { get; set; }
483
484         public bool ColumnNameForHead { get; set; }
485         public int ColumnStart { get; set; }
486         public int ColumnEnd { get; set; }
487
488         public string GroupByString
489         {
490             get
491             {
492                 if (GroupBy == null || GroupBy.Count == 0)
493                 {
494                     return string.Empty;
495                 }
496
497                 string rtn = string.Empty;
498                 foreach (string key in this.GroupBy.Keys)
499                 {
500                     rtn += "and " + key + " = '" + GroupBy[key] + "' ";
501                 }
502                 return rtn.Substring(3);
503             }
504         }
505
506         public static string GetName(string elementName)
507         {
508             string[] element = elementName.Split('_');
509
510
511             if (element[0].Equals("label"))
512             {
513                 return element[2];
514             }
515             else
516             {
517                 return element[4];
518             }
519         }
520     }
521
522     /// <summary>
523     /// Table配置项
524     /// </summary>
525     public class TableConfig
526     {
527         public TableConfig(string tableDescr = "")
528         {
529             this.DataRow = 2;
530             this.SummaryRow = -1;
531
532             if (!string.IsNullOrEmpty(tableDescr))
533             {
534                 string[] element = tableDescr.Split(',');
535                 foreach (string item in element)
536                 {
537                     if (!string.IsNullOrEmpty(item))
538                     {
539                         string[] configs = item.Split(':');
540                         if (configs.Length == 2)
541                         {
542                             switch (configs[0].ToLower())
543                             {
544                                 case "data":
545                                 case "d":
546                                     this.DataRow = int.Parse(configs[1]);
547                                     break;
548                                 case "summary":
549                                 case "s":
550                                     this.SummaryRow = int.Parse(configs[1]);
551                                     break;
552                                 case "summaryfilter":
553                                 case "sf":
554                                     this.SummaryFilter = configs[1];
555                                     break;
556                                 default:
557                                     break;
558                             }
559                         }
560                     }
561                 }
562             }
563
564         }
565         public int DataRow { get; set; }
566         public int SummaryRow { get; set; }
567         public string SummaryFilter { get; set; }
568     }
569 }

微信小程序:动画(Animation)

 

简单总结一下微信动画的实现及执行步骤。

一、实现方式

官方文档是这样说的:①创建一个动画实例 animation。②调用实例的方法来描述动画。③最后通过动画实例的 export 方法导出动画数据传递给组件的 animation 属性。

因为小程序是数据驱动的,给这句话加上数字标注分为三步:

前两步是定义一个动画并设置都要干什么,然后把这个设置好的“规则”扔给界面上的某个元素,让它按照这个规则执行。

当然如果有多个元素的animation="{{ani}}",也都会执行这个动画规则。

二、用例子说话

新建一个小程序,把没用的删掉修改一下,做个简单例子,上图

代码如下:

index.wxml,一个helloworld,一个按钮
<view class="container">
  <view class="usermotto" animation="{{ani}}">
    <text class="user-motto">{{motto}}</text>
  </view>
  <button bindtap='start'>动画</button>
</view>
index.wxss, 为了看着方便加了个边框
.usermotto {
  margin-top: 100px;
  border: solid;
}

index.js

Page({
  data: {
    motto: 'Hello World',
  },
  start:function(){
    var animation = wx.createAnimation({
      duration: 4000,
      timingFunction: 'ease',
      delay: 1000
    });
    animation.opacity(0.2).translate(100, -100).step()
    this.setData({
      ani:  animation.export()
    })
  }
})

三、相关参数及方法

简单介绍一下例子中的几个参数和方法(其他的详见官方文档):

duration: 动画持续多少毫秒
      timingFunction: “运动”的方式,例子中的 'ease'代表动画以低速开始,然后加快,在结束前变慢  
      delay: 多久后动画开始运行

opacity(0.2) 慢慢变透明

translate(100, -100) 向X轴移动100的同时向Y轴移动-100

step(): 一组动画完成,例如想让上例中的HelloWorld向右上方移动并变透明后,再次向左移动50可以继续写 animation.translateX( -50).step() , 作用就是向右上方移动和变透明是同时进行, 这两种变化完成之后才会进行向左运行的一步。

例子:Github

 
 

SignalR 设计理念(一)

实现客户端和服务器端的实时通讯.

问题阐述
  1. 客户端提供的方法不确定!
  2. 客户端的方法参数不确定!
  3. 不同的名称和参数要分别调用指定的方法!
  4. 调用客户端方法时,不忽略大小写!

例如:

public void Send(string message)
{
    Clients.All.Write(message); // Clients.All.write(message); 也可以。
}

针对以上问题,你会如何设计服务器架构?

SignalR 选用 dynamic 动态数据类型作为客户端通讯的基类。

问:

  1. 动态数据类型是如何解决客户端方法不确定的? 1
  2. 动态数据类型是如何解决客户端方法参数不确定的? 2
  3. 动态数据类型是如何区分要调用的客户端方法的? 3

举一反三:

  1. 为什么服务器端调用客户端要忽略大小写?

核心代码:

public class ClientProxy : DynamicObject
{
   [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Binder is passed in by the DLR")]
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        result = Invoke(binder.Name, args);
        return true;
    }
    /// <summary>
    /// 这里处理业务逻辑
    /// </summary>
    /// <param name="method">方法名称</param>
    /// <param name="args">参数</param>
    /// <returns></returns>
    public Task Invoke(string method, params object[] args)
    {
        return Task.Factory.StartNew(() =>
        {
            //这里处理业务逻辑。
        });
    }
}
解析:

  1. 通过binder.Name 确定客户端方法名称。

  2. 通过args 确定客户端方法参数。

  3. 通过 [^1] 和 [^2] 两点确定客户端的指定方法。

 
 
 
 
 

ASP.NET -- WebForm -- ViewState

ASP.NET -- WebForm --  ViewState

1. ViewState的作用

当 ASP .NET 中的表单被提交时,表单会随所有表单值一同重新出现。这是由于 ASP .NET 维持了您的 ViewState。

ViewState 会在页面被提交到服务器时指示其状态。通过在每张页面中的一个 <form runat="server"> 控件中放置一个隐藏域,我们就可以定义页面的状态了。

新建一个Test.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test"  %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>my Test Aspx</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Button" />
    </div>
    </form>
</body>
</html>

在浏览器--开发者工具可看到ViewState隐藏域的存在:

2. ViewState的开启和关闭

维持 ViewState 是 ASP.NET Web 表单的默认设置。

如果您不希望维持 ViewState,请在 .aspx 页面的顶部包含指令: <%@ Page EnableViewState="false" %>,或为任意控件添加属性:EnableViewState="false"。

整个页面关闭ViewState:

单个控件关闭ViewState:

把EnableViewState="false",在浏览器--开发者工具,还是可以看见隐藏域__ViewState的。

如果想彻底去掉隐藏域__ViewState,必须将runat="server"去掉,换成action  (但是这样做,会导致工具箱的控件不能用), 如下图:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>my Test Aspx</title>
</head>
<body>
    <form action="Test.aspx" method="post">
    <div>
        <input type="text" name="txtName"/>
    </div>
    </form>
</body>
</html>

浏览器开发者工具中可清楚看见,隐藏域__ViewState被去掉了

 

ASP.NET -- 一般处理程序ashx

ASP.NET  --   一般处理程序ashx

如果在一个html页面向服务器端请求数据,可用ashx作为后台页面处理数据。ashx适合用作数据后台处理,相当于WebForm中的aspx.cs文件或aspx.vb文件。

入门案例:html页面向ashx页面请求数据,ashx作为后台页面返回数据。

前端html页面:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>My Test ashx</title>
    <script type="text/javascript" src="./js/jquery-2.0.3.min.js" ></script>
    <script type="text/javascript" >
        $(function() {
            $("#btn_Test").click(function() {
                $.ajax({
                    type: "post",
                    url: "Test.ashx",
                    datatype: "text",
                    data: { "TestAction":"getBaiduUrl"},
                    success: function(data) {
                       $("#myDiv1").html(data);
                    }
                });
            });
        });
    </script>
</head>
<body>
    <button type="button" id="btn_Test">Test</button>
    <div id="myDiv1" style="width:300px;height:30px;padding: 10px;border:2px solid blue;">
    </div>
</body>
</html>

后台Test.ashx页面:

<%@ WebHandler Language="C#" Class="Test" %>

using System;
using System.Web;

public class Test : IHttpHandler {

    public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/plain";
        if (context.Request["TestAction"] == "getBaiduUrl")
        {
            context.Response.Write("百度的地址是: https://www.baidu.com");
        }
    }

    public bool IsReusable {
        get {
            return false;
        }
    }

}

运行结果:

   

常用到的一些js方法,记录一下

 

  获取字符串长度

function GetStringLength(str) {
    return str.replace(/[^\x00-\xff]/g, "00").length;
}

  通过js对html转义和反转义

function HTMLEncode(html) {
    var temp = document.createElement("div");
    (temp.textContent != null) ? (temp.textContent = html) : (temp.innerText = html);
    var output = temp.innerHTML;
    temp = null;
    return output;
}

function HTMLDecode(text) {
    var temp = document.createElement("div");
    temp.innerHTML = text;
    var output = temp.innerText || temp.textContent;
    temp = null;
    return output;
} 

一些公用的js

  1 var com = com || {};
  2 (function ($, com) {
  3     /**
  4     * 截取字符串
  5     * @param str:要截取的字符串
  6     * @param len:保留多少字符
  7     * @param symbol:超过之后字符串末端要添加的字符
  8     */
  9     com.cutStr = function (str, len, symbol) {
 10         str = str || "";
 11         if (symbol == null || symbol == undefined)
 12             symbol = "...";
 13
 14         var count = 0;
 15         var strTemp = "";
 16         for (var i = 0; i < str.length; i++) {
 17             if (/[^\x00-\xff]/g.test(str.substr(i, 1))) {
 18                 count += 2;
 19             }
 20             else {
 21                 count += 1;
 22             }
 23             if (count <= len) {
 24                 strTemp += str.substr(i, 1);
 25             }
 26             else {
 27                 return strTemp + symbol;
 28             }
 29         }
 30         return str;
 31     },
 32     /*
 33     * 将日期字符串转化为Date
 34     * (如:将"2016-12-24 20:13:14"转化为Date格式)
 35     * @param d:待转化字符串(传入的时间不能有毫秒)
 36     */
 37     com.getDate = function (d) {
 38         //部分浏览器(IE)不支持日期格式“yyyy-MM-dd hh:mm:ss”,必须将“-”转化为“/”
 39         var date = new Date(Date.parse(d.replace(/-/g, "/")));
 40         return date;
 41     },
 42     /*
 43     * 获取html代码的纯文本
 44     * @param html
 45     */
 46     com.removeHTMLTag = function (html) {
 47         html = html.replace(/<\/?[^>]*>/g, ''); //去除HTML tag
 48         html = html.replace(/[ | ]*\n/g, '\n'); //去除行尾空白
 49         //html = html.replace(/\n[\s| | ]*\r/g,'\n'); //去除多余空行
 50         html = html.replace(/&nbsp;/ig, '');//去掉&nbsp;
 51         html = html.replace(/\s/g, ''); //将空格去掉
 52         return html;
 53     },
 54     /*
 55     * 获取地址栏参数
 56     * @param 参数名
 57     */
 58     com.getQueryString = function (name) {
 59         var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
 60         var r = window.location.search.substr(1).match(reg);
 61         if (r != null) return (r[2]); return null;
 62     },
 63
 64     /**************************************************************
 65     *将金额转化为大写
 66     *   str:需要转化的金额
 67     ****************************************************************/
 68     com.convertMoney = function (n) {
 69         var fraction = ['角', '分', '毫', '厘'];
 70         var digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
 71         var unit = [['元', '万', '亿'], ['', '拾', '佰', '仟']];
 72         var cnInteger = "整"; //整数金额时后面跟的字符
 73         var cnIntLast = "元"; //整型完以后的单位
 74         var maxNum = 9999999999999.9999;
 75         var head = n < 0 ? '负' : '';
 76         //取绝对值
 77         n = Math.abs(n);
 78         if (n >= maxNum) {
 79             console.error("金额转化超出最大处理数字");
 80             return "";
 81         }
 82
 83         var IntegerNum; //金额整数部分
 84         var DecimalNum; //金额小数部分
 85         var money = n.toString();
 86         if (money.indexOf(".") == -1) {
 87             IntegerNum = money;
 88             DecimalNum = '';
 89         } else {
 90             var parts = money.split(".");
 91             IntegerNum = parts[0];
 92             DecimalNum = parts[1].substr(0, 4);
 93         }
 94
 95         var ChineseStr = "";
 96
 97         //小数部分
 98         if (DecimalNum != '') {
 99             for (i = 0; i < DecimalNum.length; i++) {
100                 var m = DecimalNum.substr(i, 1);
101                 if (m != '0') {
102                     ChineseStr += digit[Number(m)] + fraction[i];
103                 }
104             }
105         }
106
107         IntegerNum = IntegerNum * 1;
108
109         //整数部分
110         for (var i = 0; i < unit[0].length && IntegerNum > 0; i++) {
111             var p = '';
112             for (var j = 0; j < unit[1].length && IntegerNum > 0; j++) {
113                 p = digit[IntegerNum % 10] + unit[1][j] + p;
114                 IntegerNum = Math.floor(IntegerNum / 10);
115             }
116             ChineseStr = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + ChineseStr;
117         }
118
119         if (ChineseStr == '') {
120             ChineseStr += digit[0] + cnIntLast + cnInteger;
121         } else if (DecimalNum == '') {
122             ChineseStr += cnInteger;
123         }
124         ChineseStr = head + ChineseStr;
125         return ChineseStr;
126     },
127
128     /**
129     * 获取字符串长度(一个汉字占两个字符)
130     * @param str:字符串
131     */
132     com.getStringLength = function (str) {
133         return str.replace(/[^\x00-\xff]/g, "00").length;
134     }
135
136 })(jQuery, com);

CryptoJS与C#AES加解密互转

 

CryptoJS下载地址:

https://code.google.com/archive/p/crypto-js/downloads

http://download.csdn.net/detail/wz122889488/9851085

页面js引用:

    <script type="text/javascript" src="/content/plugin/CryptoJSv3.1.2/components/core-min.js"></script>
    <script type="text/javascript" src="/content/plugin/CryptoJSv3.1.2/rollups/aes.js"></script>

JS端AES加密解密:

 1     com.str = {
 2         _KEY: "12345678900000001234567890000000",//32位
 3         _IV: "1234567890000000",//16位
 4         /**************************************************************
 5         *字符串加密
 6         *   str:需要加密的字符串
 7         ****************************************************************/
 8         Encrypt: function (str) {
 9             var key = CryptoJS.enc.Utf8.parse(this._KEY);
10             var iv = CryptoJS.enc.Utf8.parse(this._IV);
11
12             var encrypted = '';
13
14             var srcs = CryptoJS.enc.Utf8.parse(str);
15             encrypted = CryptoJS.AES.encrypt(srcs, key, {
16                 iv: iv,
17                 mode: CryptoJS.mode.CBC,
18                 padding: CryptoJS.pad.Pkcs7
19             });
20
21             return encrypted.ciphertext.toString();
22         },
23
24         /**************************************************************
25         *字符串解密
26         *   str:需要解密的字符串
27         ****************************************************************/
28         Decrypt: function (str) {
29             var key = CryptoJS.enc.Utf8.parse(this._KEY);
30             var iv = CryptoJS.enc.Utf8.parse(this._IV);
31             var encryptedHexStr = CryptoJS.enc.Hex.parse(str);
32             var srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
33             var decrypt = CryptoJS.AES.decrypt(srcs, key, {
34                 iv: iv,
35                 mode: CryptoJS.mode.CBC,
36                 padding: CryptoJS.pad.Pkcs7
37             });
38             var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
39             return decryptedStr.toString();
40         }
41     }

C# AES加密解密:

const string AES_IV = "1234567890000000";//16位    

    /// <summary>
    /// AES加密算法
    /// </summary>
    /// <param name="input">明文字符串</param>
    /// <param name="key">密钥(32位)</param>
    /// <returns>字符串</returns>
    public static string EncryptByAES(string input, string key)
    {
        byte[] keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 32));
        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
        {
            aesAlg.Key = keyBytes;
            aesAlg.IV = Encoding.UTF8.GetBytes(AES_IV.Substring(0, 16));

            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        swEncrypt.Write(input);
                    }
                    byte[] bytes = msEncrypt.ToArray();
                    return ByteArrayToHexString(bytes);
                }
            }
        }
    }

    /// <summary>
    /// AES解密
    /// </summary>
    /// <param name="input">密文字节数组</param>
    /// <param name="key">密钥(32位)</param>
    /// <returns>返回解密后的字符串</returns>
    public static string DecryptByAES(string input, string key)
    {
        byte[] inputBytes = HexStringToByteArray(input);
        byte[] keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 32));
        using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
        {
            aesAlg.Key = keyBytes;
            aesAlg.IV = Encoding.UTF8.GetBytes(AES_IV.Substring(0, 16));

            ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
            using (MemoryStream msEncrypt = new MemoryStream(inputBytes))
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srEncrypt = new StreamReader(csEncrypt))
                    {
                        return srEncrypt.ReadToEnd();
                    }
                }
            }
        }
    }

    /// <summary>
    /// 将指定的16进制字符串转换为byte数组
    /// </summary>
    /// <param name="s">16进制字符串(如:“7F 2C 4A”或“7F2C4A”都可以)</param>
    /// <returns>16进制字符串对应的byte数组</returns>
    public static byte[] HexStringToByteArray(string s)
    {
        s = s.Replace(" ", "");
        byte[] buffer = new byte[s.Length / 2];
        for (int i = 0; i < s.Length; i += 2)
            buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
        return buffer;
    }

    /// <summary>
    /// 将一个byte数组转换成一个格式化的16进制字符串
    /// </summary>
    /// <param name="data">byte数组</param>
    /// <returns>格式化的16进制字符串</returns>
    public static string ByteArrayToHexString(byte[] data)
    {
        StringBuilder sb = new StringBuilder(data.Length * 3);
        foreach (byte b in data)
        {
            //16进制数字
            sb.Append(Convert.ToString(b, 16).PadLeft(2, '0'));
            //16进制数字之间以空格隔开
            //sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
        }
        return sb.ToString().ToUpper();
    }

用法:

com.str.Encrypt("2017-05")//结果:68f4a7903a9fe6085d2301ac68cc039c
com.str.Decrypt("68f4a7903a9fe6085d2301ac68cc039c")//结果:2017-05
//加密
string str1 = Encrypt.EncryptByAES("2017-05", "12345678900000001234567890000000");
//解密
string str2 = Encrypt.DecryptByAES("68f4a7903a9fe6085d2301ac68cc039c", "12345678900000001234567890000000");

注:前后台的加密Key必须一致。

.net mvc 站点自带简易SSL加密传输 Word报告自动生成(例如 导出数据库结构) 微信小程序:动画(Animation) SignalR 设计理念(一) ASP.NET -- WebForm -- ViewState ASP.NET -- 一般处理程序ashx 常用到的一些js方法,记录一下 CryptoJS与C#AES加解密互转的更多相关文章

  1. .net mvc 站点自带简易SSL加密传输

    因项目需要,传输数据需要加密,因此有了一些经验,现简易抽出来分享! 请求:前端cryptojs用rsa/aes 或 rsa/des加密,后端.net 解密返回后端.net用rsa/aes 或 rsa/ ...

  2. 微信小程序用setData修改数组或对象中的一个属性值,超好用,最简单的实现方法,不容错过!大神们 都 在 看 的方法!!!

    在page中 data: { info: [{ name: "yuki", tou: "../img/head.jpg", zGong: 130, gMoney ...

  3. 微信小程序开发系列教程三:微信小程序的调试方法

    微信小程序开发系列教程 微信小程序开发系列一:微信小程序的申请和开发环境的搭建 微信小程序开发系列二:微信小程序的视图设计 这个教程的前两篇文章,介绍了如何用下图所示的微信开发者工具自动生成一个Hel ...

  4. 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理

    [微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...

  5. 剖析简易计算器带你入门微信小程序开发

    写在前面,但是重点在后面 这是教程,也不是教程. 可以先看Demo的操作动图,看看是个什么玩意儿,GitHub地址(https://github.com/dunizb/wxapp-sCalc) 自从微 ...

  6. 微信小程序首页index.js获取不到app.js中动态设置的globalData的原因以及解决方法

    前段时间开发了一款微信小程序,运行了也几个月了,在index.js中的onLoad生命周期里获取app.js中onLaunch生命周期中在接口里动态设置的globalData一直没有问题,结果昨天就获 ...

  7. 微信小程序 引用其他js里的方法

    微信小程序中,在微信官方开发文档我们可以知道 小程序的目录结构 . 一个小程序页面由四个文件组成,一个小程序页面的四个文件具有相同路径与文件名,由此我们可知一个小程序页面对应着一个跟页面同名的js文件 ...

  8. linux下使用vsftp搭建FTP服务器:匿名登录,账号登录,SSL加密传输

    目录 一.关于FTP和VSFTP 二.ftp.sftp.vsftp.vsftpd的区别 三.项目一:搭建一台所有人都可以访问的通用FTP服务器 3.1 项目要求 3.2 项目思路分析 3.3 使用vs ...

  9. 微信小程序-简易计算器

    代码地址如下:http://www.demodashi.com/demo/14210.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.co ...

随机推荐

  1. 微信、小程序开发UI库--weui

    一.weui可以开发微信内网页.微信小程序,二者使用的UI库不一样 1. 微信内网页样式文件为 .css文件  链接地址:https://weui.io/         weui-js库:  weu ...

  2. linux文件系统命令(6)---touch和mkdir

    一.目的 本文将介绍linux下新建文件或文件夹.删除文件或文件夹命令.         touch能够新建文件,mkdir用来新建文件夹.rm用来删除文件或文件夹.         本文将选取ubu ...

  3. 解决/dev/fb0无法打开的问题

    最近要在Linux做基于frame Buffer的图形显示,不论我在独立分区的Linux FC6系统中,还是在装有Red hat9的VPC中,都无法打开/dev/fb0.从网上找了很多资料,都没能解决 ...

  4. java 日期工具类

    import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; imp ...

  5. UltraEdit字体设置(fontlink大法)

    在网上游荡很久,查阅诸多资料,终于为UltraEdit选定了一套我喜欢的字体方案.这套字体方案是:英文字体使用Consolas,中文字体使用微软雅黑. 虽然说起来好像很清楚,但是因为在UltraEdi ...

  6. EatCam Webcam Recorder Pro

    EatCam Webcam Recorder Pro Webcam Recorder records webcams to AVI, FLV, WMV files and watch them whe ...

  7. FIS常用命令

    命令 用途 简写 fis --version 查看版本 fis -v fis install 安装   fis release 发布项目   fis server start 启动一个服务器用于预览项 ...

  8. poj3126--Prime Path(广搜)

    Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11751   Accepted: 6673 Descr ...

  9. Linux进程间通信—信号量

    二.信号量(semophore) 信号量是一种计数器,可以控制进程间多个线程或者多个进程对资源的同步访问,它常实现为一种锁机制.实质上,信号量是一个被保护的变量,并且只能通过初始化和两个标准的原子操作 ...

  10. 【USACO1.2_2】★Transformations 方块转换

    一块N x N(1<=N<=10)正方形的黑白瓦片的图案要被转换成新的正方形图案.写一个程序来找出将原始图案依照下面列转换方法转换成新图案的最小方式: 1:转90度:图案按顺时针转90度. ...