Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading an assembly generated by the Roslyn compiler

I'm generating a Greeter.dll using the Roslyn compiler. My problem occurs trying to load the DLL file.

Here's the code:

using System;

using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;

using System.IO;
using System.Reflection;
using System.Linq;

namespace LoadingAClass
{
    class Program
    {
        static void Main(string[] args)
        {
            var syntaxTree = SyntaxTree.ParseCompilationUnit(@"
class Greeter
{
    static void Greet()
    {
        Console.WriteLine(""Hello, World"");
    }
}");

            var compilation = Compilation.Create("Greeter.dll",
                syntaxTrees: new[] { syntaxTree },
                references: new[] {
                    new AssemblyFileReference(typeof(object).Assembly.Location),
                    new AssemblyFileReference(typeof(Enumerable).Assembly.Location),
                });

            Assembly assembly;
            using (var file = new FileStream("Greeter.dll", FileMode.Create))
            {
                EmitResult result = compilation.Emit(file);
            }

            assembly = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), @"Greeter.dll"));
            Type type = assembly.GetType("Greeter");
            var obj = Activator.CreateInstance(type);

            type.InvokeMember("Greet",
                BindingFlags.Default | BindingFlags.InvokeMethod,
                null,
                obj,
                null);

            Console.WriteLine("<ENTER> to continue");
            Console.ReadLine();

        }
    }
    // Thanks, http://blogs.msdn.com/b/csharpfaq/archive/2011/11/23/using-the-roslyn-symbol-api.aspx
}

The error message occurs on the line assembly = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), @"Greeter.dll")); and reads

Im Modul wurde ein Assemblymanifest erwartet. (Ausnahme von HRESULT: 0x80131018)

Which roughly translates to

An assembly manifest was expected in the module.

Does anyone know what I'm missing here?

like image 549
lowerkey Avatar asked May 25 '12 08:05

lowerkey


People also ask

Is Roslyn a compiler?

NET Compiler Platform, also known by its codename Roslyn, is a set of open-source compilers and code analysis APIs for C# and Visual Basic (VB.NET) languages from Microsoft.

How Roslyn works?

Roslyn is a collection of open-source compilers, code analysis and refactoring tools which work with C# and Visual Basic source codes. This set of compilers and tools can be used to create full-fledged compilers, including, first and foremost, source code analysis tools.

What is Roslyn in asp net?

Roslyn is a complete rewrite of the C# and VB.net compilers with each written in their respective language for example the C# compiler is written in C# rather than C++. Roslyn is open source (Roslyn on GitHub) so you could even theoretically create your own version of C# or VB.net!

Is a compiler platform for .NET core?

Roslyn, the . NET Compiler Platform, empowers the C# compiler on . NET Core and allows developers to leverage the rich code analysis APIs to perform code generation, analysis and compilation.


2 Answers

I stumbled across this and, even though you have an accepted answer, I don't think it's helpful in general. So, I'll just leave this here for future searchers like myself.

The problem with the code is two things, which you would have found out by looking at the returned value from

EmitResult result = compilation.Emit(file);

If you look at the properties on the EmitResult object, you would have found that there were 2 errors in the results.Diagnostics member.

  1. Main method not found
  2. Couldn't find class Console

So, to fix the problem, 1. You need to mark the output as a dll 2. You need to add 'using System;' to the code you're passing into the API or say 'System.Console.WriteLine'

The following code works making changes to fix those two issues:

        var outputFile = "Greeter.dll";
        var syntaxTree = SyntaxTree.ParseCompilationUnit(@"
 // ADDED THE FOLLOWING LINE
using System;

class Greeter
{
    public void Greet()
    {
        Console.WriteLine(""Hello, World"");
    }
}");
        var compilation = Compilation.Create(outputFile,
            syntaxTrees: new[] { syntaxTree },
            references: new[] {
                new AssemblyFileReference(typeof(object).Assembly.Location),
                new AssemblyFileReference(typeof(Enumerable).Assembly.Location),
            },

// ADDED THE FOLLOWING LINE
            options: new CompilationOptions(OutputKind.DynamicallyLinkedLibrary));

        using (var file = new FileStream(outputFile, FileMode.Create))
        {
            EmitResult result = compilation.Emit(file);
        }

        Assembly assembly = Assembly.LoadFrom("Greeter.dll");

        Type type = assembly.GetType("Greeter");
        var obj = Activator.CreateInstance(type);

        type.InvokeMember("Greet",
            BindingFlags.Default | BindingFlags.InvokeMethod,
            null,
            obj,
            null);

        Console.WriteLine("<ENTER> to continue");
        Console.ReadLine();
like image 65
Sef Avatar answered Oct 20 '22 07:10

Sef


I have been adding Roslyn support to the O2 Plarform and here is how you can use its Roslyn support to compile (code), create (and assembly) and invoke (its method) one line of code:

return @"using System; class Greeter { static string Greet() {  return ""Another hello!!""; }}"
        .tree().compiler("Great").create_Assembly().type("Greeter").invokeStatic("Greet"); 

//O2Ref:O2_FluentSharp_Roslyn.dll

Here is a version that executes a code snippet that looks like yours (I added a return value):

panel.clear().add_ConsoleOut();
var code = @"
using System;
class Greeter
{
    static string Greet()
    { 
        Console.WriteLine(""Hello, World""); 
        return ""hello from here"";
    }
}";
var tree = code.astTree();
if (tree.hasErrors())
    return tree.errors();   

var compiler = tree.compiler("Great")
                   .add_Reference("mscorlib");

if (compiler.hasErrors()) 
    return compiler.errors();    

var assembly  =tree.compiler("Great")
                   .create_Assembly();

return assembly.type("Greeter")
               .invokeStatic("Greet"); 

//O2Ref:O2_FluentSharp_Roslyn.dll
//O2File:_Extra_methods_Roslyn_API.cs
//O2File:API_ConsoleOut.cs

For a couple more details and screenshots of what this looks like, see this blog post: 1 line to compile, create and execute: O2 Script to use Roslyn to Dynamically compile and execute a method

UPDATE: see http://blog.diniscruz.com/search/label/Roslyn for a large number number of Roslyn related posts and tools (created using the O2 Platform)

like image 32
Dinis Cruz Avatar answered Oct 20 '22 07:10

Dinis Cruz