У нас есть некоторые отчеты SSRS, которые не выполняются, когда два из них выполняются очень близко друг к другу.
Я обнаружил, что если два экземпляра отчета SSRS выполняются одновременно, любые переменные кода, объявленные на уровне класса (не внутри функции), могут столкнуться. Я подозреваю, что это может быть причиной ошибок нашего отчета, и я работаю над потенциальным исправлением.
Причина, по которой мы вообще используем часть кода SSRS, заключается в таких вещах, как расчет пользовательских групп и заголовков страниц. Код вызывается из выражений в TextBoxes и возвращает текущую метку. Код должен поддерживать состояние, чтобы помнить, какое было последнее значение заголовка, чтобы вернуть его, когда он неизвестен, или сохранить новое значение заголовка для повторного использования.
Примечание: вот мои ресурсы для решения проблемы коллизии переменных:
Форум MSDN SSRS :
Поскольку при этом используются статические переменные, если два человека запускают отчет с одинаковой
В настоящее время существует небольшая вероятность того, что один из них разбьет состояние переменной другого (в SQL 2000
это может иногда происходить из-за того, что два пользователя разбивают на страницы в одном отчете
в то же время не только из-за точно одновременных казней). Если вам нужно быть на 100%
Чтобы избежать этого, вы можете сделать каждую из общих переменных хеш-таблицей на основе
идентификатор пользователя (Globals! UserID).
Встроенный код в службах отчетов :
... если несколько пользователей выполняют отчет с этим кодом одновременно, оба
в отчетах будет изменяться одно и то же поле Count (поэтому оно является общим). Вы
не хотите отлаживать такого рода взаимодействия - придерживайтесь общих функций, используя только
локальные переменные (переменные, переданные ByVal или объявленные в теле функции).
Я предполагаю, что идея заключается в том, что на сервере генерации отчетов отчет загружается, а модуль Code является статическим классом. Если второй клиент запрашивает тот же отчет, что и другой, достаточно быстро, он подключается к тому же экземпляру этого статического класса. (Вы можете исправить мое описание, если я ошибаюсь.)
Итак, я приступил к идее использования хеш-таблицы для изоляции вещей. Я планировал, чтобы хеш-ключ был внутренним параметром отчета 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
Больше всего меня беспокоит безопасность потоков. Возможно, я смогу разобраться с остальными вопросами ниже, но у меня нет опыта в этом, и я знаю, что это область, в которой ЛЕГКО ошибиться. Ссылка выше использует метод Dim _sht as System.Collections.Hashtable = System.Collections.Hashtable.Synchronized(_hashtable)
. Это лучше? А как насчет Mutex? Семафор? У меня нет опыта в этом.
Я думаю, что пространство имен System.Collections для Hashtable является правильным, но у меня возникают проблемы с добавлением System.Collections в качестве ссылки в моем отчете, чтобы попытаться исправить мою текущую ошибку «Не удалось загрузить файл или сборку» System.Collections». Когда я добавляю ссылку, это недоступный компонент для выбора.
Я только что подтвердил, что могу вызывать код из выражения значения параметра по умолчанию, поэтому я добавлю туда свой код инициализации. Я также только что узнал о процедуре OnInit, но у нее есть свои недостатки, которые необходимо изучить и обойти: На коллекцию параметров нельзя ссылаться из метода OnInit во время инициализации параметра .
Я не уверен в объявлении переменной Data новой, возможно, ее следует создавать в инициализаторе только в том случае, если это еще не сделано (но я беспокоюсь о состоянии гонки из-за задержки между проверкой, что она пуста и экземпляр этого).
У меня также есть вопрос по поводу ключевого слова Shared. Это необходимо во всех случаях? Я получаю ошибки, если я оставляю это вне объявлений функций, но , кажется, работает , когда я оставляю это вне объявления переменных. Тестирование нескольких одновременных выполнений отчетов затруднительно ... Может кто-нибудь объяснить, что именно Shared означает конкретно в контексте кода SSRS?
Есть ли лучший способ инициализировать переменные? Должен ли я предоставить второй параметр функции GetValue, который будет использоваться по умолчанию, если он обнаружит, что переменная еще не существует в хеш-таблице?
Лучше ли иметь вложенные Hashtables, которые я выбрал в своей реализации, или объединить мой InstanceID с именем переменной, чтобы иметь плоскую хеш-таблицу?
Я бы очень признателен за руководство, идеи и / или критические замечания по любому аспекту того, что я здесь представил.
Спасибо!
Эрик