Как избежать загрузки нескольких версий сборки в один и тот же контекст - PullRequest
0 голосов
/ 04 ноября 2011

Тема как бы охватывает мою проблему.Я видел документ «Лучшая практика» по этой проблеме, но на самом деле он не описывает, как выйти из ситуации.http://msdn.microsoft.com/en-us/library/dd153782.aspx

Моя ситуация.Путь A: Основное применение.(Подпись, версия.. 3.5) Сборка общего интерфейса X. (Подпись, версия)

Путь B: Сборка пользователя.Сборка Common Interface X. (Подписано, версиями) (Возможно, версия отличается от описанной выше. Может не знать фактическую версию, поскольку мы не можем контролировать действия клиента / пользователя.)

Наше Основное приложение загружаетуказанный класс из пользовательской сборки, используя отражение, и взаимодействует с классом, используя указанный интерфейс, определенный в сборке общего интерфейса X. Приложения должны оставаться в одном конкретном пути, а пользовательские (бизнес) сборки - в другом пути.Не просите меня изменить это, это не в моих руках.

Проблема в том, что, скорее всего, будет копия Common Interface Assembly X на пути B. Поэтому, когда я загружаю пользовательскую сборку, используяотражая это, он автоматически загружает Common Interface Assembly X по тому же пути, вместо того, чтобы использовать уже загруженный в память вместе с Приложением.В итоге я обнаружил, что тип iXXX не совпадает с типом iXXX или не могу найти конструктор для класса User Assembly, потому что, опять же, он перепутал интерфейсы между двумя копиями Common Interface Assembly X.

Итак,как я могу загрузить и создать класс из User Assembly в Path B, но не загружать Common Interface Assembly X из Path B (и использовать тот из Path A, который уже находится в памяти)?

Дополнительная информация: большинство проблем, с которыми я сталкиваюсь, возникает вокруг CreateInstance, так как ClientContext находится в Common Interface Assembly X, поэтому, хотя я создал его по пути A, конструктор в моем диалоговом окне, похоже, ожидает его из пути BЗатем я получаю «конструктор типа« ExternalTestForms.WindowDemo1 »не найден».ошибка.(Даже с точно такой же [подписанной и версионной] сборкой как в пути A, так и в пути B, эта ошибка все еще происходит.)

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

        public IExternalForm ShowExternalWindow(string filename, string classname, string parameters, string formIdentity)
        {
            if (File.Exists(filename))
            {
                ClientContext context = GetCurrentClientContext(parameters, formIdentity);

                object dialog = null;

                AppDomain currentDomain = AppDomain.CurrentDomain;
                currentDomain.AssemblyResolve += this.CurrentDomain_AssemblyResolve;

                this.basePath = Path.GetDirectoryName(filename);
                Assembly externalAssembly = Assembly.LoadFile(filename);

                try
                {
                    // The Window must must have a ClientContext defined in the constructor.
                    dialog = externalAssembly.CreateInstance(classname, false, BindingFlags.CreateInstance, null, new object[] { context }, context.Desktop.Culture, null);
                }
                catch (Exception ex)
                {
                    // MessageBox "Could not launch the Window"
                    // LogTraceException
                }

                if (dialog != null && dialog is IExternalForm && dialog is System.Windows.Window)
                {
                    System.Windows.Window window = (System.Windows.Window)dialog;
...
...
...
                }
...
            }
        }


        private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            string filename = args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll";

            // Seek out the specified assembly in the current Application path first.
            string assemblyPath = Path.Combine(Application.StartupPath, filename);

            if (!File.Exists(assemblyPath))
            {
                assemblyPath = Path.Combine(this.basePath, filename);
            }

            if (File.Exists(assemblyPath))
            {
                // Load the assembly from the specified path.
                Assembly myAssembly = Assembly.LoadFrom(assemblyPath);

                // Return the loaded assembly.
                return myAssembly;
            }

            return null;
        }

1 Ответ

1 голос
/ 04 ноября 2011

Несколько различных вариантов с низким воздействием, чтобы рассмотреть:

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

2) При запуске приложения удалите все копии стандартных библиотек DLL в каталогах клиентов, чтобы избежать конфликтов.

...