Рефакторинг парсинга

1. Добавлен шаблон для сообщений
2. Поправлен naming у сервисов парсинга траекторий
3. Удалена регистрация зависимостей парсеров траекторий
4. Внутри фабрики добавлено создание отдельного scope. Фикс нейминга констант
This commit is contained in:
Степанов Дмитрий 2024-02-08 12:50:14 +03:00
parent c33b7d086a
commit 1b3c06c927
11 changed files with 82 additions and 28 deletions

View File

@ -1,6 +1,4 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions;
@ -35,4 +33,5 @@ public interface IParserService<TDto, in TOptions> : IParserService
/// </summary>
public interface IParserService
{
const string MessageTemplate = "Лист: {0}, Строка: {1}, Столбец: {2}. {3}";
}

View File

@ -45,7 +45,6 @@ using AsbCloudDb.Model.WellSections;
using AsbCloudInfrastructure.Services.ProcessMaps;
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Requests;
using AsbCloudInfrastructure.Services.Trajectory.Parser;
namespace AsbCloudInfrastructure
{
@ -205,8 +204,6 @@ namespace AsbCloudInfrastructure
services.AddTransient<TrajectoryPlanExportService>();
services.AddTransient<TrajectoryFactManualExportService>();
services.AddTransient<TrajectoryFactNnbExportService>();
services.AddTransient<TrajectoryPlanParserService>();
services.AddTransient<TrajectoryFactManualParserService>();
services.AddTransient<IWellOperationRepository, WellOperationRepository>();
services.AddTransient<IDailyReportService, DailyReportService>();
services.AddTransient<IDetectedOperationService, DetectedOperationService>();

View File

@ -21,21 +21,68 @@ public abstract class ParserServiceBase<TDto, TOptions> : IParserService<TDto, T
this.serviceProvider = serviceProvider;
}
protected virtual ICollection<ValidationResult> ValidationResults { get; } = new List<ValidationResult>();
protected abstract string SheetName { get; }
public abstract ParserResultDto<TDto> Parse(Stream file, TOptions options);
public abstract Stream GetTemplateFile();
protected virtual ValidationResultDto<TDto> ValidateRow(int rowNumber,
IDictionary<string, int> columnNumbers,
TDto dto)
{
var validationContext = new ValidationContext(dto, serviceProvider: null, items: null);
if (Validator.TryValidateObject(dto, validationContext, ValidationResults, true))
{
var validRow = new ValidationResultDto<TDto>
{
Item = dto
};
return validRow;
}
var invalidRow = new ValidationResultDto<TDto>
{
Item = dto,
};
var warnings = new List<ValidationResult>();
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<TDto> ParseExcelSheet(IXLWorksheet sheet,
Func<IXLRow, ValidationResultDto<TDto>> parseRow,
int columnCount,
int headerRowsCount = 0)
{
if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < columnCount)
throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
throw new FileFormatException($"Лист {SheetName} содержит меньшее количество столбцов.");
var count = sheet.RowsUsed().Count() - headerRowsCount;
if (count > 1024)
throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк.");
throw new FileFormatException($"Лист {SheetName} содержит слишком большое количество строк.");
if (count <= 0)
return new ParserResultDto<TDto>();

View File

@ -3,23 +3,30 @@ using System.Collections.Generic;
using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.ProcessMapPlan.Parser;
using AsbCloudInfrastructure.Services.Trajectory.Parser;
using Microsoft.Extensions.DependencyInjection;
namespace AsbCloudInfrastructure.Services;
public class ParserServiceFactory
public class ParserServiceFactory : IDisposable
{
public const int IdTrajectoryFactManualParserService = 1;
public const int IdTrajectoryPlanParserService = 2;
public const int IdTrajectoryFactManualParser = 1;
public const int IdTrajectoryPlanParser = 2;
public const int IdProcessMapPlanDrillingParser = 3;
private readonly IDictionary<int, Func<IParserService>> parsers;
private readonly IServiceScope serviceScope;
public ParserServiceFactory(IServiceProvider serviceProvider)
{
serviceScope = serviceProvider.CreateScope();
parsers = new Dictionary<int, Func<IParserService>>
{
{ IdTrajectoryPlanParserService, () => new TrajectoryPlanParserService(serviceProvider) },
{ IdTrajectoryFactManualParserService, () => new TrajectoryFactManualParserService(serviceProvider) }
{ IdTrajectoryPlanParser, () => new TrajectoryPlanParser(serviceScope.ServiceProvider) },
{ IdTrajectoryFactManualParser, () => new TrajectoryFactManualParser(serviceScope.ServiceProvider) },
{ IdProcessMapPlanDrillingParser, () => new ProcessMapPlanDrillingParser(serviceScope.ServiceProvider) }
};
}
@ -33,4 +40,9 @@ public class ParserServiceFactory
return parserService.Invoke() as IParserService<TDto, TOptions>
?? throw new ArgumentNullException(nameof(idParserService), "Ошибка приведения типа");
}
public void Dispose()
{
serviceScope.Dispose();
}
}

