C# loading assemblies dynamically is very slow - c#

I have a Windows services which is written in C# (.NET 3.5) and this service's role is to receive DLLs with a specific interface and execute their methods.
Some clients are complaining that sometimes the service fails to start and after I've looked at our logs I've noticed that the part when trying to load the assemblies dynamically is taking a lot of time (about ~30-40 seconds), so the service gets a timeout after 60 seconds when trying to start.
The major problem here is that this issue does not always occur. We can rarely recreate this slowness in QA Environment so when I'm trying to refactor the code of the dynamic loading I can't really know if I'm solving this issue.
Currently the code is loading 2 DLLs and for each assembly we get all referenced assemblies in order to dynamic load the assembly tree recursively.
I can also see when I'm going recursively on the loading I try to load .NET assemblies like System.Data, System.Core etc, which I obliviously fail because they aren't in my directory. This seems like a major time consuming. Any better suggestions?
/// <summary>
/// Loads all the assemblies and classes needed to run methods dinamically.
/// </summary>
public class BLService
{
public static Dictionary<string, Assembly> AssemblyHistory { get; private set; }
static BLService()
{
// assembly
Assembly assemblyToLoad = LoadAssembly(System.Configuration.ConfigurationManager.AppSettings[settingKey]);
// load assembly dependencies
foreach (var dependencyAssemblyName in assemblyToLoad.GetReferencedAssemblies())
DynamicallyLoadAssembly(dependencyAssemblyName);
}
private static Assembly DynamicallyLoadAssembly(AssemblyName dependencyAssemblyName)
{
LCTracer.Instance.WriteToLog(string.Format("Loading assembly | Trying to dynamically load assembly {0}", dependencyAssemblyName.Name), LCTracer.ProfileAction.Start);
Assembly currentAssembly = LoadAssembly(dependencyAssemblyName.Name);
if (currentAssembly != null)
{
LCTracer.Instance.WriteToLog(string.Format("Loading assembly | Iterating on Assembly {0} references", dependencyAssemblyName.Name));
foreach (var assembly in currentAssembly.GetReferencedAssemblies())
{
DynamicallyLoadAssembly(assembly);
}
LCTracer.Instance.WriteToLog(string.Format("Loading assembly | Finished iterating on Assembly {0} references", dependencyAssemblyName.Name));
}
LCTracer.Instance.WriteToLog(string.Format("Loading assembly"), LCTracer.ProfileAction.End);
return currentAssembly;
}
/// <summary>
/// Loads an assembly
/// </summary>
/// <param name="assemblyName"></param>
/// <returns></returns>
private static Assembly LoadAssembly(string assemblyName)
{
string assembliesDir = System.Configuration.ConfigurationManager.AppSettings["AssemblyPath"];
string assemblyPath = Path.Combine(assembliesDir, assemblyName + ".dll");
// We only load files from inside the designated directory.
if (!File.Exists(assemblyPath))
{
LCTracer.Instance.WriteToLog("Loading assembly | " + assemblyName + " does not exist in path");
return null;
}
byte[] assemblyByteArray = File.ReadAllBytes(assemblyPath);
Assembly asm = null;
try
{
asm = Assembly.Load(assemblyByteArray);
// Load only if already loaded.
if (!AssemblyHistory.ContainsKey(asm.GetName().Name))
{
AssemblyHistory.Add(asm.GetName().Name, asm);
LCTracer.Instance.WriteToLog("Loading assembly | Success: Adding Assembly " + assemblyName + " to history.");
}
}
catch (Exception ex)
{
LCTracer.Instance.WriteToLog("Loading assembly | Error: Adding Assembly " + assemblyName + " failed: message - " + ex.Message + " ,stack trace - " + ex.StackTrace + " ,inner exception - " + ex.InnerException, null, LCTracer.LogDebugLevel.Low);
}
return (asm != null) ? AssemblyHistory[asm.GetName().Name] : AssemblyHistory[assemblyName];
}
}
Edit: Added some code for context. You can think of this service as plugin runner, which gets a plugin and executes it.
Any help will be appreciated.

Try installing Fusion log viewer (comes with Windows SDK) on the complaining clients' servers, and set it to log all load attempts (also successfull).
Then you can see where it si looking for the assemblies - you might find some slow network path there or other problems.
MSDN on Fusion Log Viewer
usefull blog post on using Fusion Log Viewer

I found the solution!
One of the assembly that I try to load was NHibernate.XmlSerializers.dll which is created at runtime if not found and on slow machine this creation was taking a lot of time.
Here is an article of how to pregenerated this dll to improve the performance.
The main command is:
sgen.exe NHibernate.dll /type:NHibernate.Cfg.MappingSchema.HbmMapping /compiler:/keyfile:NHibernate.snk

Related

How to access Fody/Costura embedded libraries at runtime from a different AppDomain

I need to create a new AppDomain for my solution so that I can invoke the method from it's own AppDomain. All of the dependent .dll files for my solution have been embedded into my.exe using Fody/Costura. I have created a Loader : MarshalByRefObject class to invoke my method but when I execute the loader at runtime I get an exception of:
Could not load file or assembly 'my.Assembly, Version=19.1.7242.23931, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
The code is looking for the .dll files in my AppDomain.CurrentDomain.BaseDirectory to execute my method via the loader but they are not there but are embedded in the executable. Is there a way for my new AppDomain to know about the assemblies that have been embedded into my executable without having to load them from the BaseDirectory?
I have looked for ways to load the other assemblies into my new AppDomain but haven't found a way to do it. I also suspect there might be Fody/Costura API to do it but haven't found anything that worked for this scenario.
internal class Loader : MarshalByRefObject
{
object CallInternal(string dll, string typename, string method, object[] parameters)
{
Assembly a = Assembly.LoadFile(dll);
Type t = a.GetType(typename);
MethodInfo m = t.GetMethod(method);
Console.WriteLine("Invoking " + m.Name);
return m.Invoke(null, parameters);
}
public static object Call(string dll, string typename, string method, params object[] parameters)
{
object result = null;
try
{
AppDomain newAppDomain = AppDomain.CreateDomain("myNewDomain", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation);
Loader ld = (Loader)newAppDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(Loader).FullName); //DLL file not found exception thrown from here
result = (Loader)ld.CallInternal(dll, typename, method, parameters);
AppDomain.Unload(newAppDomain);
}
catch (Exception ee)
{
Console.WriteLine("Exception Message [" + ee.Message + "]");
PDFUtil.Report.ErrSilent(ee);
}
return result;
}
}
I am looking to have my Loader class be instantiated without a need to load the .dlls from disk during runtime. Is this possible with Fody/Costura embedded .dlls?
I added my .dlls to my Visual Studio Project and set Build-Action to be Embedded Resource
I am running this bit of code to get the assembly into my new AppDomain:
string resName = null;
foreach (string resourceName in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
Console.WriteLine("Assembly.GetExecutingAssembly().GetManifestResourceNames() [" + resourceName + "] ");
if (resourceName.Contains("my.Assembly"))
{
resName = resourceName;
Console.WriteLine("CurrentDomain Assembly my.Assembly [" + "] Resource name [" + resName + "]");
}
}
Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(resName);
if (s != null)
{
byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);
Assembly a = Assembly.Load(data);
newAppDomain.Load(data);
foreach (Assembly cdAssem in newAppDomain.GetAssemblies())
{
Console.WriteLine("newAppDomain Assembly 2 [" + cdAssem.GetName().FullName + "]");
}
}
I can see that the assembly is part of my new AppDomain:
newAppDomain Assembly 2 [mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
newAppDomain Assembly 2 my.Assembly Version=19.1.7243.19014, Culture=neutral, PublicKeyToken=null]
But using CreateInstanceAndUnwrap() still fails saying it can't find my.Assembly.dll. I am wondering if the only way one can load an assembly into the AppDomain is by loading it from the Base Directory?

Unable to cast object of type XXXXXX to type IXXXXX (.NET 4.0)

