G
GlennDoten
Jon said:I'm not in the habit of saying something is broken when it's not.
Didn't say you were. You seem to assume I don't know how VS works with
key files, yet I'm the one who has been signing all of his assemblies
for seven years now.
Try
the following in VS2005:
1) Create a new project in one directory, e.g. c:\TestProject
2) Create a new key in a different directory, e.g. c:\TestKey
3) Go to the Signing tab of the properties view of the project, tick
"Sign the assembly" and then browse to the key
4) Now look in c:\TestProject - you'll find it's copied the key.
I didn't want it to copy the key, I wanted it to use the location I
browsed to. Otherwise each project has it's own key file, which isn't
what I want.
So, what am I doing wrong with VS?
This is the designed bahavior of VS'05. If you don't want it to copy the
file like that (and this is nothing specific to the key file, all the
files work this way in VS) then you first must make a link to your key
file from within your project. Right-click the project name and select
Add, Existing Item. In the Add Item dialog, browse to the key file,
highlight it, then click the little down arrow in the Add button and
select Add As Link. Notice the newly linked-to file shows up in your
project's root and has a little shortcut icon on it to indicate it is a
link to the original file (it does NOT move the file). You can now
drag-and-drop the file to another folder in your project if you want (I
like to keep them in the Properties folder). *Now* you go to the signing
tab, check Sign the assembly, select the drop-down, and you'll see your
file listed in its original location.
This takes a matter of seconds, is done once per project, and to
continue to insist this is some sort of maintenance issue is completely
misleading readers of this thread.
I've run into the problem where a production assembly being signed
means that a unit test assembly needs to be signed too, if you want to
use InternalsVisibleTo.
I can't reproduce that.
I created three projects:
- A class library called ProductionAssembly
- A class library called RefelctingAssembly
- A console app called SignTest
The ProductionAssembly has no references (except the standard System
ones). The ReflectingAssembly project has a reference to the
ProductionAssembly project. The SignTest project references both the
ProductionAssembly and ReflectingAssembly projects.
ProductionAssembly has a public class called ClassWithAttribute and a
private class called APrivateClass. The assembly is marked with the
InternalsVisibleToAttribute attribute.
ReflectingAssembly has a class called Reflect which does this:
Assembly a = Assembly.LoadFrom("ProductionAssembly.dll");
string fullName = a.FullName;
MethodInfo entry = a.EntryPoint;
object i = a.CreateInstance("APrivateClass");
Type[] types = a.GetExportedTypes();
foreach (Type type in types)
{
Console.WriteLine(type.FullName);
}
None of the projects are signed. Like you pointed out, when I run this
it displays just what I would expect, even though ProductionAssembly is
not signed as the docs seem to indicate it should be.
It is pretty cool that I can also do this in the ReflectingClass project:
object x = new
and IntelliSense shows me the APrivateClass class. If I comment-out the
attribute and/or change the name of the assembly the attribute refers to
then the private class no longer appears in IntelliSense. Pretty cool;
gotta love the VS IDE!
If I sign the ProductionAssembly project and try to compile I get this
error:
Friend assembly reference 'ReflectingAssembly' is invalid. Strong-name
signed assemblies must specify a public key in their InternalsVisibleTo
declarations.
This is completely expected to me because I think this is what the docs
are trying to say: If the assembly containing the attribute is not
signed then it does not need to specify a fully-qualified assembly name
as a parameter to the attribute; if the assembly containing the
attribute is signed then it must specify a fully-qualified assembly name
as a parameter to the attribute.
OK, so I sign the ReflectingAssembly project. Same error as above. As
expected, so I change the attribute parameter from the simple assemble
name "ReflectingAssembly" to this:
[assembly: InternalsVisibleTo("ReflectingAssembly,PublicKey=" +
"002400000480000094000000060200000024000052534131000400000100010059f705c061994e"
+
"5cea0cdb921f714a24deed23ed478364605e436bcde9358d6005294e8b72efc9e86794eb88edd3"
+
"4ca41276ee2b1acd2f81025f059bdea806c6f25237da27573f7eb0abe4c9adde97a694596c9b76"
+
"2213fe0a7cd6d5455edb3262eaf6c69e6ebab4d270ad23bde09a4b1c4419bf3f777da98c2c7935"
+
"392d18f2")]
Now the console app runs just fine again.
So yes, if you have a unit test assembly and it references an assembly
that uses InternalsVisibleTo and the referenced assembly is also signed
then the unit test assembly must also be signed. But that's the whole
intent of how the InternalsVisibleTo attribute. The private members of
an unsigned assembly can be accessed via a friend assembly that is
either signed or unsigned; however, the private members of a signed
assemble cannot be accessed by a friend assembly unless the friend
assembly is also signed.
I can see how the docs can be misleading on this one, perhaps even
downright incorrect.
As I said, the documentation is completely broken. You can either sign
both assemblies, or sign neither of them - but you can't just sign the
production assembly.
Yes, but only in the case of using that attribute. If you are not using
that attribute then the test (or any other assembly) that references a
signed assembly does not itself need to signed.
If you have to sign the unit test assembly, that means you then have to
make sure that everything you reference from the unit test assembly
also has to be signed - including any third party assemnblies etc. The
viral nature of signing strikes again.
Is your point that unit test assemblies require the usage of the
InternalsVisibleTo attribute or something? If so, that's not the case.
You are talking about a fringe case: friend assemblies. Perhaps you use
those a lot; I'm not aware of anyone who does, however.
But even if you were to use InternalsVisibleTo in all your production
assemblies (a strange thing to do, it seems to me) then signing your
unit test assembly is no big deal because it will use precisely the same
assemblies you've already built the production assembly with. Again, no
problem at all.
I really don't want to have to sign third party software - and if I
only have the binaries, it's pretty difficult to do so...
I don't like having to sign third-party assemblies either, but have done
it a few times. It is incredibly simple to do. Disassemble to IL, add
one directive to the top of the file, reassemble the IL. Done. And it
only needs to be done *once*.
I have scripts that do this for me for the rare case a third-party does
not and/or will not sign their assembly. I have not seen this in a long
time. Back in the day (2000-2003 or so) I used assemblies from certain
third-party vendors who didn't understand signing and didn't sign their
assemblies. So I made my own version of their DLL file that was signed.
Problem solved. Nowadays, every third-party vendor I happen to deal with
signs their assembly. It it absolutely not fair for a third-party that
charges money for their product to not sign their assemblies. The two
main reasons are (1) it limits the assemblies I can create and (2) it is
just not good policy for any vendor to ship unsigned assemblies.
(1) is a huge problem. For example, if I need to write an assembly that
must be signed (like for BizTalk consumption) and my assembly has to use
an unsigned vendor's assembly I have *no choice* but to sign their
assembly myself. That is just inexcusable for a vendor to do these days.
Well, silly you for believing the docs when someone who is not prone to
making stuff up has disputed them.
Well silly you for not knowing how Visual Studio works from someone who
has been doing this for seven years!
You'll notice I never said your claim about the docs was wrong. When you
said that I studied the issue and came up with my own test code. The
results are in my last reply as well as above.
If the production assembly is signed, the test assembly has to be too.
If the production assembly isn't signed, the test assembly doesn't have
to be.
Exactly. As I've shown in very precise detail above. I can see what the
docs are trying to say now. They just don't do a very good job, at all.
It's viral in the same way that the GPL is often considered viral - by
applying the property to one thing, it's required for others: if I want
to sign one assembly, I have to sign everything it references *and* any
unit test assemblies which want to reference its internals.
The analogy doesn't hold. Only in the edge case of using
InternalsVisibleTo does this viral claim hold. But then that is the
exact design of InternalsVisibleTo. I can easily see why whoever
designed the attribute made the requirement that if the containing
assembly that uses the attribute is signed then the friend assembly must
also be signed.
But your use of the term viral makes it sounds like you believe signing
an assembly requires any users of the assembly to sign their assembly as
well. And that is just not true. So in all cases *except* when you use
InternalsVisibleTo (and you would not use that in shipping code unless
you signed the assembly anyhow, at least I hope you would) signing an
assembly has no viral aspect to it.
How can doing something be zero effort?
You know exactly what I mean.
How (really, why) are you making it sound oh so time consuming to add a
reference to a key file when you know damn well it takes seconds, which
in any normal developer's book is zero-effort. If you'll admit that this
is extremely simple to do then I'll admit it is not precisely a
zero-effort task.
I've just been upgrading a bunch of projects from 1.1 to 2.0. In each
projects which was signed, in order to avoid warnings I moved the
signing from AssemblyInfo to the properties pane. I then had to
manually edit the project file due to the problem referred to earlier.
Visual Studio is your friend. Let it do it's thing the way it was
designed to. See my description above.
Believe me, this was far from zero effort.
I now understand why you are gun-shy about these key files.
Sounds like you'll get a load of warnings in VS2005, which recommends
setting the key file in the project properties rather than
AssemblyInfo...
This just isn't true. I've updated many projects (solutions) from 03 to
05 with nothing like you mention. Of course, I let VS do all the work
for me; I didn't have to lift a finger. And this is from someone who has
been doing this for seven years, not someone who is making up how VS
studio (doesn't) work.
It does if you have to do it time and time again.
It *doesn't*. To say otherwise is just plain wrong. You add the file
*once* when you create the project and then forget about it.
Customers don't reference our assemblies. (For my open source
libraries, they're welcome to sign it if they want to.)
My question was a hypothetical about using BizTalk and not about open
source libraries. It was also about shipping code (meaning code people
pay for) and not open source libraries. See the difference?
In any event, if I want to sign my assembly (because I have to use
BizTalk, or whatever) how can I use your open source assemblies since
they are not signed? See how not singing makes life difficult for your
assembly users? You claimed above that "it's pretty difficult to do so
[sign a non-signed assembly]". You don't think that's putting an
unnecessary burden on the users of your assembly?
The GAC is a pain in the neck for non-system assemblies, IME. It's
great for framework libraries, but I avoid putting my own ones in
there.
I use the GAC on production systems. It's great for that and makes
assembly management incredibly easy. It sucks for development systems.
The GAC has its place, for system-level assemblies. I can't remember
writing an assembly which I'd classify as system-level.
I'm not sure why you use the moniker system-level. I would say that any
assembly that is sold for money (i.e., is a shipping product) should be
signed, whether or not that product's installer puts it in the GAC
automatically or not.
Strongly-named assemblies have their place too, but it's certainly not
for every assembly IMO.
Please try the simple steps I've shown earlier. I'm really not making
it up about VS copying key files for no reason.
I know. You just got it wrong. It happens!
The strongly-named assembly contains a hash of the data in the
assembly. The obfuscator changes that data - therefore it has to resign
it.
See above. The obfuscator would have to know about the private key in
order to resign the modified assembly.
(Addressed in a previous reply.)
If you find it to be genuinely zero effort, then that's fine - but it's
been a source of annoyance on a number of fronts for me.
I can see that. But give VS a try again regarding this issue. It really
does take care of all the key file stuff and signing stuff for you.
How do you cope with third party components which aren't signed, by the
way?
Yeah, that's what I thought. Those are the assemblies that are a pain in
the butt to deal with.