View File

@ -5,12 +5,12 @@ using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
public class TrajectoryFactManualParserService : TrajectoryParserService<TrajectoryGeoFactDto>
public class TrajectoryFactManualParser : TrajectoryParser<TrajectoryGeoFactDto>
{
protected override string SheetName => "Фактическая траектория";
protected override string TemplateFileName => "TrajectoryFactManualTemplate.xlsx";
public TrajectoryFactManualParserService(IServiceProvider serviceProvider)
public TrajectoryFactManualParser(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}

View File

@ -2,26 +2,23 @@
using AsbCloudApp.Data.Trajectory;
using ClosedXML.Excel;
using System.IO;
using System.Linq;
using System.Reflection;
using AsbCloudApp.Data;
using AsbCloudApp.Requests.ParserOptions;
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
public abstract class TrajectoryParserService<T> : ParserServiceBase<T, IParserOptionsRequest>
public abstract class TrajectoryParser<T> : ParserServiceBase<T, IParserOptionsRequest>
where T : TrajectoryGeoDto
{
private const int HeaderRowsCount = 2;
private const int ColumnCount = 6;
protected TrajectoryParserService(IServiceProvider serviceProvider)
protected TrajectoryParser(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}
protected abstract string SheetName { get; }
protected abstract string TemplateFileName { get; }
protected abstract ValidationResultDto<T> ParseRow(IXLRow row);

View File

@ -5,12 +5,12 @@ using ClosedXML.Excel;
namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
public class TrajectoryPlanParserService : TrajectoryParserService<TrajectoryGeoPlanDto>
public class TrajectoryPlanParser : TrajectoryParser<TrajectoryGeoPlanDto>
{
protected override string SheetName => "Плановая траектория";
protected override string TemplateFileName => "TrajectoryPlanTemplate.xlsx";
public TrajectoryPlanParserService(IServiceProvider serviceProvider)
public TrajectoryPlanParser(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}

View File

@ -2,6 +2,7 @@
using System;
using System.IO;
using System.Linq;
using AsbCloudApp.Services;
namespace AsbCloudInfrastructure;
@ -39,8 +40,9 @@ public static class XLExtentions
}
catch
{
throw new FileFormatException(
$"Лист '{cell.Worksheet.Name}'. {cell.Address.RowNumber} строка содержит некорректное значение в {cell.Address.ColumnNumber} столбце");
var message = string.Format(IParserService.MessageTemplate, cell.Worksheet.Name, cell.Address.RowNumber,
cell.Address.ColumnNumber, "Содержит некорректное значение");
throw new FileFormatException(message);
}
}
}

View File

@ -37,7 +37,7 @@ public class TrajectoryParserTest
Assert.Fail("Файла для импорта не существует");
var parserService = parserServiceFactory.Create<TrajectoryGeoPlanDto, IParserOptionsRequest>(
ParserServiceFactory.IdTrajectoryPlanParserService);
ParserServiceFactory.IdTrajectoryPlanParser);
var trajectoryRows = parserService.Parse(stream, IParserOptionsRequest.Empty());
@ -54,7 +54,7 @@ public class TrajectoryParserTest
Assert.Fail("Файла для импорта не существует");
var parserService = parserServiceFactory.Create<TrajectoryGeoFactDto, IParserOptionsRequest>(
ParserServiceFactory.IdTrajectoryFactManualParserService);
ParserServiceFactory.IdTrajectoryFactManualParser);
var trajectoryRows = parserService.Parse(stream, IParserOptionsRequest.Empty());

View File

@ -24,7 +24,7 @@ public class TrajectoryFactManualController : TrajectoryEditableController<Traje
parserServiceFactory,
trajectoryExportService,
trajectoryRepository,
ParserServiceFactory.IdTrajectoryFactManualParserService)
ParserServiceFactory.IdTrajectoryFactManualParser)
{
}
}

View File

@ -31,7 +31,7 @@ namespace AsbCloudWebApi.Controllers.Trajectory
parserServiceFactory,
trajectoryExportService,
trajectoryRepository,
ParserServiceFactory.IdTrajectoryPlanParserService)
ParserServiceFactory.IdTrajectoryPlanParser)
{
this.trajectoryVisualizationService = trajectoryVisualizationService;
}