Общие переменные SSRS и одновременное выполнение отчетов

У нас есть некоторые отчеты SSRS, которые терпят неудачу, когда два из них выполняются очень близко друг к другу.

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

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

Примечание: вот мои ресурсы для проблемы с переменным столкновением:

Форум MSDN SSRS :

Поскольку это использует статические переменные, если два человека запустили отчет в тот же самый момент, есть небольшая вероятность, что вы разбейте состояние переменной другого (в SQL 2000 это может случиться из-за двух пользователей, разбивающихся по одному и тому же отчету в то же время а не только благодаря точному одновременному исполнению). Если вам нужно быть уверенным на 100%, чтобы избежать этого, вы можете сделать каждую из общих переменных хэш-таблицей на основе идентификатора пользователя (Globals! UserID).

Встроенный код в службах Reporting Services :

… если несколько пользователей одновременно выполняют отчет с этим кодом, оба отчета будут изменять одно и то же поле подсчета (поэтому это общее поле). Вы не хотите отлаживать эти виды взаимодействий – придерживаться общих функций, используя только локальные переменные (переменные, переданные ByVal или объявленные в теле функции).

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

Итак, я приступил к идее использования хеш-таблицы, чтобы сохранить что-то изолированное. Я планировал, что хеш-ключ является внутренним параметром отчета, называемым InstanceID, по умолчанию =Guid.NewGuid().ToString() .

Частично благодаря моим исследованиям в этом, я обнаружил, что это еще сложнее, потому что Hashtables не являются потокобезопасными, согласно разделу «Сохранение состояния в службах Reporting Services» .

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

Поэтому, прежде чем я пойду слишком далеко, мне интересно, если кто-то еще уже идет по этому пути и может дать мне несколько советов. Вот код, который у меня есть до сих пор:

 Private Shared Data As New System.Collections.Hashtable() Public Shared Function Initialize() As String If Not Data.ContainsKey(Parameters!InstanceID.Value) Then Data.Add(Parameters!InstanceID.Value, New System.Collections.Hashtable()) End If LetValue("SomethingCount", 0) Return "" End Function Private Shared Function GetValue(ByVal Name As String) As Object Return Data.Item(Parameters!InstanceID.Value).Item(Name) End Function Private Shared Sub LetValue(ByVal Name As String, ByVal Value As Object) Dim V As System.Collections.Hashtable = Data.Item(Parameters!InstanceID.Value) If Not V.ContainsKey(Name) Then V.Add(Name, Value) Else V.Item(Name) = Value End If End Sub Public Shared Function SomethingCount() As Long SomethingCount = GetValue("SomethingCount") + 1 LetValue("SomethingCount", SomethingCount) End Function 
  1. Моя самая большая проблема здесь – безопасность потоков. Я мог бы выяснить остальные вопросы ниже, но я не испытываю этого, и я знаю, что это область, в которой ЛЕГКО идти не так. Ссылка выше использует метод Dim _sht as System.Collections.Hashtable = System.Collections.Hashtable.Synchronized(_hashtable) . Это лучше? Как насчет Mutex? Семафор? У меня нет опыта в этом.

  2. Я думаю, что пространство имен System.Collections для Hashtable верное, но мне сложно добавить System.Collections в качестве ссылки в моем отчете, чтобы попытаться вылечить мою текущую ошибку «Не удалось загрузить файл или сборку« System.Collections ». Когда я просматриваю, чтобы добавить ссылку, это не доступный компонент для выбора.

  3. Я только что подтвердил, что я могу вызвать код из выражения значения по умолчанию параметра, поэтому я поставлю там код инициализации. Я также только что узнал о процедуре OnInit, но у этого есть свои собственные проблемы, чтобы исследовать и работать: набор параметров не может ссылаться на метод OnInit во время инициализации параметра .

  4. Я не уверен в объявлении переменной Data как New, возможно, ее нужно только создать в инициализаторе, если она еще не выполнена (но я беспокоюсь о состоянии гонки из-за задержки между проверкой, что она пуста, и ее экземпляром).

  5. У меня также есть вопрос о ключевом слове Shared. Это необходимо во всех случаях? Я получаю ошибки, если не оставляю это в объявлении функций, но, похоже, работает, когда я оставляю его без объявления переменной. Тестирование нескольких одновременных выполнения отчетов затруднено … Может ли кто-нибудь объяснить, что Shared означает конкретно в контексте кода SSRS?

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

  7. Лучше ли иметь вложенные Hashtables, как я выбрал в своей реализации, или объединить мой экземпляр InstanceID с именем переменной, чтобы иметь плоскую хэш-таблицу?

Я очень благодарен за руководство, идеи и / или критику в любом аспекте того, что я здесь представил.

Спасибо!

Erik

Ваш код выглядит отлично. Для безопасности потоков только корневая (общая) хэш-таблица Данные должны быть синхронизированы. Если вы хотите избежать использования InstanceID, вы можете использовать Globals.ExecutionTime и User.UserID .

В основном, я думаю, вы просто хотите изменить для инициализации следующим образом:

 Private Shared Data As System.Collections.Hashtable If Data Is Nothing Then Set Data = Hashtable.Synchronized(New System.Collections.Hashtable()) End If 

Содержащиеся хеш-таблицы должны использоваться только одним потоком в любой момент, но если вы сомневаетесь, вы также можете синхронизировать их.

  • Почему шаблон генератора хранимых процедур MyGeneration не работает?
  • Извлечь файл excel, хранящийся на сервере sql, используя vb.net
  • Преобразование команды SqlCommand в T-SQL
  • webservice vb.net чтение данных sql server 2008 R2
  • Обновление DataSet и SQL-запрос
  • Является ли мой код отсоединения правильным?
  • Использование VB.net OR C # (SSIS) для записи изображения на диск
  • System.Data.SqlClient.SqlException: преобразование не удалось при преобразовании даты и времени из символьной строки в зависимости от языка ОС
  • Исключение переполнения SqlDateTime
  • SQL Server 'Resume Next' Equivalent
  • Как вставить изображения в таблицу базы данных SQL Server
  • Давайте будем гением компьютера.