【问题标题】:Castle Windsor InternalsVisibleTo SilverlightCastle Windsor InternalsVisibleTo Silverlight
【发布时间】:2010-11-11 16:11:41
【问题描述】:

我正在使用 Castle Windsor for SL v2.5.1.0。我有它代理内部类(接口当然是公共的,但实现是内部的,所以消费者只知道接口)。

我在我的程序集中使用以下属性和内部类

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

在完整的 .NET 4.0 模式下,使用 .NET 4.0 Castle 程序集,这可以正常工作,并且我的类型可以代理。在 Silverlight 中,通过 Silverlight Castle 程序集,我得到:

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

另外,只是在解决问题时,添加以下内容似乎没有任何区别...:

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

并且我还在运行时验证了 SL 中动态托管的程序集的名称实际上仍然是 DynamicProxyGenAssembly2。

有什么想法吗?谢谢。

编辑

我发现了我认为的问题:

.NET 4.0 的城堡有:

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

}

在 DefaultProxyBuilder...和 ​​SL 4 中有

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

这是可以在城堡源中修复的吗?还是我需要/应该对 DefaultProxyFactory 进行子类化?

【问题讨论】:

    标签: .net silverlight-4.0 castle-windsor castle-dynamicproxy


    【解决方案1】:

    我运气不错。老实说,我不知道为什么,但我无法重现 Krzysztof 描述的问题。我怀疑...也许...这与我的程序集是 SN 的事实有关...这需要我进行额外的更改...但是一旦我这样做了,我就能够解决代理问题用于 SL 测试应用程序中的内部类(带有公共接口)。

    我必须对 Castle.Core 源代码进行的唯一更改是将字段 ModuleScope.moduleBuilderModuleScope.moduleBuilderWithStrongName 设置为受保护而不是私有。但同样,这只是必要的,以便我可以在 SL 中定义一个 SN 的动态程序集,Castle.Core 中的 ModuleScope 为 SL 禁用了该程序集。所以,现在我有一个自定义 ModuleScope 如下:

        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;
            }
        }
    

    还有一个自定义的 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);
            }
        }
    

    还有一个自定义的 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());
            }
        }
    

    以及容器设置:

            container = new WindsorContainer();
    
            container.Kernel.ProxyFactory = new DefaultProxyFactory();
    

    我不太喜欢不得不修改 Castle.Core 源,所以我真的很想听听您的想法 Krzysztof...如果此解决方案不起作用,也许您可​​以保护这些字段其他测试用例?

    【讨论】:

    • 嗯很有趣-所以我想这里的关键区别可能是您使用与您自己的程序集相同的密钥对生成的程序集进行签名,而通常如果 DP 生成强命名程序集,则它使用 Castle 的密钥进行签名。所以我猜测也许规则是,如果 A 有 B 作为朋友并且两者都使用相同的密钥签名,则您可以在组件 B 中使用来自程序集 A 的内部类型。
    • 感谢您对其进行调查 - 将其放入问题跟踪器中,我们将研究为 vNext 烘焙它。
    • 感谢您的快速跟进!
    • 另外,关于您的第一点,可能不是使用相同的密钥具有相关性......而是DP在SL版本中没有自己做任何强签名(它是硬编码的为 ShouldStrongName 或类似的属性设置为 false)...大概是因为 SL 没有 StrongNameKeyPair 类(msdn.microsoft.com/en-us/library/w58ww7se.aspx)...但这并没有阻止我简单地调用 SetPublicKey 并获得一个强命名的动态程序集:) ....这可能就是让事情起作用的原因
    • 我终于有一分钟的时间,并且能够通过在动态程序集上使用与 InternalsVisibleTo 程序集不同的公钥来产生访问被拒绝异常。
    【解决方案2】:

    我可能完全不在这儿,但你不是在找IncludeNonPublicTypes()吗?

    From the documentation:

    注册非公共类型

    默认情况下,只会注册从程序集外部可见的类型。如果要包含非公共类型,则必须先指定程序集,然后调用 IncludeNonPublicTypes

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

    【讨论】:

    • 不,我正在手动进行注册。该类型注册得很好,它只是在代理生成时爆炸(因为上面引用的代码)。
    • 嗯。那我就不知道了。你真的不能公开你的课程:P。
    【解决方案3】:

    原因是 Silverlight 安全模型不允许我们为内部类型构建代理,即使使用 InternalsVisibleTo。

    【讨论】:

    • 那么从设计的角度来看,您建议如何处理这个问题?我真的不希望我的代码的所有内部结构都暴露给消费者……只有接口……谢谢。
    • 有趣的附注...我确实将 DefaultProxyBuilder 从 .NET 4.0 复制到我的代码中,然后使用虚拟 ProxyFactory 制作了我的 Windsor 容器,该虚拟 ProxyFactory 使用引用我的新 DefaultProxyBuilder 的 ProxyGenerator 实例化生成器字段。 ..它适用于我的单元测试!但我想当我尝试在 SL 运行时实际运行它时它不会工作......
    • 是的,它在 Silverlight 安全沙箱中的 Silverlight 上失败了,至少在我运行测试时它失败了。随意尝试一下,如果您找到解决方案,我很乐意将其加入。
    猜你喜欢
    • 1970-01-01
    • 2018-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多