DynamicProxy and Strong Names

21 views
Skip to first unread message

Fabian Schmied

unread,
Jul 6, 2007, 7:31:26 AM7/6/07
to castle-pro...@googlegroups.com
Hi all,

Today, I made a few changes to the public API of DynamicProxy's
ModuleScope class, and I noticed that DynamicProxy can generate both
assemblies with and without a strong name. Specifically, this is
determined by ClassEmitter's constructor as follows:

bool isAssemblySigned = IsAssemblySigned(baseType);
foreach(Type type in interfaces)
{
isAssemblySigned |= IsAssemblySigned(type);
}

If a type directly inherits from or implements any type from a
strong-named assembly, the generated assembly will get a strong name.
Otherwise, it will not.

My questions are:
- Why exactly is this done that way? Why not simply always sign the
generated assembly? Or never.

- Why do the direct base type and direct interfaces make the base for
the decision? And why in that way? (Actually, I would expect it the
other way around, since strongly named assemblies normally should not
reference ones with weak names.)

Fabian

Ayende Rahien

unread,
Jul 6, 2007, 8:06:06 AM7/6/07
to castle-pro...@googlegroups.com
The reason for strongly naming is that we want to be able to use InternalsVisibleTo on the generated assembly.
The reason that we need to support both strong and weak naming is that we can't rely on the base class/interface to be in a strongly named assembly.

Fabian Schmied

unread,
Jul 6, 2007, 8:22:11 AM7/6/07
to castle-pro...@googlegroups.com
> The reason for strongly naming is that we want to be able to use
> InternalsVisibleTo on the generated assembly.
> The reason that we need to support both strong and weak naming is that we
> can't rely on the base class/interface to be in a strongly named assembly.

Right, I see. But in this case, I think the code is backwards, it
should be &=, not |=? I.e. we can only use a strong name if _all_ the
related types are in strongly named assemblies. Am I missing
something?

Fabian

Ayende Rahien

unread,
Jul 6, 2007, 8:37:52 AM7/6/07
to castle-pro...@googlegroups.com
I am afraid that I don't see the problem

On 7/6/07, Fabian Schmied <fabian....@gmail.com> wrote:

Fabian Schmied

unread,
Jul 6, 2007, 8:49:50 AM7/6/07
to castle-pro...@googlegroups.com
> I am afraid that I don't see the problem

Okay, consider the following:

BaseType => from a signed assembly
Interface => from an unsigned assembly

When we create one proxy deriving from BaseType and implementing
Interface, should this be in an assembly with strong name or should it
not?

I _believe_ it should not, because an assembly with a strong name
shouldn't/mustn't reference an assembly without a strong name.

The code:

bool isAssemblySigned = IsAssemblySigned(baseType);
foreach(Type type in interfaces)
{
isAssemblySigned |= IsAssemblySigned(type);
}

This will however yield isAssemblySigned == true, so DynamicProxy will
create the proxy in a strongly named assembly.

The question is: who is right, DP or me? And if DP, why so.

BTW, it doesn't make any difference as long as we stay in memory. It
does however make a difference when saving and reloading to/from disk,
which I'm currently trying in a project of mine.

Fabian

Ayende Rahien

unread,
Jul 8, 2007, 4:49:43 AM7/8/07
to castle-pro...@googlegroups.com
I think that you way makes more sense, it is valid for the scenario you describe.
Basically, we need to use signed IFF all the items are signed

On 7/6/07, Fabian Schmied <fabian....@gmail.com> wrote:

Fabian Schmied

unread,
Jul 8, 2007, 9:31:16 AM7/8/07
to castle-pro...@googlegroups.com
> I think that you way makes more sense, it is valid for the scenario you
> describe.
> Basically, we need to use signed IFF all the items are signed

Great, then I'll fix it tomorrow, provided nobody has a different
scenario that requires the current behavior.

Fabian

Fabian Schmied

unread,
Jul 9, 2007, 5:04:28 AM7/9/07
to castle-pro...@googlegroups.com
> > Basically, we need to use signed IFF all the items are signed
>
> Great, then I'll fix it tomorrow, provided nobody has a different
> scenario that requires the current behavior.

Done this. However, I had to set the test cases for unsigned types to
[Ignore], as the DynamicProxy.Tests project is currently signed. If
there is no good reason for this, maybe somebody more versed with NAnt
than I am could change that, then the test cases could be run.

Fabian

josh robb

unread,
Jul 9, 2007, 5:57:54 AM7/9/07
to castle-pro...@googlegroups.com
Don't we need to test both cases?

If we don't sign the testing assembly - then how can we test that DP
is working correctly when the target is signed?

j.

Fabian Schmied

unread,
Jul 9, 2007, 6:36:34 AM7/9/07
to castle-pro...@googlegroups.com
> Don't we need to test both cases?
>
> If we don't sign the testing assembly - then how can we test that DP
> is working correctly when the target is signed?

