Создание файлов отчетов SSRS внутри Parallel.ForEachAsync не имеет имен файлов, соответствующих их содержимому в C# .NET 8. Может кто-то объяснить причину?

Вопрос или проблема

Чтобы получить более быстрое создание файлов из SSRS, я создал код Parallel.ForEachAsync, чтобы распределить выполнение по 4 потокам, затем: выполнить несколько запросов к базе данных, за которыми следуют запросы SSRS для генерации отчетов и, наконец, записать байты результата на жесткий диск. Но по какой-то причине имя файла не соответствует содержимому созданного файла. Имя файла формируется на основе некоторых значений из тех же параметров, которые использовались для запроса генерации отчета в SSRS.

Первое любопытное обстоятельство заключается в том, что при генерации единственного файла все проходит хорошо и имя файла соответствует содержимому соответствующего файла, что заставляет меня думать, что это может быть связано с проблемами, вызванными параллельными потоками.

Я включаю только набросок с основными строками кода для создания файла, используя Parallel.ForEachAsync по причинам простоты:

public async Task ProcessReportOnParallelAsync( PocoClass pocoObj )
{
    List<People> people = (await this.PeopleRepository.RetrieveAllInvolved( pocoObj.Params )).ToList();
    await Parallel.ForEachAsync( people, new ParallelOptions{ MaxDegreeOfParallelism = 4 }, async ( personPoco, token ) => 
    {
        var personDetail = await this.PersonDetailsRepository( personPoco.Id, personPoco.CompanyId );
        if( personDetail.ShouldGenerateReport )
        {
            await Report.GenerateAsync( personPoco );
        }

    });
}
public async static Task GenerateAsync( PocoClass pocoObj )
{
    // настройка всей конфигурации объектов SSRS для запроса генерации отчета
    var rsExec = new ReportExecutionServiceSoapClient( httpBinding, new EndpointAddress(SSRSReportExecutionUrl));
    // ...
    
    // В конце
    await rsExec.SetExecutionParameterAsync( null, null, reportParams, "en-us" );
    const string deviceInfo = @"<DeviceInfo><Toolbar>False</Toolbar><DeviceInfo>";
    var response = await rsExec.RenderAsync( new RenderRequest(null, null, "EXCELOPENXML", deviceInfo));
    var byteResults = response.Result;
    string filename = $@"{pocoObj.Id}_{pocoObj.Name}_{pocoObj.Company}";
    string filepath = $@"{this.FolderPathForFileGeneration}\{filename}";

    var fs = new FileStream(filepath, FileMode.Create, FileAccess.ReadWrite);
    await fs.WriteAsync( byteResults);
    fs.Close();
}

Второе любопытное обстоятельство заключается в том, что я ранее создал очень похожий код (который послужил базой для этого) для другого контекста/отчета SSRS в том же проекте. Единственное отличие (исключая параметры и классы) в инструкциях Parallel и SSRS – это параметр RenderRequest, вместо RenderRequest(null, null, "EXCELOPENXML", deviceInfo) другой генерирует PDF: RenderRequest(null, null, "PDF", deviceInfo), в этом случае все проходит хорошо, имена файлов соответствуют их содержимому.

Поэтому я хотел бы понять, что может происходить, что я не могу выяснить: хранимая процедура, связанная с генерацией отчета, или разница в конфигурации между двумя отчетами SSRS, или что-то другое, я не знаю.

Также, если есть решение или другое предложение или лучший подход к этой реализации.

Заранее спасибо!

Ответ или решение

Проблема несоответствия имен файлов и содержимого при создании отчетов SSRS в C# .NET 8

Ваша проблема с несоответствием имен файлов и их содержимого при использовании Parallel.ForEachAsync для генерации отчетов SSRS может быть связана с несколькими факторами. Давайте подробно разберем возможные причины и предложим подходы для их устранения.

1. Конкуренция потоков

При запуске нескольких потоков параллельно (в данном случае 4) существует вероятность, что доступ к общим ресурсам может происходить одновременно. В вашем коде процесс создания имени файла (переменная filename) зависит от параметров, которые обрабатываются в каждом потоке. Если вы используете состояние, изменяемое во время выполнения, это может вызвать условие гонки, при котором потоки могут генерировать имя файла до того, как отчет будет фактически сгенерирован.

Рекомендация: Создайте отдельную локальную переменную для каждого потока, содержащую полное имя файла, во избежание путаницы:

var filename = $@"{pocoObj.Id}_{pocoObj.Name}_{pocoObj.Company}";

Убедитесь, что эта переменная определена в пределах обработки каждого элемента personPoco.

2. Закрытие файлового потока

В вашем коде файл закрывается в конце метода GenerateAsync. Однако, если произойдет исключение или ошибка во время записи в файл, это может привести к тому, что файл не будет закрыт корректно, и данные будут повреждены.

Рекомендация: Используйте конструкцию using для управления жизненным циклом FileStream, что обеспечивает автоматическое закрытие потока даже в случае возникновения исключений:

using (var fs = new FileStream(filepath, FileMode.Create, FileAccess.Write))
{
    await fs.WriteAsync(byteResults);
}

Это гарантирует, что поток будет закрыт корректно.

3. Потенциальные проблемы с конфигурацией SSRS

Разница в поведении между двумя.GenerationAsync(для PDF и Excel) может быть вызвана различиями в конфигурации SSRS. Убедитесь, что используемые параметрыRenderRequest` корректны и соответствуют ожидаемому формату выходных данных. Проверьте, что данные передаются в процедуру корректно.

4. Асинхронные операции

Поскольку вы используете асинхронные операции, важно удостовериться, что порядок выполнения не влияет на доступ к общим данным. Хотя Parallel.ForEachAsync управляет параллельным выполнением, структура вашего кода должна обеспечивать независимость каждого потока.

5. Ошибки в логике генерации

Код может содержать логические ошибки, которые не очевидны при запуске в однопоточном режиме. Проверьте, корректно ли обрабатывается каждый personDetail и вызов GenerateAsync для каждого элемента коллекции people.

Заключение

Несоответствие имен файлов и их содержимого при использовании параллельной обработки может возникнуть по причине гонок потоков, проблем с конфигурацией SSRS или ошибок в обработке данных. Внедрение предложенных изменений улучшит процесс генерации отчетов и обеспечит соответствие между именами файлов и их содержимым. Рассмотрите возможность использования механизмов логирования для мониторинга и отладки при возникновении проблем.

Оцените материал
Добавить комментарий

Капча загружается...