C#实现多级子目录Zip压缩解压实例
参考
https://blog.csdn.net/lki_suidongdong/article/details/20942977
重点:
实现多级子目录的压缩,类似winrar,可以选择是否排除基准目录
1
public
void ZipDirectoryTest()
2
{
3
string path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), DateTime.Now.Ticks.ToString());
4
foreach (string sub in
new
string[] { "bin", "release", "test", "test\\bin", "" })
5
{
6
string subPath = System.IO.Path.Combine(path, sub);
7
if (!System.IO.Directory.Exists(subPath))
8
System.IO.Directory.CreateDirectory(subPath);
9 System.IO.File.WriteAllText(System.IO.Path.Combine(subPath, "1.cs"), "");
10 System.IO.File.WriteAllText(System.IO.Path.Combine(subPath, "1.txt"), "");
11 System.IO.File.WriteAllText(System.IO.Path.Combine(subPath, "1.html"), "");
12 System.IO.File.WriteAllText(System.IO.Path.Combine(subPath, "1.bin"), "");
13
14
}
15
Console.WriteLine(path);
16
17
new ZipHelper().ZipDirectory(path, "e:\\temp\\tt.zip",false);
18 ZipHelper.UnZip("e:\\temp\\tt.zip", "e:\\temp\\tt2");
19
//System.IO.Directory.Delete(path, true);
20
//Q.Helper.FileHelper.SelectFile(path);
21 }
代码
1
using System;
2
3
using System.Collections.Generic;
4
5
using System.Linq;
6
7
using System.Text;
8
9
using System.IO;
10
11
using ICSharpCode.SharpZipLib;
12
13
using ICSharpCode.SharpZipLib.Zip;
14
15
#if NETSTANDARD2_0
16
17
using ICSharpCode.SharpZipLib.Checksum;
18
19
#else
20
21
using ICSharpCode.SharpZipLib.Checksums;
22
23
#endif
24
25
26
27
namespace Q.Helper.Zip
28
29
{
30
31
32
33
///
<summary>
34
35
/// 适用与ZIP压缩
36
37
///
</summary>
38
39
public
class ZipHelper
40
41
{
42
43
public
int Level
44
45
{
46
47
get; set;
48
49
}
50
51
#region 压缩
52
53
54
55
///
<summary>
56
57
/// 递归压缩文件夹的内部方法(排除相对路径)
58
59
///
</summary>
60
61
///
<param name="folderToZip">要压缩的文件夹路径</param>
62
63
///
<param name="zipStream">压缩输出流</param>
64
65
///
<param name="parentFolderName">此文件夹的上级文件夹</param>
66
67
///
<param name="includeFloderName">是否包含目录名</param>
68
69
///
<returns></returns>
70
71
private
bool ZipDirectory(string folderToZip, ZipOutputStream zipStream, string parentFolderName, bool createBaseFolder = true)
72
73
{
74
75 folderToZip = folderToZip.Replace("\\", "/");
76
77
bool result = true;
78
79
string[] folders, files;
80
81 ZipEntry ent = null;
82
83 FileStream fs = null;
84
85 Crc32 crc = new Crc32();
86
87
88
89
try
90
91
{
92
93
string entPath = Path.Combine(parentFolderName, Path.GetFileName(folderToZip) + "/").Replace("\\", "/");
94
95
if (!createBaseFolder)
96
97 entPath = entPath.Substring(entPath.IndexOf("/") + 1);
98
99
if (!string.IsNullOrEmpty(entPath))
100
101
{
102
103 ent = new ZipEntry(entPath);
104
105
Console.WriteLine(entPath);
106
107
zipStream.PutNextEntry(ent);
108
109
zipStream.Flush();
110
111
}
112
113 files = Directory.GetFiles(folderToZip);
114
115
foreach (string file in files)
116
117
{
118
119 fs = File.OpenRead(file);
120
121
122
123
byte[] buffer = new
byte[fs.Length];
124
125 fs.Read(buffer, 0, buffer.Length);
126
127 entPath = Path.Combine(parentFolderName, Path.GetFileName(folderToZip) + "/" + Path.GetFileName(file)).Replace("\\", "/");
128
129
if (!createBaseFolder)
130
131 entPath = entPath.Substring(entPath.IndexOf("/") + 1);
132
133
Console.WriteLine(entPath);
134
135 ent = new ZipEntry(entPath);
136
137 ent.DateTime = DateTime.Now;
138
139 ent.Size = fs.Length;
140
141
142
143
fs.Close();
144
145
146
147
crc.Reset();
148
149
crc.Update(buffer);
150
151
152
153 ent.Crc = crc.Value;
154
155
zipStream.PutNextEntry(ent);
156
157 zipStream.Write(buffer, 0, buffer.Length);
158
159
}
160
161
162
163
}
164
165
catch (Exception ex)
166
167
{
168
169 result = false;
170
171
throw ex;
172
173
}
174
175
finally
176
177
{
178
179
if (fs != null)
180
181
{
182
183
fs.Close();
184
185
fs.Dispose();
186
187
}
188
189
if (ent != null)
190
191
{
192
193 ent = null;
194
195
}
196
197
GC.Collect();
198
199 GC.Collect(1);
200
201
}
202
203
204
205 folders = Directory.GetDirectories(folderToZip);
206
207
//多级递归时需要记住相对目录
208
209
foreach (string folder in folders)
210
211
{
212
213
if (!ZipDirectory(folder, zipStream, Path.Combine(parentFolderName, Path.GetFileName(folderToZip)), createBaseFolder))
214
215
return
false;
216
217
}
218
219
return result;
220
221
}
222
223
224
225
///
<summary>
226
227
/// 压缩文件夹
228
229
///
</summary>
230
231
///
<param name="folderToZip">要压缩的文件夹路径</param>
232
233
///
<param name="zipedFile">压缩文件完整路径</param>
234
235
///
<param name="password">密码</param>
236
237
///
<returns>是否压缩成功</returns>
238
239
public
bool ZipDirectory(string folderToZip, string zipedFile, string password, bool includeFloderName = true)
240
241
{
242
243
bool result = false;
244
245
if (!Directory.Exists(folderToZip))
246
247
return result;
248
249
250
251 ZipOutputStream zipStream = new ZipOutputStream(File.Create(zipedFile));
252
253
zipStream.SetLevel(Level);
254
255
if (!string.IsNullOrEmpty(password)) zipStream.Password = password;
256
257
258
259 result = ZipDirectory(folderToZip, zipStream, "", includeFloderName);
260
261
262
263
zipStream.Finish();
264
265
zipStream.Close();
266
267
268
269
return result;
270
271
}
272
273
274
275
///
<summary>
276
277
/// 压缩文件夹
278
279
///
</summary>
280
281
///
<param name="folderToZip">要压缩的文件夹路径</param>
282
283
///
<param name="zipedFile">压缩文件完整路径</param>
284
285
///
<returns>是否压缩成功</returns>
286
287
public
bool ZipDirectory(string folderToZip, string zipedFile, bool includeFloderName = true)
288
289
{
290
291
bool result = ZipDirectory(folderToZip, zipedFile, "", includeFloderName);
292
293
return result;
294
295
}
296
297
298
299
///
<summary>
300
301
/// 压缩文件
302
303
///
</summary>
304
305
///
<param name="fileToZip">要压缩的文件全名</param>
306
307
///
<param name="zipedFile">压缩后的文件名</param>
308
309
///
<param name="password">密码</param>
310
311
///
<returns>压缩结果</returns>
312
313
public
bool ZipFile(string fileToZip, string zipedFile, string password)
314
315
{
316
317
bool result = true;
318
319 ZipOutputStream zipStream = null;
320
321 FileStream fs = null;
322
323 ZipEntry ent = null;
324
325
326
327
if (!File.Exists(fileToZip))
328
329
return
false;
330
331
332
333
try
334
335
{
336
337 fs = File.OpenRead(fileToZip);
338
339
byte[] buffer = new
byte[fs.Length];
340
341 fs.Read(buffer, 0, buffer.Length);
342
343
fs.Close();
344
345
346
347 fs = File.Create(zipedFile);
348
349 zipStream = new ZipOutputStream(fs);
350
351
if (!string.IsNullOrEmpty(password)) zipStream.Password = password;
352
353 ent = new ZipEntry(Path.GetFileName(fileToZip));
354
355
zipStream.PutNextEntry(ent);
356
357
zipStream.SetLevel(Level);
358
359
360
361 zipStream.Write(buffer, 0, buffer.Length);
362
363
364
365
}
366
367
catch
368
369
{
370
371 result = false;
372
373
}
374
375
finally
376
377
{
378
379
if (zipStream != null)
380
381
{
382
383
zipStream.Finish();
384
385
zipStream.Close();
386
387
}
388
389
if (ent != null)
390
391
{
392
393 ent = null;
394
395
}
396
397
if (fs != null)
398
399
{
400
401
fs.Close();
402
403
fs.Dispose();
404
405
}
406
407
}
408
409
GC.Collect();
410
411 GC.Collect(1);
412
413
414
415
return result;
416
417
}
418
419
420
421
///
<summary>
422
423
/// 压缩文件
424
425
///
</summary>
426
427
///
<param name="fileToZip">要压缩的文件全名</param>
428
429
///
<param name="zipedFile">压缩后的文件名</param>
430
431
///
<returns>压缩结果</returns>
432
433
public
bool ZipFile(string fileToZip, string zipedFile)
434
435
{
436
437
bool result = ZipFile(fileToZip, zipedFile, null);
438
439
return result;
440
441
}
442
443
444
445
///
<summary>
446
447
/// 压缩文件或文件夹
448
449
///
</summary>
450
451
///
<param name="fileToZip">要压缩的路径</param>
452
453
///
<param name="zipedFile">压缩后的文件名</param>
454
455
///
<param name="password">密码</param>
456
457
///
<returns>压缩结果</returns>
458
459
public
bool Zip(string fileToZip, string zipedFile, string password)
460
461
{
462
463
bool result = false;
464
465
if (Directory.Exists(fileToZip))
466
467 result = ZipDirectory(fileToZip, zipedFile, password);
468
469
else
if (File.Exists(fileToZip))
470
471 result = ZipFile(fileToZip, zipedFile, password);
472
473
474
475
return result;
476
477
}
478
479
480
481
///
<summary>
482
483
/// 压缩文件或文件夹
484
485
///
</summary>
486
487
///
<param name="fileToZip">要压缩的路径</param>
488
489
///
<param name="zipedFile">压缩后的文件名</param>
490
491
///
<returns>压缩结果</returns>
492
493
public
bool Zip(string fileToZip, string zipedFile)
494
495
{
496
497
bool result = Zip(fileToZip, zipedFile, null);
498
499
return result;
500
501
502
503
}
504
505
506
507
#endregion
508
509
510
511
#region 解压
512
513
514
515
///
<summary>
516
517
/// 解压功能(解压压缩文件到指定目录)
518
519
///
</summary>
520
521
///
<param name="fileToUnZip">待解压的文件</param>
522
523
///
<param name="zipedFolder">指定解压目标目录</param>
524
525
///
<param name="password">密码</param>
526
527
///
<returns>解压结果</returns>
528
529
public
static
bool UnZip(string fileToUnZip, string zipedFolder, string password)
530
531
{
532
533
bool result = true;
534
535
536
537 ZipInputStream zipStream = null;
538
539 ZipEntry ent = null;
540
541
string fileName;
542
543
544
545
if (!File.Exists(fileToUnZip))
546
547
return
false;
548
549
550
551
if (!Directory.Exists(zipedFolder))
552
553
Directory.CreateDirectory(zipedFolder);
554
555
556
557
try
558
559
{
560
561 zipStream = new ZipInputStream(File.OpenRead(fileToUnZip));
562
563
if (!string.IsNullOrEmpty(password)) zipStream.Password = password;
564
565
while ((ent = zipStream.GetNextEntry()) != null)
566
567
{
568
569
if (!string.IsNullOrEmpty(ent.Name))
570
571
{
572
573 fileName = Path.Combine(zipedFolder, ent.Name);
574
575 fileName = fileName.Replace('/', '\\');//change by Mr.HopeGi
576
577
578
579
if (fileName.EndsWith("\\"))
580
581
{
582
583
Directory.CreateDirectory(fileName);
584
585
continue;
586
587
}
588
589
using (FileStream fs = File.Create(fileName))
590
591
{
592
593
int size = 2048;
594
595
byte[] data = new
byte[size];
596
597
while (true)
598
599
{
600
601
602
603 size = zipStream.Read(data, 0, data.Length);
604
605
if (size > 0)
606
607 fs.Write(data, 0, data.Length);
608
609
else
610
611
break;
612
613
}
614
615
fs.Flush();
616
617
618
619
fs.Close();
620
621
new FileInfo(fileName).LastWriteTime = ent.DateTime;
622
623
}
624
625
626
627
}
628
629
}
630
631
}
632
633
catch
634
635
{
636
637 result = false;
638
639
}
640
641
finally
642
643
{
644
645
646
647
if (zipStream != null)
648
649
{
650
651
zipStream.Close();
652
653
zipStream.Dispose();
654
655
}
656
657
if (ent != null)
658
659
{
660
661 ent = null;
662
663
}
664
665
GC.Collect();
666
667 GC.Collect(1);
668
669
}
670
671
return result;
672
673
}
674
675
676
677
///
<summary>
678
679
/// 解压功能(解压压缩文件到指定目录)
680
681
///
</summary>
682
683
///
<param name="fileToUnZip">待解压的文件</param>
684
685
///
<param name="zipedFolder">指定解压目标目录</param>
686
687
///
<returns>解压结果</returns>
688
689
public
static
bool UnZip(string fileToUnZip, string zipedFolder)
690
691
{
692
693
bool result = UnZip(fileToUnZip, zipedFolder, null);
694
695
return result;
696
697
}
698
699
700
701
#endregion
702
703
}
704
705 }
NET4.6下的UTC时间转换
int UTCSecond = (int)((DateTimeOffset)DateTime.SpecifyKind(DateTime.Now,DateTimeKind.Local)).ToUnixTimeSeconds(); DateTime time = DateTimeOffset.FromUnixTimeSeconds(UTCSecond).DateTime; Console.WriteLine("当前utc:{0},秒数:{1},换算时间:{2}", DateTimeOffset.Now, UTCSecond, time.ToString("F")); UTCSecond = Q.Helper.TimeHelper.ToUTCSecond(DateTime.Now); time = DateTimeOffset.FromUnixTimeSeconds(UTCSecond).DateTime; Console.WriteLine("当前utc:{0},秒数:{1},换算时间:{2}", DateTimeOffset.Now, UTCSecond, time.ToString("F")); Console.Read(); |
QCOMMON请使用NUGET包管理器搜索安装 QCommon
基本原理如下
/// <summary> /// UTC时间 /// </summary> static readonly DateTime UTC = TimeZoneInfo.ConvertTimeToUtc(new DateTime(1970, 1, 1), TimeZoneInfo.Utc); /// <summary> /// 时间转UTC秒 /// </summary> /// <param name="dateTime">时间(当前时区)</param> /// <returns>UTC秒</returns> public static int ToUTCSecond(this DateTime dateTime) { return (int)dateTime.ToUniversalTime().Subtract(UTC).TotalSeconds; } /// <summary> /// UTC秒转当地时间 /// </summary> /// <param name="second">秒数</param> /// <returns>当时时间</returns> public static DateTime ToDateTime(this int second) { return UTC.AddSeconds(second).ToLocalTime(); } |
[译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了
[译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了
本文首发自:博客园
文章地址: https://www.cnblogs.com/yilezhu/p/9276565.html
园子里关于ASP.NET Core Web API的教程很多,但大多都是使用EF+Mysql或者EF+MSSQL的文章。甚至关于ASP.NET Core Web API中使用Dapper+Mysql组合的文章都很少,更别提Oracel+Dapper组合的文章了,那么今天就带着大家一起翻译一篇国外大牛写的关于ASP.NET Core Web API 开发中使用Oracle+Dapper的组合的文章吧。
注:虽然本文内容是翻译,但是楼主刚在2.1环境是使用成功,中间也没有任何阻碍,只是鉴于本人电脑配置太差无法安装Oracle数据库,所以无法进行演示,再者是表示对原作者的尊重,所以在这里只是对原作内容进行翻译然后加上自己的理解稍作改动。应该能对大家使用Oracle+Dapper组合开发ASP.NET Core Web API 有所帮助。
本文的重点是介绍如何使用Dapper ORM+Oracle数据库的组合来创建ASP.NET Core Web API。首先,在这里,我们不使用SQL ,因为互联网上已有很多文章都是使用SQL Server进行演示的。所以,我想写一篇使用Oracle作为数据库的文章。为了降低数据库访问逻辑的复杂性,我们使用Dapper ORM。那么,让我们赶紧开始实战演练吧。
创建一个ASP.NET Core Web API 项目
如果要创建一个新的ASP.NET Core Web API项目的话,只需要打开Visual Studio 2017版本15.3及以上,然后按照以下步骤操作。
- 打开文件菜单,点击新建>>项目
- 在新打开的新建项目窗口,首先你需要选择 .NET Framework 4.6及以上版本,然后在左侧面板选择C# ,然后选择 .NET Core
- 在右侧面板中选择“.NET Core Web 应用程序” 并且选择项目位置,最后点击“确定”
-
在下一个窗口,在众多模板中选择Web API模板
写如何新建ASP.NET Core Web API 的这些步骤的时候我都嫌累,我想大家应该都知道怎么创建吧!就不上图片了。
设置Oracle表和存储过程
首先要为演示创建数据库以及表,我们这里使用Oracle Developer Tools。因为它非常小巧灵活,可以帮助我们顺利的处理Oracle数据库。
Oracle SQL Developer是一个免费的集成开发环境,可简化传统和云部署中Oracle数据库的开发和管理。SQL Developer提供完整的PL / SQL应用程序端到端开发,运行查询和脚本的工作表,用于管理数据库的DBA控制台,报告界面,完整的数据建模解决方案以及用于迁移第三方数据到Oracle的平台。
创建一个名为“TEST_DB”的数据库名称,并在其中创建一个表名为“EMPLOYEE”。您可以使用以下语法在“TEST_DB”数据库中创建表。
CREATE TABLE "TEST_DB"."EMPLOYEE"
(
"ID" NUMBER(10,0) GENERATED BY DEFAULT ON NULL AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 100 CACHE 20 NOORDER NOCYCLE ,
"NAME" VARCHAR2(255 BYTE),
"SALARY" NUMBER(10,0),
"ADDRESS" VARCHAR2(500 BYTE)
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "TEST_DATA" ;
我们需要在表中添加一些虚拟数据,以便我们可以直接从PostMan获取数据。所以,我们在这里添加四条记录如下。
Insert into TEST_DB.EMPLOYEE (ID,NAME,SALARY,ADDRESS) values (100,'Mukesh',20000,'India');
Insert into TEST_DB.EMPLOYEE (ID,NAME,SALARY,ADDRESS) values (101,'Rion',28000,'US');
Insert into TEST_DB.EMPLOYEE (ID,NAME,SALARY,ADDRESS) values (102,'Mahesh',10000,'India');
Insert into TEST_DB.EMPLOYEE (ID,NAME,SALARY,ADDRESS) values (103,'Banky',20000,'India');
现在我们来创建一个存储过程,用来获取员工记录列表。这里我们使用Cursor返回数据列表作为输出参数。
CREATE OR REPLACE PROCEDURE "TEST_DB"."USP_GETEMPLOYEES" (
EMPCURSOR OUT SYS_REFCURSOR
)
AS
Begin
Open EMPCURSOR For
SELECT ID, NAME, SALARY,ADDRESS FROM Employee;
End;
下面我们再创建一个存储过程,它根据员工ID获取员工的个人记录
CREATE OR REPLACE PROCEDURE "TEST_DB"."USP_GETEMPLOYEEDETAILS"
(
EMP_ID IN INT,
EMP_DETAIL_CURSOR OUT SYS_REFCURSOR
) AS
BEGIN
OPEN EMP_DETAIL_CURSOR FOR
SELECT ID, NAME, SALARY,ADDRESS FROM Employee WHERE ID = EMP_ID;
END;
安装Dapper ORM
从“工具”菜单的“Nuget包管理器”中打开“包管理器控制台”,然后输入以下命令并按Enter键以安装dapper及其依赖项(如果有)
Install-Package Dapper -Version 1.50.5
当然还有另一个安装方式,具体可以看 [ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了][http://www.cnblogs.com/yilezhu/p/9241261.html] 中关于安装Swashbuckle.AspNetCore的步骤
安装完成后,你可以查看下项目大的引用中,是否有“Dapper”的引用,如果有的话表示安装正确
为项目安装Oracle Manage Data Access
我们在Asp.Net Core Web API应用程序中使用Oracle,需要从Core应用程序访问Oracle数据库。要将Oracle数据库与.Net Core应用程序一起使用,我们有Oracle库,它将帮助我们管理数据库访问的逻辑。因此,我们必须安装以下bata的软件包。
Install-Package Oracle.ManagedDataAccess.Core -Version 2.12.0-beta2
添加 Oracle 数据库连接
现在我们已准备好与数据库相关的所有内容,如数据库,表和SP等。要从Web API访问数据库,我们必须像往常一样在“appsettings.json”文件中创建连接字符串。
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
},
"ConnectionStrings": {
"EmployeeConnection": "data source=mukesh:1531;password=**********;user id=mukesh;Incr Pool Size=5;Decr Pool Size=2;"
}
}
创建一个仓储
为了保持关注点的分离,我们在这里使用Repository。在Web API项目中创建一个新文件夹作为“仓储库”,并创建一个“IEmployeeRepository”接口和一个它的实现类“EmployeeRepository”,它将实现到IEmployeeRepository。
namespace Core2API.Repositories
{
public interface IEmployeeRepository
{
object GetEmployeeList();
object GetEmployeeDetails(int empId);
}
}
以下是实现了IEmployeeRepository的EmployeeRepository类。它需要访问配置中的数据库连接串,因此我们在构造函数中注入IConfiguration。所以,我们已经准备好使用配置对象了。除此之外,我们还有GetConnection()方法,该方法将从appsettings.json获取连接字符串,并将其提供给OracleConnection以创建连接并最终返回连接。我们已经实现了“IEmployeeRepository”,它有两个方法,如GetEmployeeDetails和GetEmployeeList。
using Core2API.Oracle;
using Dapper;
using Microsoft.Extensions.Configuration;
using Oracle.ManagedDataAccess.Client;
using System;
using System.Data;
namespace Core2API.Repositories
{
public class EmployeeRepository : IEmployeeRepository
{
IConfiguration configuration;
public EmployeeRepository(IConfiguration _configuration)
{
configuration = _configuration;
}
public object GetEmployeeDetails(int empId)
{
object result = null;
try
{
var dyParam = new OracleDynamicParameters();
dyParam.Add("EMP_ID", OracleDbType.Int32, ParameterDirection.Input, empId);
dyParam.Add("EMP_DETAIL_CURSOR", OracleDbType.RefCursor, ParameterDirection.Output);
var conn = this.GetConnection();
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
if (conn.State == ConnectionState.Open)
{
var query = "USP_GETEMPLOYEEDETAILS";
result = SqlMapper.Query(conn, query, param: dyParam, commandType: CommandType.StoredProcedure);
}
}
catch (Exception ex)
{
throw ex;
}
return result;
}
public object GetEmployeeList()
{
object result = null;
try
{
var dyParam = new OracleDynamicParameters();
dyParam.Add("EMPCURSOR", OracleDbType.RefCursor, ParameterDirection.Output);
var conn = this.GetConnection();
if(conn.State == ConnectionState.Closed)
{
conn.Open();
}
if (conn.State == ConnectionState.Open)
{
var query = "USP_GETEMPLOYEES";
result = SqlMapper.Query(conn, query, param: dyParam, commandType: CommandType.StoredProcedure);
}
}
catch (Exception ex)
{
throw ex;
}
return result;
}
public IDbConnection GetConnection()
{
var connectionString = configuration.GetSection("ConnectionStrings").GetSection("EmployeeConnection").Value;
var conn = new OracleConnection(connectionString);
return conn;
}
}
}
public IDbConnection GetConnection()
{
var connectionString = configuration.GetSection("ConnectionStrings").GetSection("EmployeeConnection").Value;
var conn = new OracleConnection(connectionString);
return conn;
}
为了在.Net Core中使用Oracle的数据类型,我们使用的是OracleDyamicParameters类,它将提供管理Oracle参数行为的一系列方法。
using Dapper;
using Oracle.ManagedDataAccess.Client;
using System.Collections.Generic;
using System.Data;
namespace Core2API.Oracle
{
public class OracleDynamicParameters : SqlMapper.IDynamicParameters
{
private readonly DynamicParameters dynamicParameters = new DynamicParameters();
private readonly List<OracleParameter> oracleParameters = new List<OracleParameter>();
public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction, object value = null, int? size = null)
{
OracleParameter oracleParameter;
if (size.HasValue)
{
oracleParameter = new OracleParameter(name, oracleDbType, size.Value, value, direction);
}
else
{
oracleParameter = new OracleParameter(name, oracleDbType, value, direction);
}
oracleParameters.Add(oracleParameter);
}
public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction)
{
var oracleParameter = new OracleParameter(name, oracleDbType, direction);
oracleParameters.Add(oracleParameter);
}
public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
((SqlMapper.IDynamicParameters)dynamicParameters).AddParameters(command, identity);
var oracleCommand = command as OracleCommand;
if (oracleCommand != null)
{
oracleCommand.Parameters.AddRange(oracleParameters.ToArray());
}
}
}
}
在Startup.cs中配置依赖
如果要在控制器或仓储类中使用依赖项的话,我们必须配置或者说在Startup类的ConfigureServices方法中为我们的接口注册我们的依赖项类。 (翻译的好拗口,楼主四级没过,希望不被喷)
using Core2API.Repositories;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Core2API
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IEmployeeRepository, EmployeeRepository>();
services.AddSingleton<IConfiguration>(Configuration);
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
}
添加 EmployeeController 控制器
现在是时候在EmployeeControler中创建API调用了。首先,我们在构造函数中添加了IEmployeeRepository以使用依赖项。其次,我们必须为两个方法创建带有Route属性的API调用。
using Core2API.Repositories;
using Microsoft.AspNetCore.Mvc;
namespace CoreAPI.Controllers
{
[Produces("application/json")]
public class EmployeeController : Controller
{
IEmployeeRepository employeeRepository;
public EmployeeController(IEmployeeRepository _employeeRepository)
{
employeeRepository = _employeeRepository;
}
[Route("api/GetEmployeeList")]
public ActionResult GetEmployeeList()
{
var result = employeeRepository.GetEmployeeList();
if (result == null)
{
return NotFound();
}
return Ok(result);
}
[Route("api/GetEmployeeDetails/{empId}")]
public ActionResult GetEmployeeDetails(int empId)
{
var result = employeeRepository.GetEmployeeDetails(empId);
if (result == null)
{
return NotFound();
}
return Ok(result);
}
}
}
现在我们已准备就绪,就像存储库已准备好,与Oracle数据库的连接已准备就绪,最后,API调用也在控制器内部就绪。因此,是时候在PostMan中运行API来查看结果了。只需按F5即可运行Web API然后打开PostMan进行测试。
要在PostMan中进行测试,首先选择“Get”作为方法,并提供URL以获取员工记录列表,然后单击“发送”按钮,该按钮将向我们的API发出请求并使用我们文章开始时创建的数据库脚本来获取我们在此处添加的员工列表数据。
要获取单个员工记录,只需传递以下URL,如图中所示。您可以在此处看到,我们希望查看员工ID 103的记录。发送请求后,您可以看到如下所示的输出。
最后
所以,今天,我们已经学会了如何创建ASP.NET Core Web API项目并使用Dapper与Oracle数据库一起使用。
我希望这篇文章能对你有所帮助。请使用评论来进行反馈,这有助于我提高自己的下一篇文章。如果您有任何疑问,请在评论部分发表你的疑问,如果您喜欢这篇文章,请与您的朋友分享。并记得点下推荐哦!
原文地址:https://www.c-sharpcorner.com/article/asp-net-core-web-api-with-oracle-database-and-dapper/
翻译人:依乐祝
总结
今天主要是翻译了一篇国外的使用Dapper以及Oracle的组合来开发asp.net core web api的教程!目的就是填补园子里使用Dapper以及Oracle的组合来开发asp.net core web api的空白!还有就是最近连续出差都没有更新文章了!接下来我会为大家介绍更多asp.net core 微服务相关的技术,希望大家持续关注!如果感觉博主写的还不错的话希望给个推荐!谢谢!
asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程
最近在学习张善友老师的NanoFabric 框架的时了解到Exceptionless : https://exceptionless.com/ !因此学习了一下这个开源框架!下面对Exceptionless的学习做下笔记!
Exceptionless是什么?能做什么呢?
“Exceptionless”这个词的定义是:没有异常。Exceptionless可以为您的ASP.NET、Web API、WebFrm、WPF、控制台和MVC应用程序提供实时错误、特性和日志报告。它将收集的信息组织成简单的可操作的数据,这些数据将帮助你很方便的查看异常信息。还有最重要的是,它是开源的!
Exceptionless的使用方式有哪些?
1.官网创建帐号,并新建应用程序以及项目,然后生成apikey(数据存储在Exceptionless)
2.自己搭建Exceptionless的环境,部署在本地(数据存储在本地)
Exceptionless的运行环境有哪些要求?需要安装哪些软件,进行什么配置呢?
- .NET 4.6.1 (安装了.net core 或者vs2017的话环境应该都没问题,不需要额外安装)
- Java JDK 1.8+(如果使用windows系统的话需要配置环境变量,这个使用过java的人应该都知道吧!相信对于你来说应该不是难事).下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
- IIS Express 8+(win 7以上环境应该都没问题,不需要额外安装)
- PowerShell 3+(win 7以上环境应该都没问题,不需要额外安装)
- 这里分win7(管理员身份运行cmd ,然后复制下面这条命令,按回车就行了
powershell Set-ExecutionPolicy Unrestricted
) 以及 win10(管理员身份运行powershell,然后执行powershell Set-ExecutionPolicy Unrestricted
) - Elasticsearch 5.6 官方推荐这个版本,(当然你也可以不进行安装,因为后面会教你如何自动安装这个软件)需要在历史版本中找 ,下载地址:https://www.elastic.co/downloads/past-releases
Exceptionless下载以及配置
1.打包下载地址:https://github.com/exceptionless/Exceptionless/releases 如下图所示进行下载就可以了!,别看只有15M有的人下载可能需要半个小时,别问为什么,因为~~~~~
2.下载完成之后,右键解压
3.看到如下的文件目录结构,有几点需要说明,如果你比较懒,嫌部署到iis比较麻烦,安装Elasticsearch也比较麻烦,那么,你可以双击“Start.bat”这个脚本,它会自动帮你安装Elasticsearch,以及(当然,生产环境,还是建议自己搭建Elasticsearch的好)
4.如果出现下图所示,那么你就耐心的等等就行了,运行结束后会自动为您打开Exceptionless的管理页面
,如果不幸,cmd里面出现红色字体,而且一闪就自动退出的话,那就执行下powershell Set-ExecutionPolicy Unrestricted 这个命令,然后再双击“Start.bat”这个脚本运行吧!
- 这里分win7(管理员身份运行cmd ,然后复制下面这条命令,按回车就行了
powershell Set-ExecutionPolicy Unrestricted
) 以及 win10(管理员身份运行powershell,然后执行powershell Set-ExecutionPolicy Unrestricted
)
5.如果全部安装成功后,会自动为你打开几个页面。还是先来看下目录结构吧,如下图所示,默认安装Elasticsearch是5.5.2 同时安装了kibana版本也是5.5.2
6.打开的几个页面如下图所示,然后在Exceptionless的页面,点击注册按钮注册一个账号,然后进行登录
7.注册成功后,进入如下的界面,在两个文本框输入,组织机构名称以及项目名称,用来对我们的项目的异常进行分类吧
8.下面进入项目类型配置界面,在1.select your project type下拉框选择asp.net core
9.出现下面的界面,说明配置完成,并且给出使用说明。到此Exceptionless的安装配置已经完成。
接下来我们通过一个实例项目进行使用说明吧
1.新建一个 netcore api项目,这一步应该难不倒你吧,我就不上图了。
2.在程序包管理器中,选中你的项目,然后输入“ Install-Package Exceptionless.AspNetCore”安装nuget包吧,当然也可以通过其他方式安装,就不介绍了
3.在startup.cs中添加 引用
1
|
using Exceptionless;
|
然后在Configure方法中添加Exceptionless管道信息
1
2
3
|
ExceptionlessClient.Default.Configuration.ApiKey = Configuration.GetSection( "Exceptionless:ApiKey" ).Value;
ExceptionlessClient.Default.Configuration.ServerUrl = Configuration.GetSection( "Exceptionless:ServerUrl" ).Value;
app.UseExceptionless();
|
然后在appsettings.json中添加apikey以及serverurl的配置
1
2
3
4
|
"Exceptionless" : {
"ApiKey" : "OvzcKg8V7bPcWU8yAYBVe6uCEKIAQm3xfEzW5yxp" ,
"ServerUrl" : "http://localhost:50000"
}
|
好了,exceptionless的配置以及完成,接下来就是代码中使用了!
4.代码中使用异常,直接上代码吧!就是在ValuesController中修改下get方法进行下测试,代码很简单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// GET api/values [HttpGet]
public ActionResult Get()
{
try
{
throw new Exception( "ExceptionDemo 的异常" );
}
catch (Exception ex)
{
ex.ToExceptionless().Submit();
}
return Ok();
}
|
5.运行起来吧。然后浏览器切换到exceptionless的面板进行查看吧,会自动刷新出现异常信息,如下图 http://localhost:50000/#!/project/5b2663e4e6c0b51dd015bdab/dashboard
6.点击进入可以查看详细信息
总结:
本文从Exceptionless是什么入手,然后介绍了Exceptionless的安装环境以及要求,接下来通过图文详细的介绍了Exceptionless的安装以及配置。最后通过一个Demo演示了如何在代码中使用Exceptionless,当然只是简单地一些使用!今天的关于asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程的介绍就到这里了!
asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案
之前碰到asp.net core异步进行新增操作并且需要判断某些字段是否重复的问题,进行插入操作的话会导致数据库中插入重复的字段!下面把我的解决方法记录一下,如果对您有所帮助,欢迎拍砖!
场景:EFCore操作MySql数据库的项目,进行高并发插入操作
需求:消息队列,最后进行新增数据的操作,插入前判断某些字段是否重复
问题:采用await db.SaveChangesAsync()进行提交操作前,FirstOrDefault判断数据库中是否有重复数据。测试100条一样的数据进行并发插入,结果数据库中插入成功四条重复数据!
原因分析:有可能是await db.SaveChangesAsync异步进行操作导致的时差问题!
解决方案:
第一种方案: 数据库中对表设置复合主键,即把需要判断不能重复的字段组合起来设置主键(不建议这种方式);
第二种方案:数据库插入操作采用同步的方式进行插入,即:await db.SaveChangesAsync() 改为 db.SaveChanges();
第三种方案:数据库查询操作FirstOrDefault 以及数据库提交插入操作 await db.SaveChangesAsync() 放在一个数据库事务中即用 using (var tran = dBContext.Database.BeginTransaction())包裹下代码即可!
以上就是asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案!希望对您有所帮助!
.NET Core开发日志——Middleware
熟悉ASP.NET架构的开发者一定对于HTTP Modules与HTTP Handlers不陌生。两者的作用主要是对网络请求执行特定的处理工作。而在.NET Core中,它们都被Middleware(中件间)取代了。
之前的Http Modules和HTTP Handlers是如下图般处理请求的:
现在变成了这样:
一言概括之,Middleware完成了HTTP Modules与HTTP Handlers的原有工作,但又不是简单的化二为一的减法作用。
Middleware减去的其实是与原来ASP.NET中重要的基础——应用程序生命周期事件(application life cycle event)的绑定。
HTTP Modules在初始化时就需要针对HttpApplication的事件作绑定处理,这样当HttpApplication的各项事件被触发时,已绑定的相应处理程序才会按照预期的那样被执行。
public class HelloWorldModule : IHttpModule
{
public HelloWorldModule()
{
}
public String ModuleName
{
get { return "HelloWorldModule"; }
}
// In the Init function, register for HttpApplication
// events by adding your handlers.
public void Init(HttpApplication application)
{
application.BeginRequest +=
(new EventHandler(this.Application_BeginRequest));
application.EndRequest +=
(new EventHandler(this.Application_EndRequest));
}
private void Application_BeginRequest(Object source,
EventArgs e)
{
// Create HttpApplication and HttpContext objects to access
// request and response properties.
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Write("<h1><font color=red>
HelloWorldModule: Beginning of Request
</font></h1><hr>");
}
private void Application_EndRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
context.Response.Write("<hr><h1><font color=red>
HelloWorldModule: End of Request</font></h1>");
}
public void Dispose()
{
}
}
然后你还需要在web.config配置文件注册这个HTTP Module。
<configuration>
<system.web>
<httpModules>
<add name="HelloWorldModule" type="HelloWorldModule"/>
</httpModules>
</system.web>
</configuration>
如果是用Middleware的话,事情就变得很简单了。抛弃IHttpModule接口及HttpModule实现类,不用再关心HttpApplication的任何事件,还有烦人的web.config配置。直接在代码中以最简洁的方式完成工作。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async(context, next) =>{
await context.Response.WriteAsync("Beginning of Request\n");
await next.Invoke();
await context.Response.WriteAsync("End of Request\n");
});
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!\n");
});
}
相似的,对于HTTP Handlers,虽然不用取消对HttpApplication事件的依赖,但以两者的代码实现方式作比较,Middleware亳无疑问胜出一筹。
public class HelloWorldHandler : IHttpHandler
{
public HelloWorldHandler()
{
}
public void ProcessRequest(HttpContext context)
{
HttpRequest Request = context.Request;
HttpResponse Response = context.Response;
// This handler is called whenever a file ending
// in .sample is requested. A file with that extension
// does not need to exist.
Response.Write("<html>");
Response.Write("<body>");
Response.Write("<h1>Hello from a synchronous custom HTTP handler.</h1>");
Response.Write("</body>");
Response.Write("</html>");
}
public bool IsReusable
{
// To enable pooling, return true here.
// This keeps the handler in memory.
get { return false; }
}
}
仍需要在web.config文件中注册HTTP handler。
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="*.sample"
type="HelloWorldHandler"/>
</httpHandlers>
</system.web>
</configuration>
换作Middleware的写法:
private static void HandleSample(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Hello Sample");
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.MapWhen(context => context.Request.Path.Value.EndsWith("sample"), HandleSample);
}
总结下使用Middleware的优点:
- 没有对HttpApplication的依赖
- 没有对IHttpModule与IHttpHandler接口的依赖
- 无需在web.config文件中添加各种配置
- 代码简洁
最后需要补充Middleware与HTTP Modules的一点差异。各Middleware中处理请求与响应的顺序是刚好相反的,越早处理请求的Middleware越晚处理响应。而HTTP Modules中处理请求与响应的顺序则保持一致,因为每个HTTP Module请求与响应事件的绑定都是在同一阶段完成的。