Which `[InternalsVisibleTo]` for .NET Framework and .NET Standard / Core framework assemblies?
Asked Answered
Z

1

6

I'm having an issue with cross-assembly / friend assembly type visibility.

I have the following program (which I sign / strong-name). It tells Castle DynamicProxy (I'm using version 4.2.1 of the Castle.Core NuGet package) to create a proxy for my interface IFoo. I'm also specifying that my internal class InterfaceProxyBase should be the base class for the proxy type.

DynamicProxy then uses System.Reflection.Emit to create the proxy type. But apparently, System.Reflection.Emit.TypeBuilder does not have access to InterfaceProxyBase.

// [assembly: InternalsVisibleTo("?")]
//                               ^^^
// What do I need here for my program to work both on the .NET Framework 4.5+
// and on .NET Core / .NET Standard 1.3+?

using Castle.DynamicProxy;

class Program
{
    static void Main()
    {
        var generator = new ProxyGenerator();

        var options = new ProxyGenerationOptions
            {
                BaseTypeForInterfaceProxy = typeof(InterfaceProxyBase)  // <--
            };

        var proxy = generator.CreateInterfaceProxyWithoutTarget(
                typeof(IFoo),
                options,
                new Interceptor());
    }
}

public interface IFoo { }

internal abstract class InterfaceProxyBase { }

internal sealed class Interceptor : IInterceptor
{
    public void Intercept(IInvocation invocation) { }
}

Unhandled Exception: System.TypeLoadException: Access is denied: 'InterfaceProxyBase'.
   at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type)
   ...
   at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, ProxyGenerationOptions options, IInterceptor[] interceptors)
   at Program.Main() in Program.cs

So, apparently I need an [assembly: InternalsVisibleTo] attribute for the framework's own assembly / assemblies. My program (a class library, actually) targets both .NET 4.5 and .NET Standard 1.3.

Which [assembly: InternalsVisibleTo] attribute(s) do I need (including the precise public keys) to make my code work for the mentioned platforms / targets?


P.S.: I know that I can circumvent the problem by just making InterfaceProxyBase public and hiding it with [EditorBrowsable(Never)] for appearance's sake, but I really don't want to make this internal type public if I don't have to.

P.P.S.: If making internals public to framework assemblies is a really bad idea, security-wise, please let me know, then I'll happily reconsider my approach.

Zoophilous answered 11/12, 2017 at 20:50 Comment(4)
Cannot you try "Castle.Core"? What's the result?Letishaletitia
@LexLi: That's what I tried first. Making internals visible to Castle.Core doesn't have any noticeable effect. Then I took a look at the stack trace and saw that the exception is triggered by TypeBuilder inside the framework; not by Castle. I would've expected permissions to bubble down from Castle into the framework (those pesky LinkDemand thingies I never really understood), but apparently that's not how it works these days.Zoophilous
Sounds like you need to set to mscorlib for .NET Framework, and System.Reflection.Emit for .NET Core, learn.microsoft.com/en-us/dotnet/api/… But I wonder if Castle offers you a better way. Can you try to check how TypeBuilder is used in Castle (from the exception call stack)? That might give you some hints.Letishaletitia
@LexLi: That might be worth a shot. I've obviously already tried mscorlib, System, System.Core, and System.Reflection.Emit (on .NET Core), the difficulty is knowing which public key(s) to include.Zoophilous
L
6

You should set InternalsVisibleTo for DynamicProxyGenAssembly2:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

DynamicProxyGenAssembly2 is a temporary assembly built by Castle.DynamicProxy. This assembly contains generated proxy type that inherits from your InterfaceProxyBase. That's why DynamicProxyGenAssembly2 should have an access to InterfaceProxyBase type. The possible options are either adding InternalsVisibleTo attribute or making InterfaceProxyBase public.

Laurelaureano answered 22/12, 2017 at 8:41 Comment(2)
Ah... of course! I was under the false impression that it was the framework assemblies failing to access InterfaceProxyBase, when the "access denied" is really triggered by the inheritance relationship between the interface proxy type generated in DynamicProxyGenAssembly2 and InterfaceProxyBase. Could you please add this as a short explanation to your answer, then I'll mark it as the accepted answer.Zoophilous
I have added this note to my answer.Laurelaureano

© 2022 - 2024 — McMap. All rights reserved.