Can someone please explain what is happening to me? I have a test project that tests a dummy instance of my service. In the test project, I simply reference the dummyService.exe and System.SystemProcess dll.
In my dummyService project however, I have referenced the class library, which itself uses other dlls from other componentsn as well as other projects in my solution.
The problem is that when I run my test, exceptions get thrown( First Chance exceptions for dlls which are loaded and working in the dummyService), in addition invalidcast exception (error message below).
Unable to cast object of type 'Export.CaseOutputGenerator' to type 'Export.ICaseOutputGenerator'.
System.InvalidCastException was caught
Message=Unable to cast object of type 'Export.CaseOutputProcess.CustomCaseOutputGenerator' to type
'Export.CaseOutputProcess.ICaseOutputGenerator'.
Source=Export.CaseOutputProcess
StackTrace:
at Export.CaseOutputProcess.CaseOutputGeneratoryFactory.GetCaseOutputGeneratorObject(String assemblyName, String className)
in C:\Monitor\Export.CaseOutputProcess\CaseOutputGeneratoryFactory.cs:line 56
at Monitor.BOMock.GenerateCaseOutput(String OutputFolder, String iFile, Int32 seqNum, DataTable CaseSettings, String SettingFileName)
in C:\Monitor\BOMock\BOMock.cs:line 1069
at Monitor.BOMock.Handling() in C:\Monitor\BOMock\BOMock.cs:line 492 InnerException:
public static ICaseOutputGenerator GetCaseOutputGeneratorObject(string assemblyName, string className)
{
ICaseOutputGenerator customeOutputGen = null;
var obj = GetObject(assemblyName, className);
if (obj != null)
caseOutputGen = (ICaseOutputGenerator)obj; // FAILS HERE
return caseOutputGen;
}
private static object GetObject(string fullName, string className)
{
try
{
Type caseOutputGen = null;
var localAssembly = Assembly.LoadFrom(fullName);
foreach (var testType in localAssembly.GetTypes())
{
if (!testType.FullName.EndsWith(className, StringComparison.InvariantCultureIgnoreCase)) continue;
caseOutputGen = testType;
break;
}
if (caseOutputGen == null) return null;
var obj = Activator.CreateInstance(caseOutputGen);
return obj;
}
catch (FileNotFoundException ex)
{
throw new Exception("Failed to load assembly: " + Environment.NewLine + fullName, ex);
}
catch (Exception ex)
{
throw new Exception("Failed to load assembly: " + Environment.NewLine + fullName, ex);
}
}
Where assemblyName is the Path to the dll file to load and className happens to be the name of the class to create an instance of.
In the code, as you see, using reflection I load the assembly at the assemblyName PATH provided (String assemblyName) http://msdn.microsoft.com/en-us/library/system.reflection.assembly.loadfrom.aspx , and then using reflection again, I then create an instance of the className (String className ) contained in the loaded assembly. http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx
How do I remedy this problem please? I don't want to have to reference all my dlls in the test project. How do I get around or solve this problem please?? Thanks in advance.
Based on that stack trace, it looks like the assembly where the type lives is not being found. If you just add the reference to the compiled exe, you're probably not going to get the other libraries along with it. I think you've got a couple of choices:
Go ahead and bite the bullet: add the references to the other libraries in your test project. They're typically not transitive: just because your service knows about them doesn't necessarily follow that your test's assembly knows about them as well.
Add a post-compilation step to your test's project that copies over the other assemblies so that they can be found by the app domain running your test.
Use dependency injection and an inversion of control container. There are quite a few out there, but Castle Windsor, StructureMap and Unity come to mind. Scott Hanselman's got a great list of them on his blog: http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx

AssemblyResolve event fires when calling Assembly.Load(byte())

