forked from ddrilling/AsbCloudServer
Рефаткоринг инфраструктуры экспорта/импорта
This commit is contained in:
parent
151e481a98
commit
1ccfa84e45
@ -3,12 +3,12 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Requests.ExportOptions;
|
||||
|
||||
namespace AsbCloudApp.Services;
|
||||
namespace AsbCloudApp.Services.Export;
|
||||
|
||||
/// <summary>
|
||||
/// Экспорт данных
|
||||
/// </summary>
|
||||
public interface IExportService<in TOptions>
|
||||
public interface IExportService<in TOptions> : IExportService
|
||||
where TOptions : IExportOptionsRequest
|
||||
{
|
||||
/// <summary>
|
||||
@ -18,4 +18,12 @@ public interface IExportService<in TOptions>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
Task<(string FileName, Stream File)> ExportAsync(TOptions options, CancellationToken token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Экспорт данных
|
||||
/// </summary>
|
||||
public interface IExportService
|
||||
{
|
||||
|
||||
}
|
20
AsbCloudApp/Services/Export/IExportServiceFactory.cs
Normal file
20
AsbCloudApp/Services/Export/IExportServiceFactory.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using AsbCloudApp.Requests.ExportOptions;
|
||||
|
||||
namespace AsbCloudApp.Services.Export;
|
||||
|
||||
/// <summary>
|
||||
/// Фабрика создания сервисов для экспорта
|
||||
/// </summary>
|
||||
/// <typeparam name="TId"></typeparam>
|
||||
public interface IExportServiceFactory<in TId>
|
||||
where TId : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Создать сервис экспорта
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <typeparam name="TOptions"></typeparam>
|
||||
/// <returns></returns>
|
||||
IExportService<TOptions> CreateExportService<TOptions>(TId id)
|
||||
where TOptions : IExportOptionsRequest;
|
||||
}
|
23
AsbCloudApp/Services/Parsers/IParserFactory.cs
Normal file
23
AsbCloudApp/Services/Parsers/IParserFactory.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Requests.ParserOptions;
|
||||
|
||||
namespace AsbCloudApp.Services.Parsers;
|
||||
|
||||
/// <summary>
|
||||
/// Фабрика для создания сервиса парсинга
|
||||
/// </summary>
|
||||
/// <typeparam name="TId"></typeparam>
|
||||
/// <typeparam name="TDto"></typeparam>
|
||||
public interface IParserFactory<in TId, TDto>
|
||||
where TId : struct
|
||||
where TDto : class, IId
|
||||
{
|
||||
/// <summary>
|
||||
/// Создать парсер
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <typeparam name="TOptions"></typeparam>
|
||||
/// <returns></returns>
|
||||
IParserService<TDto, TOptions> CreateParser<TOptions>(TId id)
|
||||
where TOptions : IParserOptionsRequest;
|
||||
}
|
@ -2,14 +2,14 @@ using System.IO;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Requests.ParserOptions;
|
||||
|
||||
namespace AsbCloudApp.Services;
|
||||
namespace AsbCloudApp.Services.Parsers;
|
||||
|
||||
/// <summary>
|
||||
/// Сервис парсинга
|
||||
/// </summary>
|
||||
/// <typeparam name="TDto"></typeparam>
|
||||
/// <typeparam name="TOptions"></typeparam>
|
||||
public interface IParserService<TDto, in TOptions>
|
||||
public interface IParserService<TDto, in TOptions> : IParserService
|
||||
where TDto : class, IId
|
||||
where TOptions : IParserOptionsRequest
|
||||
{
|
||||
@ -26,4 +26,11 @@ public interface IParserService<TDto, in TOptions>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Stream GetTemplateFile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сервис парсинга
|
||||
/// </summary>
|
||||
public interface IParserService
|
||||
{
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Requests.ExportOptions;
|
||||
using AsbCloudApp.Services.Export;
|
||||
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
|
||||
using ClosedXML.Excel;
|
||||
using Mapster;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.ExcelServices;
|
||||
|
||||
public abstract class ExcelExportService<TDto, TOptions, TTemplate> : IExportService<TOptions>
|
||||
where TOptions : IExportOptionsRequest
|
||||
where TTemplate : class, ITemplateParameters, new()
|
||||
{
|
||||
protected TTemplate TemplateParameters => new();
|
||||
|
||||
protected abstract Task<string> BuildFileNameAsync(TOptions options, CancellationToken token);
|
||||
|
||||
protected abstract Task<IEnumerable<TDto>> GetDtosAsync(TOptions options, CancellationToken token);
|
||||
|
||||
public async Task<(string FileName, Stream File)> ExportAsync(TOptions options, CancellationToken token)
|
||||
{
|
||||
var dtos = await GetDtosAsync(options, token);
|
||||
|
||||
var fileName = await BuildFileNameAsync(options, token);
|
||||
var file = BuildFile(dtos);
|
||||
return (fileName, file);
|
||||
}
|
||||
|
||||
private Stream BuildFile(IEnumerable<TDto> dtos)
|
||||
{
|
||||
using var template = GetTemplateFile();
|
||||
using var workbook = new XLWorkbook(template);
|
||||
AddDtosToWorkbook(workbook, dtos);
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
workbook.SaveAs(memoryStream, new SaveOptions { });
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
private void AddDtosToWorkbook(XLWorkbook workbook, IEnumerable<TDto> dtos)
|
||||
{
|
||||
var dtosToArray = dtos.ToArray();
|
||||
|
||||
if (!dtosToArray.Any())
|
||||
return;
|
||||
|
||||
var sheet = workbook.GetWorksheet(TemplateParameters.SheetName);
|
||||
for (var i = 0; i < dtosToArray.Length; i++)
|
||||
{
|
||||
var row = sheet.Row(1 + i + TemplateParameters.HeaderRowsCount);
|
||||
AddRow(row, dtosToArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddRow(IXLRow xlRow, TDto dto)
|
||||
{
|
||||
var properties = dto.Adapt<IDictionary<string, object>>();
|
||||
|
||||
foreach (var (name, cellValue) in properties)
|
||||
{
|
||||
if (TemplateParameters.Cells.TryGetValue(name, out var cell))
|
||||
xlRow.Cell(cell.ColumnNumber).SetCellValue(cellValue);
|
||||
}
|
||||
}
|
||||
|
||||
private Stream GetTemplateFile() =>
|
||||
Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateParameters.FileName)
|
||||
?? throw new ArgumentNullException($"Файл '{TemplateParameters.FileName}' не найден");
|
||||
}
|
134
AsbCloudInfrastructure/Services/ExcelServices/ExcelParser.cs
Normal file
134
AsbCloudInfrastructure/Services/ExcelServices/ExcelParser.cs
Normal file
@ -0,0 +1,134 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.IO;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Requests.ParserOptions;
|
||||
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.ExcelServices;
|
||||
|
||||
public abstract class ExcelWellRelatedParser<TDto, TOptions, TTemplate> : ExcelParser<TDto, TOptions, TTemplate>
|
||||
where TDto : class, IValidatableObject, IId, IWellRelated
|
||||
where TOptions : WellRelatedParserRequest
|
||||
where TTemplate : class, ITemplateParameters, new()
|
||||
{
|
||||
public override ParserResultDto<TDto> Parse(Stream file, TOptions options)
|
||||
{
|
||||
var result = base.Parse(file, options);
|
||||
|
||||
foreach (var dto in result.Item)
|
||||
dto.Item.IdWell = options.IdWell;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -6,13 +6,14 @@ using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Requests.ExportOptions;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.Export;
|
||||
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
|
||||
using ClosedXML.Excel;
|
||||
using Mapster;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.ExcelServices;
|
||||
|
||||
[Obsolete]
|
||||
public abstract class ExportExcelService<TDto, TOptions> : IExportService<TOptions>
|
||||
where TOptions : IExportOptionsRequest
|
||||
{
|
||||
|
@ -6,13 +6,14 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Requests.ParserOptions;
|
||||
using AsbCloudApp.Services;
|
||||
using AsbCloudApp.Services.Parsers;
|
||||
using AsbCloudInfrastructure.Services.ExcelServices.Templates;
|
||||
using ClosedXML.Excel;
|
||||
using Mapster;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.ExcelServices;
|
||||
|
||||
[Obsolete]
|
||||
public abstract class ParserExcelService<TDto, TOptions> : IParserService<TDto, TOptions>
|
||||
where TDto : class, IValidatableObject, IId
|
||||
where TOptions : IParserOptionsRequest
|
||||
|
@ -13,6 +13,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.WellOperation;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.ProcessMaps.Report;
|
||||
|
||||
@ -57,7 +58,7 @@ public class ProcessMapReportDrillingService : IProcessMapReportDrillingService
|
||||
|
||||
var requestWellOperationFact = new WellOperationRequest()
|
||||
{
|
||||
IdWell = idWell,
|
||||
IdsWell = new[] { idWell },
|
||||
OperationType = WellOperation.IdOperationTypeFact,
|
||||
GeDepth = geDepth,
|
||||
LeDepth = leDepth
|
||||
|
@ -9,6 +9,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data.WellOperation;
|
||||
|
||||
namespace AsbCloudInfrastructure.Services.WellOperationService
|
||||
{
|
||||
@ -89,7 +90,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
||||
{
|
||||
var row = sheet.Row(i + headerRowsCount);
|
||||
SetCell(row, columnRowNumber, $"{i}");
|
||||
SetCell(row, columnCaption, $"{tvdItem.CategoryName} {tvdItem.CategoryInfo}".Trim());
|
||||
SetCell(row, columnCaption, $"{tvdItem.OperationCategoryName} {tvdItem.CategoryInfo}".Trim());
|
||||
SetCell(row, columnWellDepthStart, tvdItem.DepthStart);
|
||||
SetCell(row, columnWellDepthEnd, tvdItem.DepthEnd);
|
||||
SetCell(row, columnDuration, tvdItem.DurationHours);
|
||||
@ -150,7 +151,7 @@ namespace AsbCloudInfrastructure.Services.WellOperationService
|
||||
var row = sheet.Row(1 + i + headerRowsCount);
|
||||
|
||||
SetCell(row, columnRowNumber, $"{1 + i}");
|
||||
SetCell(row, columnCaption, $"{operation.CategoryName} {operation.CategoryInfo}".Trim());
|
||||
SetCell(row, columnCaption, $"{operation.OperationCategoryName} {operation.CategoryInfo}".Trim());
|
||||
|
||||
SetCell(row, columnWellDepthStartPlan, tvdItem.Plan?.DepthStart);
|
||||
SetCell(row, columnWellDepthStartFact, tvdItem.Fact?.DepthStart);
|
||||
|
@ -17,10 +17,16 @@ public static class XLExtentions
|
||||
|
||||
public static IXLCell SetCellValue<T>(this IXLCell cell, T value, string? format = null)
|
||||
{
|
||||
if (typeof(T) == typeof(DateTime))
|
||||
if (value is DateTime || value is DateTimeOffset)
|
||||
{
|
||||
cell.Style.DateFormat.Format = format ?? "DD.MM.YYYY HH:MM:SS";
|
||||
}
|
||||
|
||||
if (value is DateTimeOffset dateTimeOffset)
|
||||
{
|
||||
cell.Value = XLCellValue.FromObject(dateTimeOffset.DateTime);
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
|
||||
cell.Value = XLCellValue.FromObject(value);
|
||||
|
||||
|
@ -5,6 +5,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Data.ProcessMaps;
|
||||
using AsbCloudApp.Data.WellOperation;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudApp.Requests;
|
||||
using AsbCloudApp.Services;
|
||||
|
@ -16,6 +16,8 @@ using AsbCloudApp.Requests.ParserOptions;
|
||||
using AsbCloudApp.Data.ProcessMaps;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using AsbCloudApp.Requests.ExportOptions;
|
||||
using AsbCloudApp.Services.Export;
|
||||
using AsbCloudApp.Services.Parsers;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers.ProcessMaps;
|
||||
|
||||
|
@ -10,6 +10,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Requests.ParserOptions;
|
||||
using AsbCloudApp.Services.Parsers;
|
||||
using AsbCloudInfrastructure.Services.Trajectory.Export;
|
||||
|
||||
namespace AsbCloudWebApi.Controllers.Trajectory
|
||||
|
Loading…
Reference in New Issue
Block a user