Well, we can easily get types from signed assemblies to test with,
because unsigned assemblies can reference signed ones (for example, I
wrote my test cases for the signed case to use types from mscorlib).

But with the current configuration, we cannot get types from unsigned
assemblies to test with, because signed assemblies cannot reference
unsigned ones.

Fabian

josh robb

unread,
Jul 9, 2007, 6:48:52 AM7/9/07
to castle-pro...@googlegroups.com
Doh - sorry - just read your patch.

Sweet - I'll remove the signing from the test assembly and remove the
ignore from the tests.

j.

On 7/9/07, Fabian Schmied <fabian....@gmail.com> wrote:
>

josh robb

unread,
Jul 10, 2007, 3:04:52 PM7/10/07
to castle-pro...@googlegroups.com
Fabian,

I've just taken a look at this. There are a few problems. I feel like
I've fallen down a rabbit hole - but I'm probably just being stupid.

The magic incantation for disabling signing in
Castle.DynamicProxy.Tests.build is:
<property name="sign" value="false" overwrite="true" />

Doing this opens some issues.

AccessLevelTestCase inherits from BasePEVerifyTestCase which causes
PEVerify to run on the generated assembly. ProtectedConstructor and
ProtectedMethods create their own ProxyGenerator which does not
persist the assembly - which causes RunPEVerifyOnGeneratedAssembly to
fail. I'll send another email about this.

With signing turned off there are 5 test case failures.

1. AccessLevelTestCase.InternalConstructorIsReplicatedWhenInternalsVisibleTo
TypeLoadException : Access is denied:
'Castle.DynamicProxy.Tests.AccessLevelTestCase+InternalClass'
2. BasicClassProxyTestCase.ClassWithDifferentAccessLevelOnProperties
with System.TypeLoadException : Method 'get_Name' on type
'DiffAccessLevelOnPropertiesProxy857179ef4d2641ff949220c77f14861b'
from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null' is overriding a method that is
not visible from that assembly.

3. RhinoMocksTestCase.ProxyingInternalInterface
System.TypeLoadException : Type
'IFooProxy8a308bd02fc141049f334b9b9e2c367b' from assembly
'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null' is attempting to implement an inaccessible
interface.

4. RhinoMocksTestCase.ProxyInternalMethod
System.TypeLoadException : Method 'Foo' on type
'WithInternalMethodProxy6387f2b4cf2e463e99e8bd363679b30b' from
assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null' is overriding a method that is not visible from
that assembly.

5. RhinoMocksTestCase.InternalClassWithInternalMethodAndProperty
System.TypeLoadException : Method 'TestMethod' on type
'InternalClassWithInternalMembersProxya87c370a04ac47da9e76c6f09909e74d'
from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null' is overriding a method that is
not visible from that assembly.

Because [InternalsVisibleTo] doesn't work with unsigned code - this is
the cause of the problems.

Any thoughts? Guess we could create a separate, signed test assembly
for the test cases which test those scenarios. Sounds a little heavy -
but I can't think of a cleaner idea.

j.

Fabian Schmied

unread,
Jul 11, 2007, 3:36:54 AM7/11/07
to castle-pro...@googlegroups.com
Josh,

> I've just taken a look at this. There are a few problems. I feel like
> I've fallen down a rabbit hole - but I'm probably just being stupid.

Right, sorry for letting you fall into this, I should have done more
thorough checking before suggesting to remove the strong name from the
tests assembly.

> AccessLevelTestCase inherits from BasePEVerifyTestCase which causes
> PEVerify to run on the generated assembly. ProtectedConstructor and
> ProtectedMethods create their own ProxyGenerator which does not
> persist the assembly - which causes RunPEVerifyOnGeneratedAssembly to
> fail. I'll send another email about this.

Good catch, we definitely need to do something about this, otherwise
the build sporadically fails when it is made in a clean environment.
But this is an issue unrelated to signing, right?

> With signing turned off there are 5 test case failures.

[...]


> Because [InternalsVisibleTo] doesn't work with unsigned code - this is
> the cause of the problems.

Yes, it's even documented that the attribute can only be applied to
strongly named assemblies, strange that the C# compiler doesn't warn
about this. I didn't notice that at first.

> Any thoughts? Guess we could create a separate, signed test assembly
> for the test cases which test those scenarios. Sounds a little heavy -
> but I can't think of a cleaner idea.

We will probably indeed need two assemblies, at least if we want to
test both [InternalsVisibleTo] and code generation with unsigned
types. Actually, we should even have test cases showing that
DynamicProxy ignores internals when the InternalsVisibleToAttribute is
not present. This is not tested at all ATM.

