7
votes

I'm using Castle Windsor for SL v2.5.1.0. I have it proxy internal classes (the interfaces are public of course, but the implementation is internal, so that the consumer is only aware of the interface).

I'm using the following attributes in my assembly with the internal classes

[assembly: InternalsVisibleTo("Castle.Core, PublicKey=002400000480000094000000060200000024000052534131000400000100010077F5E87030DADCCCE6902C6ADAB7A987BD69CB5819991531F560785EACFC89B6FCDDF6BB2A00743A7194E454C0273447FC6EEC36474BA8E5A3823147D214298E4F9A631B1AFEE1A51FFEAE4672D498F14B000E3D321453CDD8AC064DE7E1CF4D222B7E81F54D4FD46725370D702A05B48738CC29D09228F1AA722AE1A9CA02FB")]
[assembly: InternalsVisibleTo("Castle.Windsor, PublicKey=002400000480000094000000060200000024000052534131000400000100010077F5E87030DADCCCE6902C6ADAB7A987BD69CB5819991531F560785EACFC89B6FCDDF6BB2A00743A7194E454C0273447FC6EEC36474BA8E5A3823147D214298E4F9A631B1AFEE1A51FFEAE4672D498F14B000E3D321453CDD8AC064DE7E1CF4D222B7E81F54D4FD46725370D702A05B48738CC29D09228F1AA722AE1A9CA02FB")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

In full .NET 4.0 mode, with the .NET 4.0 Castle assemblies, this works fine and my types are proxied OK. In Silverlight, with the Silverlight Castle assemblies, I get:

Type ConsoleApplication4.MyTypeToBeProxied is not public. Can not create proxy for types that are not accessible.

Also, just in troubleshooting the problem, adding the following seems to make no difference...:

[assembly: InternalsVisibleTo("System.Core, PublicKey=00000000000000000400000000000000")]
[assembly: InternalsVisibleTo("System.Core, PublicKey=" +
"00240000048000009400000006020000002400005253413100040000010001008d56c76f9e8649" +
"383049f383c44be0ec204181822a6c31cf5eb7ef486944d032188ea1d3920763712ccb12d75fb7" +
"7e9811149e6148e5d32fbaab37611c1878ddc19e20ef135d0cb2cff2bfec3d115810c3d9069638" +
"fe4be215dbf795861920e5ab6f7db2e2ceef136ac23d5dd2bf031700aec232f6c6b1c785b4305c" +
"123b37ab")]

and I've also verified at runtime that the name of the dynamically hosted assembly in SL is still in fact DynamicProxyGenAssembly2.

Any ideas? Thanks.

EDIT:

I found the problem I think:

Castle for .NET 4.0 has:

private bool IsAccessible(Type target)
{
  //      ....
  return ((target.IsPublic || target.IsNestedPublic) || internalAndVisibleToDynProxy);

}

in the DefaultProxyBuilder...and SL 4 has

private bool IsAccessible(Type target)
{
    target.IsNested();
    return (target.IsPublic || target.IsNestedPublic);
}

Is this something that can be fixed in the Castle source? Or do I need to/should I sub-class the DefaultProxyFactory?

3

3 Answers

2
votes

I had some luck with this. To be honest, I'm not sure why, but I couldn't reproduce the problem described by Krzysztof. I suspect...maybe...it has something to do with the fact that my assemblies are SN'd...which required me to make an additional change...but once I did, I was able to get proxies resolved for internal classes (with public interfaces) in a SL test application.

The only change I had to make to the Castle.Core source was to make the fields ModuleScope.moduleBuilder and ModuleScope.moduleBuilderWithStrongName protected instead of private. But again, that was only necessary so that I could define a SN'd dynamic assembly in SL, which is disabled for SL by the ModuleScope in Castle.Core. So, now I have a custom ModuleScope as follows:

    private class StrongNameModuleScope : ModuleScope
    {
        public StrongNameModuleScope()
        {
            var assemblyName = new AssemblyName("DynamicProxyGenAssembly2");
            // copied from another one of my SN assemblies (plus GetName() on assembly is security critical so I can't pull it off the executing assembly)
            byte[] publicKey = Convert.FromBase64String(@"ACQAAASAAACUAAAABgIAAAAkAABSU0ExAAQAAAEAAQBvwWquPXQG9zfemS8uDsFdGDScOCSjZ9aFsQDtrrAqKzvlxEGMz3t9Q9M3X9NKqy1ouLZi+sX8yVDafX+UnygFWWfOBosw9nGwG61MTKEhEjdKH0rECahGIXY+ETdNY64HduuH/BIbEs/RDhrrH2hiqGrOGb6AghD1sZ6g0A1qkg==");
            assemblyName.SetPublicKey(publicKey);
            AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
            ModuleBuilder module = assembly.DefineDynamicModule("DynamicProxyGenAssembly2");
            moduleBuilder = module;
            moduleBuilderWithStrongName = module;
        }
    }

And a custom DefaultProxyBuilder:

    /// <summary>
    ///   A custom IProxyBuilder copies from the full .NET Castle implementation that allows for proxies of internal types where the InternalsVisibleToAttribute is applied.
    /// </summary>
    private class DefaultProxyBuilder : IProxyBuilder
    {
       ...
        // Methods
        public DefaultProxyBuilder()
            : this(new StrongNameModuleScope())
        {
        }
       ...
        private static bool IsAccessible(Type target)
        {
            bool isTargetNested = target.IsNested;
            bool isNestedAndInternal = isTargetNested && (target.IsNestedAssembly || target.IsNestedFamORAssem);
            bool internalAndVisibleToDynProxy = ((!target.IsVisible && !isTargetNested) || isNestedAndInternal) && InternalsHelper.IsInternalToDynamicProxy(target.Assembly);
            return ((target.IsPublic || target.IsNestedPublic) || internalAndVisibleToDynProxy);
        }
    }

And a custom DefaultProxyFactory:

  /// <summary>
    ///   A simple DefaultProxyFactory to wrap the modified DefaultProxyBuilder.
    /// </summary>
    private class DefaultProxyFactory : global::Castle.Windsor.Proxy.DefaultProxyFactory
    {
        public DefaultProxyFactory()
        {
            generator = new ProxyGenerator(new DefaultProxyBuilder());
        }
    }

And the container setup:

        container = new WindsorContainer();

        container.Kernel.ProxyFactory = new DefaultProxyFactory();

I'm not so fond of having had to modify the Castle.Core sources, so I'd really like to hear your thoughts Krzysztof...maybe could you just make those fields protected if this solution doesn't work for other test cases?

0
votes

I may be totally off base here, but aren't you looking for IncludeNonPublicTypes()?

From the documentation:

Registering non-public types

By default only types visible from outside of the assembly will be registered. If you want to include non-public types, you have to start with specifying assembly first, and then call IncludeNonPublicTypes

container.Register(
    AllTypes.FromThisAssembly()
        .IncludeNonPublicTypes()
        .BasedOn<NonPublicComponent>()
);
0
votes

The reason for that is that Silverlight security model does not allow us to build a proxy for an internal type, even with InternalsVisibleTo.