using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; using AsbCloudApp.Data; using AsbCloudApp.Requests.ParserOptions; using AsbCloudApp.Services; using ClosedXML.Excel; namespace AsbCloudInfrastructure; public abstract class ParserServiceBase : IParserService where TDto : class, IId where TOptions : IParserOptionsRequest { protected readonly IServiceProvider serviceProvider; protected ParserServiceBase(IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; } protected virtual ICollection ValidationResults { get; } = new List(); protected abstract string SheetName { get; } public abstract ParserResultDto Parse(Stream file, TOptions options); public abstract Stream GetTemplateFile(); protected virtual ValidationResultDto ValidateRow(int rowNumber, IDictionary columnNumbers, TDto dto) { var validationContext = new ValidationContext(dto, serviceProvider: null, items: null); if (Validator.TryValidateObject(dto, validationContext, ValidationResults, true)) { var validRow = new ValidationResultDto { Item = dto }; return validRow; } var invalidRow = new ValidationResultDto { Item = dto, }; var warnings = new List(); foreach (var validationResult in from v in ValidationResults let memberNames = v.MemberNames.Where(columnNumbers.ContainsKey) select memberNames.Select(x => { var columnNumber = columnNumbers[x]; var errorMessage = v.ErrorMessage; var warningMessage = string.Format(IParserService.MessageTemplate, SheetName, rowNumber, columnNumber, errorMessage); var warning = new ValidationResult(warningMessage, new[] { x }); return warning; })) { warnings.AddRange(validationResult); } invalidRow.Warnings = warnings; return invalidRow; } protected virtual ParserResultDto ParseExcelSheet(IXLWorksheet sheet, Func> parseRow, int columnCount, int headerRowsCount = 0) { if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < columnCount) throw new FileFormatException($"Лист {SheetName} содержит меньшее количество столбцов."); var count = sheet.RowsUsed().Count() - headerRowsCount; if (count > 1024) throw new FileFormatException($"Лист {SheetName} содержит слишком большое количество строк."); if (count <= 0) return new ParserResultDto(); var dtos = new List>(count); var warnings = new List(); for (var i = 0; i < count; i++) { var row = sheet.Row(1 + i + headerRowsCount); try { var dto = parseRow.Invoke(row); dtos.Add(dto); } catch (FileFormatException ex) { var warning = new ValidationResult(ex.Message); warnings.Add(warning); } } var parserResult = new ParserResultDto { Item = dtos }; if (warnings.Any()) parserResult.Warnings = warnings; return parserResult; } }