The signed assembly with [InternalsVisibleTo] doesn't need to be a
test assembly, though, it could be a mere type container. That way, we
could keep the test cases in the unsigned assembly and move the types
whose internals need to be visible to DynamicProxy to a small signed
one. It's still heavyweight, but maybe not as much so as with having
two test assemblies.

The types in question are:
- DiffAccessLevelOnProperties
- InternalClass
- IFoo
- WithInternalMethod
- InternalClassWithInternalMembers

I've checked this (this time I did...) , each of these types is only
used from exactly one test case, so moving them should (hopefully) not
be an issue.

Fabian

josh robb

unread,
Jul 11, 2007, 6:49:47 AM7/11/07
to castle-pro...@googlegroups.com
> Right, sorry for letting you fall into this, I should have done more
> thorough checking before suggesting to remove the strong name from the
> tests assembly.

It's been quite interesting really - I've been meaning to get into DP
for a while. Now I have something useful to do.

> Good catch, we definitely need to do something about this, otherwise
> the build sporadically fails when it is made in a clean environment.
> But this is an issue unrelated to signing, right?

Unrelated. We've got another thread about that so we can ignore it here.

> Yes, it's even documented that the attribute can only be applied to
> strongly named assemblies, strange that the C# compiler doesn't warn
> about this. I didn't notice that at first.

Yep - I guess - it's not really related to compilation - it doesn't
effect the semantics of the code - just the access rights required.

> We will probably indeed need two assemblies, at least if we want to
> test both [InternalsVisibleTo] and code generation with unsigned
> types. Actually, we should even have test cases showing that
> DynamicProxy ignores internals when the InternalsVisibleToAttribute is
> not present. This is not tested at all ATM.

What about building two versions of "Castle.DynamicProxy2.Tests.dll".
Signed and Unsigned. Using NUnit [Category]'s to only run the relevant
tests. This provides comprehensive test coverage for both scenarios.

j.

Fabian Schmied

unread,
Jul 11, 2007, 7:22:04 AM7/11/07
to castle-pro...@googlegroups.com
> > We will probably indeed need two assemblies, at least if we want to
> > test both [InternalsVisibleTo] and code generation with unsigned
> > types. Actually, we should even have test cases showing that
> > DynamicProxy ignores internals when the InternalsVisibleToAttribute is
> > not present. This is not tested at all ATM.
>
> What about building two versions of "Castle.DynamicProxy2.Tests.dll".
> Signed and Unsigned. Using NUnit [Category]'s to only run the relevant
> tests. This provides comprehensive test coverage for both scenarios.

You mean, doing this automatically via the build script? Sounds
interesting (for coverage), but can we also provide a similar
experience from within Visual Studio? Or would VS builds only contain
the unsigned (or only the signed) test cases?

Fabian

josh robb

unread,
Jul 11, 2007, 10:17:23 AM7/11/07
to castle-pro...@googlegroups.com
> You mean, doing this automatically via the build script? Sounds
> interesting (for coverage), but can we also provide a similar
> experience from within Visual Studio? Or would VS builds only contain
> the unsigned (or only the signed) test cases?

Yep - via the nunit build. Not sure about VS - I hadn't really thought
about it. Would be difficult - but not impossible - not sure it's
worth the effort as we only consider nunit builds official.

Kunle Odutola

unread,
Jul 11, 2007, 11:45:03 AM7/11/07
to castle-pro...@googlegroups.com
Hi,

Shouldn't that be Nant vs MSBuild (since we are .NET 2.0-only going forward
- aren't we?)?

I don't think supporting this for VS2003 builds is useful (or justifiable
given resources). With VS2005 builds being essentially MSBuild-at-work, it's
a little more difficult to call...

Kunle

josh robb

unread,
Jul 11, 2007, 1:07:22 PM7/11/07
to castle-pro...@googlegroups.com
> Shouldn't that be Nant vs MSBuild (since we are .NET 2.0-only going forward
> - aren't we?)?

No quite sure I understand where your coming from here.

As far as I'm concerned MsBuild==VS. Our official builds are produced
using nant. As far as I know - our solution/project files are simply
shells to allow us to work in VS.

j.

Kunle Odutola

unread,
Jul 11, 2007, 6:34:52 PM7/11/07
to castle-pro...@googlegroups.com
Hi,

You mentioned nunit in the message I commented on. Anyways, full brain
function has resumed and I understand the preference for Nant given MSBuild
is currently tied to the Windows platform only and Xbuild still has a ways
to go yet...

Kunle

Fabian Schmied

unread,
Jul 12, 2007, 2:52:55 AM7/12/07
to castle-pro...@googlegroups.com

You're right, however I guess many people are developing in VS (at
least I am), so at least the greatest part of the unit tests should be
available in the VS build. Otherwise, adding new features and
refactoring would just be too cumbersome.

Fabian

Reply all
Reply to author
Forward
0 new messages