總體設計
Magicodes.IE是一個匯入匯出通用庫,支援Dto匯入匯出以及動態匯出,支援Excel、Word、Pdf、Csv和Html。在本篇教程,筆者將講述如何使用Magicodes.IE的匯入匯出篩選器。在開始之前,我們需要先了解Magicodes.IE目前支援的篩選器:
介面 | 說明 |
---|---|
IImportResultFilter | 匯入結果篩選器,可以修改匯入結果包括驗證錯誤資訊(比如動態修改錯誤標註) |
IImportHeaderFilter | 匯入列頭篩選器,可以修改列名、值對映集合等等 |
IExporterHeaderFilter | 匯出列頭篩選器,可以修改列頭、索引、值對映等等 |
匯入結果篩選器(IImportResultFilter)的使用
匯入結果篩選器可以修改匯入結果包括驗證錯誤資訊(比如動態修改錯誤標註),非常適合對匯入資料和錯誤驗證內容進行二次動態加工,比如加入自定義校驗邏輯、驗證訊息多語言翻譯等等。接下來我們開始實戰:
準備匯入檔案
如下圖所示,我們準備瞭如下Excel匯入檔案:
準備Dto
Excel準備好了,我們需要準備一個Dto:
[ExcelImporter(ImportResultFilter = typeof(ImportResultFilterTest), IsLabelingError = true)] public class ImportResultFilterDataDto1 { /// <summary> /// 產品名稱 /// </summary> [ImporterHeader(Name = "產品名稱")] public string Name { get; set; } /// <summary> /// 產品程式碼 /// 長度驗證 /// 重複驗證 /// </summary> [ImporterHeader(Name = "產品程式碼", Description = "最大長度為20", AutoTrim = false, IsAllowRepeat = false)] public string Code { get; set; } }
如上述程式碼所示,我們建立了名為“ImportResultFilterDataDto1”的Dto,使用ExcelImporter特性中的ImportResultFilter屬性指定了匯入結果篩選器的型別。
建立類並實現介面IImportResultFilter
接下來我們就建立一個類並實現IImportResultFilter介面:
public class ImportResultFilterTest : IImportResultFilter { /// <summary> /// 本示例修改資料錯誤驗證結果,可用於多語言等場景 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="importResult"></param> /// <returns></returns> public ImportResult<T> Filter<T>(ImportResult<T> importResult) where T : class, new() { var errorRows = new List<int>() { 5,6 }; var items = importResult.RowErrors.Where(p => errorRows.Contains(p.RowIndex)).ToList(); for (int i = 0; i < items.Count; i++) { for (int j = 0; j < items[i].FieldErrors.Keys.Count; j++) { var key = items[i].FieldErrors.Keys.ElementAt(j); var value = items[i].FieldErrors[key]; items[i].FieldErrors[key] = value?.Replace("存在資料重複,請檢查!所在行:", "Duplicate data exists, please check! Where:"); } } return importResult; } }
如上述程式碼所示,我們將重複錯誤的驗證提示修改為了“Duplicate data exists, please check! Where”。接下來,我們需要編寫匯入程式碼:
編寫匯入程式碼
public async Task ImportResultFilter_Test() { var filePath = Path.Combine(Directory.GetCurrentDirectory(), "TestFiles", "Errors", "資料錯誤.xlsx"); var labelingFilePath = Path.Combine(Directory.GetCurrentDirectory(), $"{nameof(ImportResultFilter_Test)}.xlsx"); var result = await Importer.Import<ImportResultFilterDataDto1>(filePath, labelingFilePath); }
開啟上述程式碼所示的標註檔案路徑,就可以看到驗證提示被我們改成了英文:
匯入列頭篩選器(IImportHeaderFilter)的使用
匯入列頭篩選器可以修改列名、驗證屬性、值對映集合等等,非常適合動態修改列名、驗證邏輯、值對映等等。和前面的一樣,我們先得準備一個匯入檔案。
準備匯入檔案
準備Dto
/// <summary> /// 匯入學生資料Dto /// IsLabelingError:是否標註資料錯誤 /// </summary> [ExcelImporter(IsLabelingError = true, ImportHeaderFilter = typeof(ImportHeaderFilterTest))] public class ImportHeaderFilterDataDto1 { /// <summary> /// 姓名 /// </summary> [ImporterHeader(Name = "姓名", Author = "雪雁")] [Required(ErrorMessage = "學生姓名不能為空")] [MaxLength(50, ErrorMessage = "名稱字數超出最大限制,請修改!")] public string Name { get; set; } /// <summary> /// 性別 /// </summary> [ImporterHeader(Name = "性別")] [Required(ErrorMessage = "性別不能為空")] public Genders Gender { get; set; } }
如上述程式碼所示,我們通過ImportHeaderFilter屬性指定了列頭篩選器型別。接下來,我們需要完成相關實現:
建立類並實現介面IImportHeaderFilter
/// <summary> /// 匯入列頭篩選器測試 /// 1)測試修改列頭 /// 2)測試修改值對映 /// </summary> public class ImportHeaderFilterTest : IImportHeaderFilter { public List<ImporterHeaderInfo> Filter(List<ImporterHeaderInfo> importerHeaderInfos) { foreach (var item in importerHeaderInfos) { if (item.PropertyName == "Name") { item.Header.Name = "Student"; } else if (item.PropertyName == "Gender") { item.MappingValues = new Dictionary<string, dynamic>() { {"男",0 }, {"女",1 } }; } } return importerHeaderInfos; } }
通過上述程式碼,我們編寫了一些測試:
- 實現了IImportHeaderFilter
- 將屬性名稱為“Name”的列的列頭修改為“Student”
- 將屬性名稱為“Gender”的列的列對映改為男女對映
接下來我們繼續編寫匯入邏輯:
public async Task ImportHeaderFilter_Test() { var filePath = Path.Combine(Directory.GetCurrentDirectory(), "TestFiles", "Import", "匯入列頭篩選器測試.xlsx"); var import = await Importer.Import<ImportHeaderFilterDataDto1>(filePath); }
如下圖所示,我們成功的將Excel列名為“Student”的列匯入到了Dto的Name屬性,同時將男女轉換為了列舉:
匯出列頭篩選器(IExporterHeaderFilter)的使用
匯出列頭篩選器可以修改列頭、索引、值對映,非常適合動態修改匯出邏輯,比如列頭的中英轉換,值對映動態邏輯等等。接下來我們一起來實戰:
準備Dto並編寫匯出程式碼
[Exporter(Name = "測試", TableStyle = "Light10", ExporterHeaderFilter = typeof(TestExporterHeaderFilter1))] public class ExporterHeaderFilterTestData1 { [ExporterHeader(DisplayName = "加粗文字", IsBold = true)] public string Text { get; set; } [ExporterHeader(DisplayName = "普通文字")] public string Text2 { get; set; } [ExporterHeader(DisplayName = "忽略", IsIgnore = true)] public string Text3 { get; set; } [ExporterHeader(DisplayName = "數值", Format = "#,##0")] public decimal Number { get; set; } [ExporterHeader(DisplayName = "名稱", IsAutoFit = true)] public string Name { get; set; } }
如上述Dto程式碼所示,我們通過匯出特性Exporter的ExporterHeaderFilter屬性指定了匯出列頭篩選器。
實現篩選器IExporterHeaderFilter
public class TestExporterHeaderFilter1 : IExporterHeaderFilter { /// <summary> /// 表頭篩選器(修改名稱) /// </summary> /// <param name="exporterHeaderInfo"></param> /// <returns></returns> public ExporterHeaderInfo Filter(ExporterHeaderInfo exporterHeaderInfo) { if (exporterHeaderInfo.DisplayName.Equals("名稱")) { exporterHeaderInfo.DisplayName = "name"; } return exporterHeaderInfo; } }
如上述程式碼所示,我們實現了匯出篩選器,並將顯示名為“名稱”的列修改為了“name”。
編寫匯出邏輯
//匯出 IExporter exporter = new ExcelExporter(); //使用GenFu生成測試資料 var data1 = GenFu.GenFu.ListOf<ExporterHeaderFilterTestData1>(); var result = await exporter.Export(filePath, data1);
使用上述程式碼匯出後,我們來驗證匯出結果:
是不是So easy呢?當然我們還可以做一些其他的事情,比如修改忽略列:
public class TestExporterHeaderFilter2 : IExporterHeaderFilter { /// <summary> /// 表頭篩選器(修改忽略列) /// </summary> /// <param name="exporterHeaderInfo"></param> /// <returns></returns> public ExporterHeaderInfo Filter(ExporterHeaderInfo exporterHeaderInfo) { if (exporterHeaderInfo.ExporterHeaderAttribute.IsIgnore) { exporterHeaderInfo.ExporterHeaderAttribute.IsIgnore = false; } return exporterHeaderInfo; } }
如何使用容器注入篩選器
篩選器主要是為了滿足大家能夠在匯入匯出時支援動態處理,比如值對映等等。但是通過特性指定篩選器的話,那麼如何支援依賴注入呢?不要慌,針對這個場景,我們也有考慮。
在ASP.NET Core的啟動類(StartUp)註冊容器
參考程式碼如下:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { AppDependencyResolver.Init(app.ApplicationServices); //新增註入關係 services.AddSingleton<IImportResultFilter, ImportResultFilterTest>(); services.AddSingleton<IImportHeaderFilter, ImportHeaderFilterTest>(); services.AddSingleton<IExporterHeaderFilter, TestExporterHeaderFilter1>(); }
然後就盡情使用吧。值得注意的是:
- 注入的篩選器型別的優先順序高於特性指定的篩選器型別,也就是當兩者並存時,優先會使用注入的篩選器
- 注入的篩選器是全域性的,當注入多種型別的篩選器時,均會執行,接下來我們還會支援更多細節控制
- 如果某個邏輯需要禁用所有篩選器,請參考下面部分
- 此功能需要2.4.0-beta2或以上版本才支援
使用IsDisableAllFilter屬性禁用所有的篩選器
如果某段匯入匯出需要禁用所有的篩選器,我們該如何處理?僅需將IsDisableAllFilter設定為true即可。匯入匯出特性均已支援。