3

I'm having an issue when compiling text into dynamic objects at runtime.

I wrote a simple piece of code to compile the text:

public class CompileFactory
{
    public dynamic Compile(String classCode, String mainClass, Object[] requiredAssemblies)
    {
        CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> 
          { 
             { "CompilerVersion", "v4.0" } 
          });

        CompilerParameters parameters = new CompilerParameters
        {
            GenerateExecutable = true,       // Create a dll
            GenerateInMemory = true,          // Create it in memory
            WarningLevel = 3,                 // Default warning level
            CompilerOptions = "/optimize",    // Optimize code
            TreatWarningsAsErrors = false     // Better be false to avoid break in warnings
        };

        // Add all extra assemblies required
        foreach (var extraAsm in requiredAssemblies)
        {
            parameters.ReferencedAssemblies.Add(extraAsm as string);
        }
        CompilerResults results = provider.CompileAssemblyFromSource(parameters, classCode);
        if (results.Errors.Count != 0)
        {
            return "FAILED";
        }
        return results.CompiledAssembly.CreateInstance(mainClass); ;
    }
}

This is how I am using the Compile method.

List<string> assemblies = new List<string>{"System.Net.Mail.dll", "System.Net.dll"};
dynamic obj = compile.Compile(fileText, pluginName, assemblies.ToArray()); 

As you can see I'm adding references to extra assemblies at some point. For some reason when I add using System.Net; to the text file, it will not be referenced and I get errors. The text I'm compiling is literally a .cs file saved as text. I thought of working around this by extracting the using * and adding them separately, however for when adding System.Net.Mail.dll, the metadata file cannot be found.

Has anyone experienced something similar? I really would like to just add the using * to the file and be ready with it. Any input would be greatly appreciated.

3
  • Can you show how you call Compile? I'd like to see the arguments you pass Commented Jun 22, 2016 at 12:23
  • @PhilippeParé dynamic obj = compile.Compile(fileText, pluginName, assemblies.ToArray()); Assemblies is just a List<string>{"System.Net.Mail.dll", "System.Net.dll"}; Commented Jun 22, 2016 at 12:24
  • You should add this to your post because it is very relevant to your issue, see my answer below Commented Jun 22, 2016 at 12:41

1 Answer 1

2

The issue here is that System.Net.dll does not exist. You can check in which assembly a .Net type is by right clicking somewhere it is referenced and choosing "Go to definition". This will bring up a tab with the class definition "from metadata". At the top of this file, you've got a #region showing where this type comes from. In the case of a TcpClient, we can see this:

#region Assembly System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.dll
#endregion

Change your call to Compile with "System.dll" instead of "System.Net.dll" and it should work just fine

Edit/Clarification: It is not possible to get an assembly name from a using statement.

Sign up to request clarification or add additional context in comments.

25 Comments

you can't find an assembly required only based on a using statement. I recommend you put all the assemblies you need in the references
It isn't clear what you are trying to do. If you need to execute a string of code at runtime, I strongly recommend you know which assemblies are referenced. Especially if you are not the one writing the string of code (a user on a site)
If you are missing a reference in visual studio, you would get a message like The type or namespace name 'MyControl' does not exist in the namespace 'MyNamespace' (are you missing an assembly reference?. If I where you, I would add options for the user to select assemblies to reference. you list them once and present the option to the user. Simpler, safer and easier.
@RobinVanCleef: you'll need to specify references somehow. using statements simply don't contain enough information. Assemblies can be located anywhere, different assemblies can contain the same namespaces, multiple versions of the same assembly can exist... If you're familiar with Linqpad, you'll see that its .linq files contain plain-text code, with a small xml header that contains referenced assembly paths.
You don't need "using". It's the same problem we had earlier, the assembly is system.dll. Just go to ObjectBrowser window in Visual Studio and look for "System.Net.Mail" , if you don't see the assembly full path at the bottom, then go to System.Net and then System.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.