C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志

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及以上,然后按照以下步骤操作。

  1. 打开文件菜单,点击新建>>项目
  2. 在新打开的新建项目窗口,首先你需要选择 .NET Framework 4.6及以上版本,然后在左侧面板选择C# ,然后选择 .NET Core
  3. 在右侧面板中选择“.NET Core Web 应用程序” 并且选择项目位置,最后点击“确定”
  4. 在下一个窗口,在众多模板中选择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发出请求并使用我们文章开始时创建的数据库脚本来获取我们在此处添加的员工列表数据。

ASP.NET Core Web Api

要获取单个员工记录,只需传递以下URL,如图中所示。您可以在此处看到,我们希望查看员工ID 103的记录。发送请求后,您可以看到如下所示的输出。

ASP.NET Core

最后

所以,今天,我们已经学会了如何创建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请求与响应事件的绑定都是在同一阶段完成的。

posted @ 2018-07-07 18:43  ~雨落忧伤~  阅读(203)  评论(0编辑  收藏  举报