views:

175

answers:

2

I'm trying to create an assembly dynamically in .Net. I can't seem to figure out how to get the CodeBase property to return a value, however. Here's an example:

var assemblyName = new AssemblyName
                        {
                            Name = "Whatever",
                            CodeBase = Directory.GetCurrentDirectory()
                        };
var assemblyBuilder = AppDomain.CurrentDomain
    .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("WhateverModule", "Whatever.dll");
var typeBuilder = moduleBuilder.DefineType("WhateverType", TypeAttributes.Public);
var type = typeBuilder.CreateType();
assemblyBuilder.Save("Whatever.dll");
var codeBase = type.Assembly.CodeBase; // throws the below exception

System.NotSupportedException was unhandled
  Message=The invoked member is not supported in a dynamic assembly.
  Source=mscorlib
  StackTrace:
       at System.Reflection.Emit.InternalAssemblyBuilder.get_CodeBase()
       at Stupid.Program.Main(String[] args) in C:\Users\Walking Disaster\Documents\Visual Studio 10\Projects\Lingual.Proxy\Stupid\Program.cs:line 25
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

Can anyone see what I'm doing wrong?

Explanation: I'm trying to extend NUnit with an addin that generates test methods at runtime. It does this by taking an array of Action delegates. Unfortunately, Reflection is baked pretty deep into the framework, so I have had to emit classes with a method for each Action delegate. This works fine when I'm using the NUnitTestMethod classes only, but when I use the NUnitTestFixture, it fails because it tries to read the CodeBase from the assembly. I didn't want to create a physical assembly, but this project has been one compromise after another.

A: 

I think the exception cause is that CodeBase is meaningless on dynamic assembly. From MSDN:

The location of the assembly as specified originally

If you'll reload the assembly it won't throw the exception:

var assemblyName = new AssemblyName
                       {
                           Name = "Whatever",
                           CodeBase = Directory.GetCurrentDirectory()
                       };
var assemblyBuilder = AppDomain.CurrentDomain
    .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(
    "WhateverModule", "Whatever.dll");
var typeBuilder = 
                 moduleBuilder.DefineType("WhateverType", TypeAttributes.Public);
var type = typeBuilder.CreateType();
assemblyBuilder.Save("Whatever.dll");

var assembly = Assembly.LoadFrom("Whatever.dll");
var codeBase = assembly.CodeBase; // this won't throw exception
Elisha
I was fearful of this. I might have to do this to get 'r done, then dig deeper into NUnit to try to limit the damage that their heavy reliance on Reflection is causing.
Michael Meadows
A: 

Is the Assembly's Location valid? Could you fork NUnit and use that instead given your refernece to being damaged :P

I've spent some hours being subjected to NUnit's 'extensibility' story and can't imagine ever choosing it over xUnit.net - but I guess the decider of that will be how many tests you have...

Ruben Bartelink
I'm with you. I can't believe NUnit chose to get all of the test metadata via reflection. Unfortunately, this is for an existing project, and we already have 7K+ NUnit tests. I know xUnit allows you to run NUnit tests, but there's a disincentive to switch this close to the project's completion. I'm looking at porting my work to xUnit, though, for the next project.
Michael Meadows
I guess it's pretty unlikely it'll fit, but have you looked at RunWithNUnitAttribute [which allows you to run NUnit tests via the xunit runner]. Havent seen any examples around it but you'd be surprised how clean and brief the Samples in xunit are (download Samples and look for NUnitRunnerAcceptanceTests) ? (Yes, a very long shot!)
Ruben Bartelink