So I have a WPF project that is pulling in dlls that are used by another project here at my job. It's a mess of dependencies, I've been using the technique here: http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application to embed the dependencies into a single executable.
Now, when I'm calling a specific method inside one of the dependencies, I hit the AssemblyResolve event. My OnResolveAssembly event runs, it finds the assembly as an embedded resource (cool!), and does "return Assembly.Load(assembyRawBytes)". If I hit F11 at this point (with a breakpoint at the beginning of OnResolveAssembly), I get another call into the same event. It's for the same assembly too (args.Name is the same).
If I let this run I hit a stack overflow, since I can never seem to escape this recursive event calling.
The MSDN docs don't really say when Assembly.Load can fail, except with a FileNotFoundException or BadImageFormatException.
I've tried unhooking the OnResolveAssembly at the moment before I call Assembly.Load, but then my application dies a mysterious death, even under VS it just goes poof.
I'm probably breaking several rules here, but some ideas of where to start looking for problems would be welcome.
I'm going to start poking around in the problematic DLL to see if there are hints about what is wrong with it (maybe it's a mixed assembly?).
Here's my OnResolveAssembly handler:
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
string path = assemblyName.Name + ".dll";
if (assemblyName.CultureInfo.Equals(System.Globalization.CultureInfo.InvariantCulture) == false)
{
path = String.Format(#"{0}\{1}", assemblyName.CultureInfo, path);
}
using (Stream stream = executingAssembly.GetManifestResourceStream(path))
{
if (stream == null)
return null;
byte[] assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
assemblyDictionary.Add(assemblyName.Name, Assembly.Load(assemblyRawBytes));
return assemblyDictionary[assemblyName.Name];
}
}
For the time being, I've resolved it by iterating through all of my resources and attempting Assembly.Load on them, and storing them in a dictionary for retrieval (during the OnResolveAssembly event):
[STAThread]
public static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
Assembly executingAssembly = Assembly.GetExecutingAssembly();
string[] resources = executingAssembly.GetManifestResourceNames();
foreach (string resource in resources)
{
if (resource.EndsWith(".dll"))
{
using (Stream stream = executingAssembly.GetManifestResourceStream(resource))
{
if (stream == null)
continue;
byte[] assemblyRawBytes = new byte[stream.Length];
stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
try
{
assemblyDictionary.Add(resource, Assembly.Load(assemblyRawBytes));
}
catch (Exception ex)
{
System.Diagnostics.Debug.Print("Failed to load: " + resource + " Exception: " + ex.Message);
}
}
}
}
App.Main();
}
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly executingAssembly = Assembly.GetExecutingAssembly();
AssemblyName assemblyName = new AssemblyName(args.Name);
string path = assemblyName.Name + ".dll";
if (assemblyDictionary.ContainsKey(path))
{
return assemblyDictionary[path];
}
return null;
}
It seems be working fine now (the "failing" assembly will load fine in my second snippet), but I'd be interested to learn why it doesn't work in the first.
Loading an assembly from byte[] is a good way to end up in .dll hell (the place you go for too many/complex dependencies). Problem here is that although you loaded the dll to an AppDomain it is not automatically resolved, when you need it again for dependent types.
I commented on this problem here: AssemblyResolve Does not fire
Long story short, Assemblies are loaded into different "contexts" inside of AppDomains. The context used by Load(byte[]) does not resolve Assemblies automatically.
The solution is keeping track of the loaded assemblies and returning the already loaded assembly instead of loading it a second time. There is a starting point to this approach in my answer to:
Need to hookup AssemblyResolve event when DisallowApplicationBaseProbing = true
But I think you got it right with your workaround.
BTW. Loading an assembly twice is a way to get identical but incompatible types. Ever cast an object of MyType from MyAssembly into MyType from the very same assembly and got null?
That's a warm "Welcome to .dll hell".

AppDomain.CurrentDomain.AssemblyResolve asking for a <AppName>.resources assembly?

