Вопрос по appdomain, delegates, c# – Передать и выполнить делегат в отдельном домене приложений

30

Я хочу, чтобы исключить какой-то кусок кода в отдельном AppDomain с делегатом. Как я могу это сделать?

UPD1: некоторые подробности о моей проблеме. Моя программа обрабатывает некоторые данные (одна итерация: получать данные из БД, оценивать их и создавать сборки во время выполнения, выполнять динамические сборки и записывать результаты в БД).

Текущее решение: каждая итерация выполняется в отдельном потоке. Лучшее решение: каждая итерация выполняется в отдельном домене приложений (для выгрузки динамических сборок).

UPD2: Всем, спасибо за ответы.

Я нашел один для меня в этой теме:Замена Process.Start с доменами приложений

Ваш Ответ

4   ответа
3

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

На самом деле я'Я создаю такой сервис. И я хочу выполнить каждый запрос в отдельном домене. lak-b
Использование именованных каналов, конечно. Will
8

атьSystem.AppDomain.DoCallBack (), Связанная страница MSDN имеет отличный пример. Обратите внимание, что вы можете использовать только делегаты типаCrossAppDomainDelegate.

6

.NET Remoting и конкретно наУдаленные объекты так как это все, что вы можете пройти через AppDomains.

Короче говоря, ваш объект либо переданпо значению или жепо ссылке (через прокси).

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

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

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

Вы уверены, что можете использовать любой делегат? Из того, что я вижу, как упоминалось в моем посте, вы можете использовать только делегат типа 'CrossAppDomainDelegate» Phil
48

который будет обрабатываться отдельным доменом приложений, я лично всегда использовалCreateInstanceAndUnwrap» метод, который создает объект в чужом домене приложения и возвращает ему прокси.

Чтобы это работало, ваш объект должен наследоваться отMarshalByRefObject.

Вот пример:

    public interface IRuntime
    {
        bool Run(RuntimesetupInfo setupInfo);
    }

    // The runtime class derives from MarshalByRefObject, so that a proxy can be returned
    // across an AppDomain boundary.
    public class Runtime : MarshalByRefObject, IRuntime
    {
        public bool Run(RuntimeSetupInfo setupInfo)
        {
            // your code here
        }
    }

    // Sample code follows here to create the appdomain, set startup params
    // for the appdomain, create an object in it, and execute a method
    try
    {
        // Construct and initialize settings for a second AppDomain.
        AppDomainSetup domainSetup = new AppDomainSetup()
        {
            ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
            ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
            ApplicationName = AppDomain.CurrentDomain.SetupInformation.ApplicationName,
            LoaderOptimization = LoaderOptimization.MultiDomainHost
        };

        // Create the child AppDomain used for the service tool at runtime.
        childDomain = AppDomain.CreateDomain(
            "Your Child AppDomain", null, domainSetup);

        // Create an instance of the runtime in the second AppDomain. 
        // A proxy to the object is returned.
        IRuntime runtime = (IRuntime)childDomain.CreateInstanceAndUnwrap(
            typeof(Runtime).Assembly.FullName, typeof(Runtime).FullName);

        // start the runtime.  call will marshal into the child runtime appdomain
        return runtime.Run(setupInfo);
    }
    finally
    {
        // runtime has exited, finish off by unloading the runtime appdomain
        if(childDomain != null) AppDomain.Unload(childDomain);
    }

В приведенном выше примере он закодирован для выполненияБежать' метод передает некоторую информацию о настройке, и завершение метода Run определяется, чтобы указать, что весь код в дочернем AppDomain завершил работу, поэтому у нас есть блок finally, который гарантирует, что AppDomain выгружен.

Вы часто можете быть осторожны с тем, какие типы вы помещаете в какие сборки - вам может понадобиться использовать интерфейс и поместить его в отдельную сборку, которая используется как вызывающей стороной (наш код, который устанавливает домен приложения и вызывает его), так и Реализатор (класс Runtime) зависит от. Этот IIRC позволяет родительскому AppDomain загружать только сборку, содержащую интерфейс, тогда как дочерний appdomain будет загружать как сборку, которая содержит Runtime, так и 'Зависимость (сборка IRuntime). Любые определяемые пользователем типы, которые используются интерфейсом IRuntime (например, наш класс RuntimeSetupInfo), обычно также должны быть помещены в ту же сборку, что и IRuntime. Кроме того, будьте осторожны с тем, как вы определяете эти пользовательские типы - если они являются объектами передачи данных (как, вероятно, RuntimeSetupInfo), вам, вероятно, следует пометить их атрибутом [serializable], чтобы копия объекта передавалась (сериализовалась родительское приложение для ребенка). Вы хотите избежать перенаправления вызовов из одного домена приложения в другой, так как это довольно медленно. Передача DTO по значению (сериализация) означает, что доступ к значениям в DTO нене принимать вызовы между квартирами (так как у дочернего домена естьs собственная копия оригинала). Конечно, это также означает, что изменения значений не отражаются в родительском домене приложения.Оригинальный DTO.

Как показано в примере, родительский домен приложения фактически завершит загрузку сборок IRuntime и Runtime, но это потому, что при вызове CreateInstanceAndUnwrap я использую typeof (Runtime) для получения имени сборки и полного имени типа. Вместо этого вы можете жестко закодировать или извлечь эти строки из файла, что бы отделить зависимость.

На AppDomain также есть метод с именем 'DoCallBack» похоже, это позволяет вызвать делегата в чужом домене приложений. Тем не менее, тип делегата, который он принимает, имеет тип 'CrossAppDomainDelegate», Определение которого:

public delegate void CrossAppDomainDelegate()

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

Также я'рекомендую заглянуть вLoaderOptimization имущество. То, что вы установили, может оказать существенное влияние на производительность, поскольку некоторые настройки этого свойства заставляют новый домен приложения загружать отдельные копии всех сборок (и их JIT и т. Д.), Даже если (IIRC) сборка находится в GAC ( то есть это включает сборки CLR). Это может дать вам ужасную производительность, если вы используете большое количество сборок из дочернего домена приложения. Например, ямы использовали WPF из дочерних доменов приложений, что вызывало огромные задержки при запуске моего приложения, пока я не установил более подходящую политику загрузки.

@Triynko, при создании новой настройки AppDomain попробуйте указать ту же папку bin, что и в главном домене, или, по крайней мере, использовать местоположение, в котором новый домен может получить сборки. Ivaylo Slavov
В моей ситуации процесс Outlook создал два домена приложений, один из которых мой, а другой - от поставщика, с которым я интегрируюсь. Так как я'Я не могу явно создать один из доменов как дочерний для другого. Ваш код все еще выполним? The Muffin Man
Метод CreateInstanceAndUnwrap выдает ошибку, говоря, что не может найти сборку, как указано в (typeof (Runtime) .Assembly.FullName). Это работает на веб-сервере для меня и формат полного имени "myhostdll, версия = 1.0.0.0, культура = нейтральная, PublicKeyToken = ноль ". Triynko

Похожие вопросы