Как я могу использовать CodeDOM для создания и загрузки сборки в домене приложения?
Я работаю над проектом, который будет использовать CodeDOM для создания класса, который вычисляет пользовательское выражение, создает сборку для класса и загружает сборку. Поскольку существует достаточное количество определяемых пользователем выражений, я хотел бы сначала создать домен приложения, выполнить создание/загрузку и выполнение CodeDOM для сборки в этом домене приложения, а затем выгрузить домен приложения.
Я искал довольно много и нашел много примеров того, как загрузить существующий файл. сборка в домен приложения, но я не могу найти тот, который показывает мне, как создать сборку из внутри домена приложения.
Этот пример ( DynamicCode) создает сборку с помощью CodeDOM, а затем загружает ее в домен приложения, однако автор генерирует сборку на диск. Я бы предпочел создать сборку в памяти, чтобы мне не приходилось управлять очисткой созданных сборок. (хотя это и создает а .dll в темпе папка).
Может ли кто-нибудь указать мне пример того, как это сделать? Любая помощь будет весьма признательна.Я включил некоторые выдержки из моего кода, чтобы вы все могли почувствовать, что у меня есть до сих пор:
private string CreateSource()
{
CodeCompileUnit codeUnit = new CodeCompileUnit();
CodeNamespace codeNamespace = new CodeNamespace(Namespace);
CodeTypeDeclaration codeClass = new CodeTypeDeclaration
{
Name = "ExpressionEvaluator",
IsClass = true,
TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed
};
codeNamespace.Types.Add(codeClass);
codeUnit.Namespaces.Add(codeNamespace);
AddMethods(codeClass);
string result = GenerateSourceCode(codeUnit);
return result.ToString();
}
private CompilerResults CompileSource(string source)
{
using (CodeDomProvider provider = new CSharpCodeProvider())
{
CompilerParameters parameters = CreateCompilerParameters();
CompilerResults result = CompileCode(provider, parameters, source);
return result;
}
}
private static CompilerParameters CreateCompilerParameters()
{
CompilerParameters result = new CompilerParameters
{
CompilerOptions = "/target:library",
GenerateExecutable = false,
GenerateInMemory = true
};
result.ReferencedAssemblies.Add("System.dll");
return result;
}
private object RunEvaluator(CompilerResults compilerResults)
{
object result = null;
Assembly assembly = compilerResults.CompiledAssembly;
if (assembly != null)
{
string className = "ExpressionEvaluator";
object instance = assembly.CreateInstance("Lab.ExpressionEvaluator");
Module[] modules = assembly.GetModules(false);
Type type = (from t in modules[0].GetTypes()
where t.Name == className
select t).FirstOrDefault();
MethodInfo method = (from m in type.GetMethods()
where m.Name == "Evaluate"
select m).FirstOrDefault();
result = method.Invoke(instance, null);
}
else
{
throw new Exception("Unable to load Evaluator assembly");
}
return result;
}
Я считаю, что эти фрагменты кода показывают основные функциональные возможности моего проекта. Теперь все, что мне нужно сделать, это обернуть его в свой собственный домен приложений.
4 ответа:
Проблема курицы и яйца. Вам нужна небольшая сборка загрузчика, которую вы можете загрузить в новом домене приложения. С хорошо известным классом, который загружает сгенерированную CodeDom сборку и запускает ее.
Делать это с GenerateInMemory довольно бессмысленно, вам придется сериализовать это в новый домен приложения. Это просто куча накладных расходов, с таким же успехом можно загрузить его с диска, он все равно есть. И это уже в памяти. Память кэша файловой системы. Загрузка его будет очень быстро, так как на самом деле его не нужно считывать с диска.
Я нашел ответ, который искал в http://www.softwareinteractions.com/blog/2010/2/7/loading-and-unloading-net-assemblies.htmlу него есть хорошая статья, подробно описывающая создание домена приложения и загрузку сборки в качестве плагина. Я последовал его примеру и смог создать домен приложения, создать прокси для моей фабрики классов ExpressionEvaluator и успешно вызвать его и получить результаты.
Просто используйте
AssemblyBuilderAccess.Run
, когда вы определяете динамическую сборку http://msdn.microsoft.com/en-us/library/system.reflection.emit.assemblybuilderaccess.aspxДинамическая сборка может быть выполнена, но не сохранена.