using the code How to embed a satellite assembly into the EXE file provided by csharptest.net, I've created a custom assembly resolver and embedded my assemblies in my resources.
I can successfully resolve my assemblies used in but somehow AppDomain.CurrentDomain.AssemblyResolve asks for an assembly called 'AppName.resources' specifically "MyProgram.resources, Version=0.15.3992.31638, Culture=en-US, PublicKeyToken=null" which i don't know how to resolve?
I've tried to disable loading my custom assemblies from resources (placed all my assembly dll's in program directory) and just enabled AppDomain.CurrentDomain.AssemblyResolve, but it was still asking for it.
I'm a bit confused about this, will appreciate a lot if you can help me on this.
Here's my code for interested ones;
static Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
string name = args.Name.Substring(0, args.Name.IndexOf(','));
if (name == "MyProgram.resources") return null;
else name = string.Format("MyProgram.Resources.Assemblies.{0}.dll", name);
lock (_loadedAssemblies)
{
if (!_loadedAssemblies.TryGetValue(name, out assembly))
{
using (Stream io = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
{
if (io == null)
{
MessageBox.Show("MyProgram can not load one of it's dependencies. Please re-install the program", string.Format("Missing Assembly: {0}", name), MessageBoxButtons.OK, MessageBoxIcon.Error);
Environment.Exit(-1);
}
using (BinaryReader binaryReader = new BinaryReader(io))
{
assembly = Assembly.Load(binaryReader.ReadBytes((int)io.Length));
_loadedAssemblies.Add(name, assembly);
}
}
}
}
return assembly;
}
Answering on my own;
Adding this line to AssemblyInfo.cs solves it and resolver will not get asked for resources any-more.
[assembly: NeutralResourcesLanguageAttribute("en-US", UltimateResourceFallbackLocation.MainAssembly)]
Though this is a work-around should be carefully considered multi-language applications.
More Info:
https://connect.microsoft.com/VisualStudio/feedback/details/526836/wpf-appdomain-assemblyresolve-being-called-when-it-shouldnt
http://blogs.msdn.com/b/kimhamil/archive/2008/11/11/what-does-the-neutralresourceslanguageattribute-do.aspx
http://forums.devshed.com/net-development-87/c-wpf-appdomain-assemblyresolve-being-called-when-it-shouldn-t-669567.html
http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx
This approach fails for machines with non en-US cultures. A better approach is ignoring resources on assembly resolver;
public Assembly Resolver(object sender, ResolveEventArgs args)
{
lock (this)
{
Assembly assembly;
AssemblyName askedAssembly = new AssemblyName(args.Name);
string[] fields = args.Name.Split(',');
string name = fields[0];
string culture = fields[2];
// failing to ignore queries for satellite resource assemblies or using [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)]
// in AssemblyInfo.cs will crash the program on non en-US based system cultures.
if (name.EndsWith(".resources") && !culture.EndsWith("neutral")) return null;
/* the actual assembly resolver */
...
}
}
My situation was a bit more complex and the above solution did not work for me. (That is changing the AssemblyInfo.cs file)
I have moved all my form and image resources to a seperate dll and the moment any of the images are used the 'filenotfoundexception' exception is thrown.
The important information is the following:
Beginning with the .NET Framework 4, the ResolveEventHandler event is raised for all assemblies, including resource assemblies. See the following reference
https://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve(v=vs.110).aspx
The solution turned out to be very simple. If a resource file is requested in the form 'dllname.resources.dll' always return null;
Here is the event code that I have adapted from other samples found. (I have commented the debugging lines - un-comment them if you have a problem using the code.
Add this line in your class. It is used to prevent loading a dll more than once
readonly static Dictionary<string, Assembly> _libs = new Dictionary<string, Assembly>();
This is the event method.
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
string keyName = new AssemblyName(args.Name).Name;
if (keyName.Contains(".resources"))
{
return null; // This line is what fixed the problem
}
if (_libs.ContainsKey(keyName))
{
assembly = _libs[keyName]; // If DLL is loaded then don't load it again just return
return assembly;
}
string dllName = DllResourceName(keyName);
//string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); // Uncomment this line to debug the possible values for dllName
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(dllName))
{
if (stream == null)
{
Debug.Print("Error! Unable to find '" + dllName + "'");
// Uncomment the next lines to show message the moment an assembly is not found. (This will also stop for .Net assemblies
//MessageBox.Show("Error! Unable to find '" + dllName + "'! Application will terminate.");
//Environment.Exit(0);
return null;
}
byte[] buffer = new BinaryReader(stream).ReadBytes((int) stream.Length);
assembly = Assembly.Load(buffer);
_libs[keyName] = assembly;
return assembly;
}
}
private static string DllResourceName(string ddlName)
{
if (ddlName.Contains(".dll") == false) ddlName += ".dll";
foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
if (name.EndsWith(ddlName)) return name;
}
return ddlName;
}

