DD.WellWorkover.Cloud/AsbCloudInfrastructure/Services/ExcelServices/ExcelParser.cs

134 lines
4.0 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reflection;
using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions;
using AsbCloudApp.Services.Parsers;
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
using ClosedXML.Excel;
using Mapster;
namespace AsbCloudInfrastructure.Services.ExcelServices;
public abstract class ExcelParser<TDto, TOptions, TTemplate> : IParserService<TDto, TOptions>
where TDto : class, IValidatableObject, IId
where TOptions : IParserOptionsRequest
where TTemplate : class, ITemplateParameters, new()
{
protected TTemplate TemplateParameters => new();
public virtual ParserResultDto<TDto> Parse(Stream file, TOptions options)
{
using var workbook = new XLWorkbook(file);
var sheet = workbook.GetWorksheet(TemplateParameters.SheetName);
var dtos = ParseExcelSheet(sheet);
return dtos;
}
public virtual Stream GetTemplateFile() =>
Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateParameters.FileName)
?? throw new ArgumentNullException($"Файл '{TemplateParameters.FileName}' не найден");
protected virtual IDictionary<string, object?> ParseRow(IXLRow xlRow)
{
var cells = TemplateParameters.Cells.ToDictionary(x => x.Key, x =>
{
var columnNumber = x.Value.ColumnNumber;
var xlCell = xlRow.Cell(columnNumber);
var cellValue = x.Value.GetValueFromCell(xlCell);
return cellValue;
});
return cells;
}
protected virtual TDto BuildDto(IDictionary<string, object?> row, int rowNumber)
{
var dto = row.Adapt<TDto>();
return dto;
}
private ValidationResultDto<TDto> Validate(TDto dto, int rowNumber)
{
var validationResults = new List<ValidationResult>();
var isValid = dto.Validate(validationResults);
if (isValid)
{
var validDto = new ValidationResultDto<TDto>
{
Item = dto
};
return validDto;
}
var columnsDict = TemplateParameters.Cells.ToDictionary(x => x.Key, x => x.Value.ColumnNumber);
var invalidDto = new ValidationResultDto<TDto>
{
Item = dto,
Warnings = validationResults
.SelectMany(v => v.MemberNames
.Where(columnsDict.ContainsKey)
.Select(m =>
{
var columnNumber = columnsDict[m];
var errorMessage = v.ErrorMessage;
var warningMessage = string.Format(XLExtentions.ProblemDetailsTemplate,
TemplateParameters.SheetName,
rowNumber,
columnNumber,
errorMessage);
var warning = new ValidationResult(warningMessage, new[] { m });
return warning;
}))
};
return invalidDto;
}
protected virtual ParserResultDto<TDto> ParseExcelSheet(IXLWorksheet sheet)
{
var count = sheet.RowsUsed().Count() - TemplateParameters.HeaderRowsCount;
if (count <= 0)
return new ParserResultDto<TDto>();
var valiationResults = new List<ValidationResultDto<TDto>>(count);
var warnings = new List<ValidationResult>();
for (var i = 0; i < count; i++)
{
var xlRow = sheet.Row(1 + i + TemplateParameters.HeaderRowsCount);
var rowNumber = xlRow.RowNumber();
try
{
var row = ParseRow(xlRow);
var dto = BuildDto(row, rowNumber);
var validationResult = Validate(dto, rowNumber);
valiationResults.Add(validationResult);
}
catch (FileFormatException ex)
{
var warning = new ValidationResult(ex.Message);
warnings.Add(warning);
}
}
var parserResult = new ParserResultDto<TDto>
{
Item = valiationResults
};
if (warnings.Any())
parserResult.Warnings = warnings;
return parserResult;
}
}