ScriptBuffer выдает исключение NullReferenceException при вызове из события как часть цикла — компонент сценария SSIS

У меня есть пакет SSIS, который вызывает Data Flow Task как часть цикла, который повторяет разные адреса конечных точек (вне области действия).

Управление потоком

У Data Flow Task есть источник Script Component, отвечающий за вызов REST API и создание строки для каждого результата.

Есть 3 выходных буфера; 1. строка фактических данных 2. строка ошибок 3. контроль

Буфер мониторинга, используемый для телеметрии, заполняется с помощью события (EventHander), которое запускается каждый раз, когда API делает запрос.

Во время первой итерации цикла ForEach в цикле Control Flow все работает, как и ожидалось, все буферы выдают правильные строки.

Однако во время следующих итераций буфер мониторинга, который заполняется внутри события, выдает;

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.SqlServer.Dts.Pipeline.ScriptComponentHost.HandleUserException(Exception e)
   at Microsoft.SqlServer.Dts.Pipeline.ScriptComponentHost.PrimeOutput(Int32 outputs, Int32[] outputIDs, PipelineBuffer[] buffers)
   at Microsoft.SqlServer.Dts.Pipeline.ManagedComponentHost.HostPrimeOutput(IDTSManagedComponentWrapper100 wrapper, Int32 outputs, Int32[] outputIDs, IDTSBuffer100[] buffers, IntPtr ppBufferWirePacket)

Я не понимаю, почему MonitoringBuffer не инициализируется в последующих итерациях.

Исключение возникает при вызове MonitoringBuffer.AddRow();.

Вот весь компонент сценария, упрощенный для удобства чтения:

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
    private string ClientCode { get { return Variables.ErplyClientCode; } }
    private string Username { get { return Variables.ErplyUsername; } }
    private string Password { get { return Variables.ErplyPassword; } }
    private bool IsTest { get { return Variables.IsTest; } }
    private int ErplyRecordsPerPage { get { return Variables.ErplyRecordsPerPage; } }
    private string ErplyDebugOutputPath { get { return Variables.ErplyDebugOutputPath; } }
    private DateTime ChangeSince { get { return Variables.ChangeSince; } }
    private int records { get; set; }
    private int errors { get; set; }
    private string rawFolder { get; set; }
    public override void PreExecute()
    {
        base.PreExecute();
    }

    public override void PostExecute()
    {
        base.PostExecute();
    }

    public override void CreateNewOutputRows()
    {
        ErplyAPI.OnPreRequestEvent += new EventHandler<EAPIEvent>(ErplyAPI_OnPreRequestEvent);

        var staff = ErplyAPI.getStaff(ClientCode, Username, Password, ChangeSince, ErplyRecordsPerPage, IsTest);
        foreach (var p in staff.List)
        {
            try
            {
                if (!p.IsError)
                {
                    EmployeeBuffer.AddRow();
                    EmployeeBuffer.employeeID = p.employeeID;
                }
                else
                {
                    ErrorBuffer.AddRow();
                    ErrorBuffer.employeeID = p.employeeID;
                    ErrorBuffer.Error = p.Error.Message.Trim() + "\n" + p.Error.StackTrace;
                    errors++;
                }
                records++;
            }
            catch (Exception ex)
            {
                this.ComponentMetaData.FireWarning(0, "Script", ex.Message + "\n" + ex.StackTrace, string.Empty, 0);
            }

        }

        EmployeeBuffer.SetEndOfRowset();
        ErrorBuffer.SetEndOfRowset();

    }

    private void ErplyAPI_OnPreRequestEvent(object sender, EAPIEvent e)
    {
        var request = string.Empty;
        var sessionKey = string.Empty;
        bool fireAgain = true;

        if (e == null)
        {
            ComponentMetaData.FireWarning(0, "SC_ERPLY_API", string.Format("EAPIEvent is NULL in ErplyAPI_OnPreRequestEvent. Amonit did not log the Erply request."), string.Empty, 0);
            return;
        }

        if (e.eAPI == null)
        {
            ComponentMetaData.FireWarning(0, "SC_ERPLY_API", string.Format("EAPIEvent.eAPI is NULL in ErplyAPI_OnPreRequestEvent. Amonit did not log the Erply request."), string.Empty, 0);
            return;
        }

        try
        {
            if (e.Parameters != null && e.Parameters.ContainsKey("request"))
                request = e.Parameters["request"].ToString();

            if (request != "verifyUser" && e.Parameters != null && e.Parameters.ContainsKey("sessionKey"))
                sessionKey = e.Parameters["sessionKey"].ToString();
        }
        catch (Exception ex)
        {
            ComponentMetaData.FireWarning(0, "SC_ERPLY_API", string.Format("Error occurred assigning variables from EAPIEvent parameters in ErplyAPI_OnPreRequestEvent. {0} {1}", ex.Message, ex.StackTrace), string.Empty, 0);
        }

        try
        {
            MonitoringBuffer.AddRow(); // Exception occurs here
            MonitoringBuffer.Request = ResizeString(request, 255);
            MonitoringBuffer.SessionKey = ResizeString(sessionKey, 128);
        }
        catch (Exception ex)
        {
            var message = string.Format("Error occurred outputting Erply request in ErplyAPI_OnPreRequestEvent. {0} {1}", ex.Message, ex.StackTrace);

            MonitoringBuffer.ErrorMessage = ResizeString(message, 8000);

            ComponentMetaData.FireWarning(0, "SC_ERPLY_API", message, string.Empty, 0);
        }
        finally
        {
            MonitoringBuffer.EndOfRowset();
        }
    }
}

person Bernarzinho    schedule 16.04.2020    source источник


Ответы (2)


Я разобрался с проблемой.

Исключение возникало при доступе к дозатору переменных из события. По какой-то причине GetValueWithContext(ScriptComponent.EvaluatorContext) отбрасывается во время второго вызова. Почему это происходит, мне не понятно.

Решение простое, назначьте переменные из диспенсера переменных локальному свойству или переменной в функции OnPreExecute.

Также рекомендуется не вызывать дозатор переменных в CreateNewOutputRows, так как это приводит к блокировке переменных.

person Bernarzinho    schedule 08.05.2020

Я тоже столкнулся с этой проблемой, но мое решение было немного другим - перемещение назначений переменных в PreExecute() не помогло.

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

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

person anthonypants    schedule 16.01.2021