In C#, how do you reference types from one in-memory assembly inside another?

The example program below compiles two in-memory assemblies. The first compilation works fine. The second one fails because it needs access to a class from the first assembly and the type isn't available.
Specifically: The ReferencedAssemblies member of the CompilerParameters class is a string collection and it is used to load the manifests of the assemblies to obtain their types. It appears the C# compiler gets types strictly from the manifest rather than by using reflection (possibly for performance reasons.) In any case, when an assembly is constructed in memory there is no file and no manifest so the second assembly build fails with an error like this:
COMPILER ERROR: Metadata file 'ax5lw0tl, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' could not be found
Adding an AssemblyResolver event handler doesn't work. I tried this and it looks like it isn't ever called. From what I can tell (and I'm a novice with .Net so bear with me) the compiler only cares about the manifest; it's not actually trying to load the assembly at this time, so AssemblyResolver isn't in the picture.
I could, if desperate, construct my assemblies on disk which would solve the immediate problem to have a physical dll and manifest to read. I would much rather not do this as it leads to having to manage what will become a very large collection of temporary assemblies on disk.
I'm optimistic .Net can do this and, being a novice, I'm simply missing it.
(I hope the spacing comes out ok on the code sample. It seems to render properly in the preview window for a few moments but once the syntax highlighter is done it rerenders and the spacing is incorrect although it remains readable.)
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Collections.Generic;
using Microsoft.CSharp;
namespace AsmCompileTest
{
class Program
{
static Assembly Compile( string code, Assembly referencedAssembly )
{
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;
if( null != referencedAssembly )
{
cp.ReferencedAssemblies.Add( referencedAssembly.FullName );
}
CodeDomProvider provider = new CSharpCodeProvider( new Dictionary<string,string> { { "CompilerVersion", "v3.5" } } );
CompilerResults compilerResults = provider.CompileAssemblyFromSource( cp, code );
if( compilerResults.Errors.HasErrors )
{
foreach( CompilerError error in compilerResults.Errors )
{
Console.WriteLine( "COMPILER ERROR: " + error.ErrorText );
}
}
return compilerResults.CompiledAssembly;
}
static string Code1 = "using System;" +
"public class HelloClass" +
" {" +
" public HelloClass() { Console.WriteLine( \"Hello, World!\" ); }" +
" }";
static string Code2 = "using System;" +
"public class TestClass" +
" {" +
" public TestClass() { new HelloClass(); }" +
" }";
static void Main()
{
Assembly asm1 = Compile( Code1, null );
Console.WriteLine( "Compiled: " + asm1.FullName );
asm1.GetType( "HelloClass" ).InvokeMember( String.Empty, BindingFlags.CreateInstance, null, null, null );
Assembly asm2 = Compile( Code2, asm1 );
Console.WriteLine( "Compiled: " + asm2.FullName );
asm2.GetType( "TestClass" ).InvokeMember( String.Empty, BindingFlags.CreateInstance, null, null, null );
}
}
}
Based on documentation found on MSDN and on the code in reflector that I looked at (for the compiler classes) it is not possible to do what you want. The reason is that underneath, the code compiler classes that you are using shell out to the actual compiler.
Also, the code compiler classes are actually generating the temporary files underneath, and based on the code I looked at in reflector, they are not cleaning up the files. So based on that, I would say just generate the file on the disk in a temporary location, and then add reference to it.
Define interfaces in a normal assembly and have classes in each generated assembly implement those interfaces. The generated assemblies will need a reference to the one containing the interfaces, not each other.

Categories