Skip to content

ModuleScope.SaveAssembly produces incorrect / incomplete assemblies when proxying types from a weak-named assembly #327

@stakx

Description

@stakx

TL;DR: I am either misunderstanding how ModuleScope.SaveAssembly works, or DynamicProxy — when it produces proxies for types in weak-named assemblies — puts generated proxy types in a weak-named module and proxy method invocation types in a strong-named module, resulting in failure or incomplete output by ModuleScope.SaveAssembly.

The generated assemblies mentioned below can be found in CastleDynProxy2_strong_and_weak.zip.

Saving with ModuleScope.SaveAssembly(strongNamed: false)

Suppose I'm trying to save the dynamic assembly generated by DynamicProxy as follows:

using Castle.DynamicProxy;

public interface IFoo
{
    void Method();
}

public abstract class Bar
{
    public abstract void Method();
}

class Program
{
    public static void Main()
    {
        var proxyGenerator = new ProxyGenerator(new PersistentProxyBuilder());
        var foo = proxyGenerator.CreateInterfaceProxyWithoutTarget<IFoo>();
        var bar = proxyGenerator.CreateClassProxy<Bar>();
        proxyGenerator.ProxyBuilder.ModuleScope.SaveAssembly(strongNamed: false);
    }
}

Note that I am not strong-naming the assembly containing above code—if I did, then everything would work as expected.

This generates an assembly CastleDynProxy2, which appears to have two problems:

  1. It is missing types Castle.Proxies.Invocations.IFoo_Method and Castle.Proxies.Invocations.Bar_Method. PEVerify is a bit cryptic about it, but seems to tell me the same thing:

    [IL]: Error: [C:\...\CastleDynProxy2.dll : Castle.Proxies.IFooProxy::Method]
    [HRESULT 0x80070002] - The system cannot find the file specified.
    
    [IL]: Error: [C:\...\CastleDynProxy2.dll : Castle.Proxies.BarProxy::Method
    [HRESULT 0x80070002] - The system cannot find the file specified.
    
    2 Error(s) Verifying CastleDynProxy2.dll
    
  2. There is an assembly reference to a strong-named DynamicProxyGenAssembly2, which is confusing, because the generated assembly already has the exact same name (except for being weak-named).

If I try to run code that references and uses the CastleDynProxy2.dll as produced above, I will get a FileNotFoundException (perhaps due to the second issue above):

class Program
{
    static void Main()
    {
        var bar = new BarProxy();
    }
}
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
   at Program.Main()

Saving with ModuleScope.SaveAssembly(strongNamed: true)

When I change the last line of the original program (at the top) to:

        proxyGenerator.ProxyBuilder.ModuleScope.SaveAssembly(strongNamed: true);
        //                                                                ^^^^

and inspect the generated assembly CastleDynProxy2.dll (which is now strong-named), I see this:

  1. The assembly has the invocation types Castle.Proxies.Invocations.IFoo_Method and Castle.Proxies.Invocations.Bar_Method, but it is missing the proxy types Castle.Proxies.IFooProxy and Castle.Proxies.BarProxy.

Saving with ModuleScope.SaveAssembly()

If I try to save the assembly without specifying strongNamed: false, nor strongNamed: true, I get an exception right away:

Unhandled Exception: System.InvalidOperationException: Both a strong-named and a weak-named assembly have been generated.
   at Castle.DynamicProxy.ModuleScope.SaveAssembly()
   at Program.Main() in ...\Program.cs:line 20

Possible conclusions

  • I am making a beginner mistake (hinted at by the last exception shown just above). What I don't understand in this case is, how would I let DynamicProxy save a correct, weak-named dynamic assembly referencing types IFoo, Bar from my own weak-named assembly? SaveAssembly(strongNamed: false) doesn't seem to do the trick.

  • When generating proxies for types in weak-named assemblies, DynamicProxy puts the proxy types in a weak-named assembly and the invocation types in a strong-named assembly. Therefore it will only be able to save either of those at a time, but fails to save both. This results in incomplete output assembly either way.

What is going wrong here?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions