Хотя вы можете сделать вызов в делегат, который будет обрабатываться отдельным доменом приложения, я лично всегда использовал метод 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», передавая некоторую информацию о настройке, и завершение метода Run определяется, чтобы указать, что весь код в дочернем домене AppDomain завершил работу, поэтому у нас есть блок, обеспечивающий выгрузку домена приложений.
Вы часто можете быть осторожны с тем, какие типы вы помещаете в какие сборки - вы можете использовать интерфейс и помещать его в отдельную сборку, которая будет как вызывающей (наш код, который устанавливает домен приложения, так и вызывает его). ) и реализатор (класс Runtime) зависят от. Этот IIRC позволяет родительскому домену AppDomain загружать только сборку, содержащую интерфейс, в то время как дочерний домен приложения будет загружать как сборку, содержащую среду выполнения, так и ее зависимость (сборку IRuntime). Любые определяемые пользователем типы, которые используются интерфейсом IRuntime (например, наш класс RuntimeSetupInfo), обычно также должны быть помещены в ту же сборку, что и IRuntime. Кроме того, будьте осторожны с тем, как вы определяете эти пользовательские типы - если они являются объектами передачи данных (как, вероятно, RuntimeSetupInfo), вам, вероятно, следует пометить их атрибутом [serializable], чтобы копия объекта передавалась (сериализовалась родительское приложение для ребенка). Вы хотите избежать перенаправления вызовов из одного домена приложения в другой, так как это довольно медленно. Передача значений DTO по значению (сериализация) означает, что доступ к значениям в DTO не требует межквартирного вызова (поскольку дочерний домен приложения имеет собственную копию оригинала). Конечно, это также означает, что изменения значений не отражаются в исходном DTO родительского домена приложения.
Как закодировано в примере, родительский домен приложения фактически завершит загрузку сборок IRuntime и Runtime, но это потому, что при вызове CreateInstanceAndUnwrap я использую typeof (Runtime), чтобы получить имя сборки и полное имя типа , Вместо этого вы можете жестко закодировать или извлечь эти строки из файла, что бы отделить зависимость.
Существует также метод в AppDomain с именем DoCallBack, который выглядит так, как будто он позволяет вызывать делегата в чужом AppDomain. Однако тип делегата, который он принимает, имеет тип 'CrossAppDomainDelegate'. Определение которого:
public delegate void CrossAppDomainDelegate()
Итак, он не позволит вам передавать в него какие-либо данные. И, поскольку я никогда не использовал его, я не могу сказать вам, есть ли какие-то особые ошибки.
Кроме того, я бы рекомендовал просмотреть свойство LoaderOptimization . То, что вы установили, может оказать существенное влияние на производительность, поскольку некоторые настройки этого свойства заставляют новый домен приложения загружать отдельные копии всех сборок (и их JIT и т. Д.), Даже если (IIRC) сборка находится в GAC ( то есть это включает сборки CLR). Это может дать вам ужасную производительность, если вы используете большое количество сборок из дочернего домена приложения. Например, я использовал WPF из дочерних доменов приложений, что вызывало огромные задержки при запуске моего приложения, пока я не установил более подходящую политику загрузки.