AppDomains и configSections - PullRequest
       16

AppDomains и configSections

2 голосов
/ 03 декабря 2009

Мы используем CSLA (довольно древнюю версию) в наших приложениях .NET 3.5, и мы используем загрузку приложений NetRun для некоторых наших пользователей. Для тех, кто не знаком с NetRun, NetRun.exe - это в основном «бегунок» приложения, который устанавливается на компьютерах пользователей (например, в c: \ Program Files \ NetRun \ NetRun.exe). Пользователь просто запускает приложение, запуская NetRun.exe.

Что делает NetRun.exe:

(1) Создает новый AppDomainSetup

Dim setupDomain As New AppDomainSetup()
setupDomain.ApplicationBase = CurrentDomainPath() ' this will be C:\Program Files\NetRun\
setupDomain.ConfigurationFile = "http://www.ourdomain.com/TheApp.xml" ' The app.config file is actually named TheApp.xml on the server because it has NetRun-specific config settings that don't belong in the standard TheApp.config that is used when the app is running directly from the server.

(2) Затем новый AppDomain создается с этим AppDomainSetup

' create new application domain 
Dim newDomain As AppDomain = AppDomain.CreateDomain("TheApp", Nothing, setupDomain)

(3) Затем в этом новом домене приложений создается экземпляр NetRun.Launcher (класс помощника для запуска - в основном используется для общего экрана-заставки) через:

' create launcher object in new appdomain
Dim launcher As Launcher = CType(newDomain.CreateInstanceAndUnwrap("NetRun", "NetRun.Launcher"), Launcher)

(4) Затем вспомогательный класс luncher запускает приложение в новом домене приложений через

' use launcher object from the new domain to launch the remote app in that appdomain
launcher.RunApp()

(5) Который, после всего всплывающего экрана, приложение, наконец, запускается через

Dim ass = Assembly.LoadFrom("http://www.ourdomain.com/TheApp.exe")
ass.EntryPoint.Invoke(ass.EntryPoint, Nothing)

Итак, резюмируя, база приложения AppDomain действующего приложения - это C: \ Program Files \ NetRun \, а EntryPoint для реального приложения находится в "http://www.ourdomain.com/TheApp.exe". Пока все хорошо.

Само приложение, помимо TheApp.exe, также в качестве зависимости от ALibrary.dll. На сегодняшний день это прекрасно сработало для нас. Даже когда ALibrary.dll имеет записи конфигурации, которые были извлечены в файл TheApp.xml, эти записи конфигурации всегда читались нормально (и продолжают это делать).

В нашем следующем выпуске мы добавили новый раздел пользовательских файлов конфигурации, который определен в ALibrary.dll. Мы добавили новый раздел в файлы TheApp.xml и TheApp.config

<configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.Applicat...">
      <section name="TheApp.My.MySettings" type="System.Configuration.ClientSettingsS..."/>
      <section name="ALibrary.My.MySettings" type="System.Configuration.ClientSettingsS..."/>
    </sectionGroup>
    <!-- NEW CONFIG SECTION -->
    <section name="fixedPriceExceptionModel" type="ALibrary.Configuration.FixedPrices.FixedPriceExceptionModelSection, ALibrary"/>
</configSections>

(части были ... вычеркнуты для экономии места в этом посте)

Однако, когда мы пытаемся получить доступ к новому разделу в NetRun, запускается TheApp.exe "обычным" способом через

CType(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None) _
                             .GetSection("fixedPriceExceptionModel"), FixedPriceExceptionModelSection)

Мы получаем следующее исключение:

Произошла ошибка при создании обработчик раздела конфигурации для fixedPriceExceptionModel: не удалось загрузить файл или сборку 'ALibrary' или одна из его зависимостей. Система не могу найти указанный файл. (http://www.ourdomain.com/TheApp.xml строка 8)

В некоторых исследованиях это связано с тем, что распознаватель сборок для библиотек конфигурации .NET ищет файл ALibrary.dll во всех обычных местах; ApplicationBase, конкретные подкаталоги, основные каталоги .NET, а затем GAC. К сожалению, ALibrary.dll никогда не будет найден ни в одном из этих мест. Когда это приложение запускается непосредственно на сервере, без NetRun, приложение не выдает исключение и правильно читает раздел конфигурации.

Одна вещь, которую я попробовал, состояла в том, чтобы установить AppDomainSetup по-другому, так как его ApplicationBase будет установлен в http://www.ourdomain.com/,, но затем последующий вызов CType (newDomain.CreateInstanceAndUnwrap ("NetRun", "NetRun.Launcher") , Launcher), потому что NetRun.exe не на сервере.

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

Ответы [ 3 ]

2 голосов
/ 04 декабря 2009

Насколько я понял проблема, дело в том, что код запускается на клиентской машине без реального (физического) присутствия сборок, так как они загружаются с сервера.

Зная это, у вас есть два варианта:
1. Умереть, пытаясь найти решение с существующим кодом;)
2. Не используйте пользовательский обработчик раздела конфигурации.

Лично я бы пошел с # 2.

Вместо использования ALibrary.Configuration.FixedPrices.FixedPriceExceptionModelSection в качестве обработчика раздела конфигурации (который вызывает исключение, так как этот тип не может быть найден на клиенте), используйте стандартный System.Configuration.ClientSettingsSection, как и другие разделы - это часть .NET Framework, так что нет проблем здесь на клиенте. После этого создайте фабрику для необходимого класса конфигурации (если вам действительно нужен строго типизированный), который будет читать шаг за шагом конфигурацию и создавать ваш объект FixedPriceExceptionModel, заполненный данными и доступный для использования всем, кто в этом нуждается.

Если я неправильно понял проблему, дайте мне знать.

1 голос
/ 06 июня 2013

Я понимаю, что это очень поздний ответ на уже отвеченный вопрос, но мне удалось это осуществить с помощью элемента codebase .

Пример (вы также можете использовать файл: /// форму URL, если вам нужно):

<configuration>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
             <dependentAssembly>
               <assemblyIdentity name="AssemblyName" publicKeyToken="null" culture="neutral" />
               <codeBase version="1.0.0.0" href="http://server.address.com/AssemblyLocation/AssemblyName.dll"/>
             </dependentAssembly>
          </assemblyBinding>
    </runtime>
</configuration>

Смотрите также:

Указание местоположения сборки

Как во время выполнения обнаруживаются сборки

0 голосов
/ 04 декабря 2009

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

Эта строка кода работает, потому что LoadFrom - это волшебный метод, который ищет определенное место для сборки и любых ее зависимостей. TheApp.exe и его библиотеки DLL загружаются из этого волшебного контекста LoadFrom:

Dim ass = Assembly.LoadFrom("http://www.ourdomain.com/TheApp.exe")

Однако загрузка сборки раздела конфигурации завершается неудачно, поскольку код платформы .NET, который загружает его, использует (предположительно) простой вызов Assembly.Load, который отключен от исходного вызова LoadFrom и не знает www. ourdomain.com. Существуют различные способы получения дополнительных каталогов в пути поиска сборки .NET, но все они относятся к базовому каталогу домена приложения.

Как вы указали, единственный другой способ узнать Assembly.Load о www.ourdomain.com - это изменить базовый каталог домена приложения. В таком случае так ли плохо развертывать NetRun.exe на веб-сервере?

...