Сборка в компоненте скрипта через отражение работает для случайных случаев - PullRequest
1 голос
/ 07 мая 2019

У меня странная проблема. У меня есть пакет служб SSIS с несколькими потоками данных, и в них я использую компонент Script в качестве места назначения для записи файлов AVRO. Теперь для записи этих AVRO-файлов я использую Microsoft.Hadoop.Avro.dll, который я не хочу устанавливать в GAC, а просто ссылаюсь с помощью отражения. Здесь есть классное руководство , которому я следовал. Теперь все это работало в демо-проекте на прошлой неделе. Однако сегодня, когда я пытаюсь включить то же самое в свое реальное решение, некоторые потоки данных работают, и все идет хорошо, но когда тот же компонент сценария копируется в другой поток данных и запускается с использованием другого набора данных, он не может сказать, что не может найти сборку ,

Обратите внимание: в наборе данных нет ничего плохого, потому что ошибка "загрузка сборки".

Ошибка: System.Reflection.TargetInvocationException: Исключение было сгенерировано целью вызова. ---> System.IO.FileNotFoundException: не удалось загрузить файл или сборку 'Microsoft.Hadoop.Avro, версия = 1.1.0.5, культура = нейтральная, PublicKeyToken = 31bf3856ad364e35' или одна из ее зависимостей. Система не может найти указанный файл.

Я в своем уме, чтобы найти причину этого, поскольку это сбивает с толку.

Вот код для отражения, который я использовал и работал в одном потоке данных, а не в другом (в том же пакете)

    public ScriptMain()
    {
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    }
    public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        string path =  @"C:\Program Files\Microsoft SQL Server\130\DTS\Binn\" ; //@"D:\AVRO Serialize and Deserialize\C#\bin\Debug\";
        if (args.Name.Contains("Microsoft.Hadoop.Avro"))
        {
            return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Microsoft.Hadoop.Avro.dll"));
        }
        if (args.Name.Contains("Newtonsoft.Json"))
        {
            return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Newtonsoft.Json.dll"));
        }
        return null;
    }

Я скопировал сборку в папку DTS \ binn, как и предлагалось в моих сообщениях.

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

П.С .: Я также однажды добавил его в GAC, а потом он заработал, но я не хочу делать это на сервере, а также тот факт, что отражение работало в другом проекте

Еще одна деталь - на прошлой неделе, когда все потоки данных работали в тестовом решении - у него была целевая версия 2017 года, которая также отображалась на фоне имени проекта в Visual Studio. Итак, в реальном проекте, где у меня есть эта странная проблема, связанная с работой в одном потоке данных, а не в другом, я попытался изменить версию целевого сервера на 2017 (с 2016 года), но отображение с названием проекта по-прежнему показывает 2016. Может ли это быть проблемой? Но тогда почему отображаемое имя проекта не изменяется на 2017 год, даже если изменить целевую версию сервера на 2017 год?

Вот как в решении, где все это работало.

ProjectName (SQL Server 2017)

А вот так в глючном проекте

ProjectName (SQL Server 2016)

Даже изменение целевой версии на 2017 не влияет на отображение, но я сомневаюсь, что это проблема

РЕДАКТИРОВАТЬ 1: ОК, я, кажется, понял проблему. Это действительно версия. причина, по которой отображаемое имя не изменялось на 2017, даже если я изменил свойство версии целевого сервера на 2017, была в том, что я не изменил его в конфигурации «Active (development)». Я изменил это, получил некоторые предупреждения от BIDS, говорящие о резервном копировании и т. Д. И т. Д. Но после этого тот же поток данных начал работать, как и предыдущий проект.

Итак, теперь возникает вопрос, почему этот фрагмент кода работает с версией SSIS для SQL 2017, но не с 2016 года. Из этого поста здесь я понимаю, что «В SQL Server 2017 сборки IS были обновлен до .NET 4.0 ", но это не стандартная сборка IS.

Кто-нибудь знает больше?

1 Ответ

1 голос
/ 08 мая 2019

Итак, наконец-то нашли проблему. Похоже, что целевые версии SSIS 2016 и 2017 ведут себя по-разному.

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

Итак, приступая к коду, это то, что было

public class ScriptMain : UserComponent
{

    List<AvroRecord> CounterpartsRowList = new List<AvroRecord>(); //This line was the problem

    public ScriptMain()
    {
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    }
    public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        string path = @"D:\BDS\clientscoredata\ClientScoreDataSsis";
        if (args.Name.Contains("Microsoft.Hadoop.Avro"))
        {
            return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Microsoft.Hadoop.Avro.dll"));
        }
        if (args.Name.Contains("Newtonsoft.Json"))
        {
            return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Newtonsoft.Json.dll"));
        }
        return null;
    }
    /// <summary>
    /// This method is called once, before rows begin to be processed in the data flow.
    ///
    /// You can remove this method if you don't need to do anything here.
    /// </summary>
    public override void PreExecute()
    {
        base.PreExecute();
        abc = new List<AvroRecord>(); // initialization moved here

Таким образом, инициализация abc перемещена в метод PreExecute, а не сразу, когда он определен.

...