Если вы хотите загрузить тип, который запускается в изолированной программной среде, и получить к нему доступ из основного домена приложения, вам необходимо использовать метод, подобный CreateInstanceFromAndUnwrap . Тип должен быть MarshalByRefObject, чтобы он мог создать прозрачный прокси в вызывающем AppDomain для доступа.
Если основной домен приложений разрешает сборку, он будет загружен в основной домен приложений (а также в домен приложения «песочница»), чтобы в итоге были загружены две копии. Ваш основной AppDomain должен всегда оставаться изолированным от песочницы через прокси, чтобы можно было получить доступ только к MarshalByRefObject и сериализуемым объектам. Обратите внимание, что тип, на который вы ссылаетесь, также не может быть определен в сборке, которую вы хотите загрузить в песочницу; вы захотите определить интерфейсы и, возможно, сериализуемые типы в третьей общей сборке, которая затем будет загружена как в основной, так и в песочницу домены приложений.
Я провел дополнительное копание, и похоже, что все методы для загрузки сборки в другой домен приложений и генерации прокси-сервера требуют разрешения имени сборки. Я не уверен, что в этом случае можно загрузить через byte []; вам может понадобиться сохранить сборку на диск и загрузить ее. Я буду копать немного больше.
Я думаю, что вы можете сделать это (это не проверено, но кажется правдоподобным).
Они должны быть в сборке «интерфейс», доступной как для вашего основного приложения, так и для песочницы (я буду называть это Services.dll):
public interface IMyService
{
//.... service-specific methods you'll be using
}
public interface IStubLoader
{
Object CreateInstanceFromAndUnwrap(byte[] assemblyBytes, string typeName);
}
Следующий класс в StubLoader.dll. Вы не будете ссылаться на эту сборку напрямую; здесь вы будете вызывать первый AppDomain.CreateInstanceFromAndUnwrap, предоставляя его в качестве имени сборки и StubLoader в качестве имени типа.
public sealed class StubLoader: MarshalByRefObject, IStubLoader
{
public object CreateInstanceFromAndUnwrap(byte[] assemblyBytes, string typeName)
{
var assembly = Assembly.Load(assemblyBytes);
return assembly.CreateInstance(typeName);
}
}
Теперь, чтобы использовать его с вашего основного домена приложений, вы делаете это:
//Create transparent proxy for the stub loader, which will live in the sandbox
var stubLoader = (IStubLoader)sandboxDomain.CreateInstanceFromAndUnwrap("Stubloader.dll", "StubLoader");
//Have the stub loader marshal a proxy to a dynamically loaded assembly (via byte[]) where MyService is the type name implementing MarshalByRefObject and IMyService
var myService = (IMyService)stubLoader.CreateInstanceFromAndUnwrap(assemblyBytes, "MyService");
К сожалению, домены приложений не просты в использовании. Это связано с тем, что они обеспечивают высокую степень изоляции и, следовательно, требуют проксирования, чтобы разрешить использование через границы домена приложений.
В ответ на то, как вы могли бы упорядочить не сериализуемый и не-MarshalByRefObject класс, вот примерный пример того, что может быть в DLL общего интерфейса:
public interface ISessionWrapper
{
void DoSomethingWithSession();
}
public sealed class SessionWrapper : MarshalByRefObject, ISessionWrapper
{
private readonly Session _session;
public SessionWrapper(Session session)
{
_session = session;
}
public void DoSomethingWithSession()
{
//Do something with the wrapped session...
//This executes inside the sandbox, even though it can be called (via proxy) from outside the sandbox
}
}
Теперь везде, где ваш исходный сервис должен был работать с Session, он может вместо этого передавать ISessionWrapper, чьи вызовы будут маршалироваться за кулисами, чтобы весь реальный код выполнялся в песочнице реального экземпляра Session, живущего в песочнице.