DLL versioning best practices?

  • Thread starter Thread starter Rob Richardson
  • Start date Start date
R

Rob Richardson

Greetings!

I ran into the problem that a DLL could not be copied to the run file
because a newer version existed there. I seem to have gotten around it
temporarily, but I'd like to learn how DLL versioning should be managed. (A
coworker said that .Net replaced "DLL Hell" with "DLL Abyss".)

Here's my situation: I have been asked to take some pieces from a
decent-sized project out and make them into components so that other
projects can use them. I created six components, each one built in a
separate project. I have a solution named "Components" that contains all
six component projects. Some of those components contain references to
others of the components, but there are no circular references. All of the
references have their "Copy Local" property set to True. The main project
contains references to the DLL files located in the bin folders of the
component projects. Those references are also have Copy Local set to
"True".

After the "Dependency could not be copied" errors showed up, I removed all
of the references to the other components from all of my components and
created new ones using the Projects tab in the "Add References" dialog box.
I then deleted all of the files in all of my components' bin directories. I
then opened my main project. I was surprised to see that the DLL folders of
the components projects now had all of the files in them that I had just
deleted!

So, the bottom line is that beyond the bare concept that references are
required so programs will know about the structures of components they would
not otherwise know about, I understand nothing about them. Where can I find
a comprehensive discussion of how to manage references in the .Net world?

Some (but by no means all) specific questions:
1. What is the difference between referencing a project through the .Net
tab and the Projects tab in the "Add References" dialog box, and when would
I prefer using one over the other?
2. I understand from reading newsgroup postings that when looking for
references, C# (or .Net in general) will pull in the first correctly named
DLL it finds, even if that file is not in the folder the user told C# to
look for the DLL in. Why is that permitted?
3. How should I organize my DLLs and references in the project described
above?
4. What steps should I take when updating a component to make sure that
everything that needs to know about the updated version knows about it?

Thanks very much!

Rob Richardson
 
Some (but by no means all) specific questions:
1. What is the difference between referencing a project through the .Net
tab and the Projects tab in the "Add References" dialog box, and when
would
I prefer using one over the other?

When you reference it through the 'projects' tab, it will know that it's
supposed to build that dependent one first, and then copy that version and
use it in the build of the 'client' project. (I believe that's the case,
anyway.)
2. I understand from reading newsgroup postings that when looking for
references, C# (or .Net in general) will pull in the first correctly named
DLL it finds, even if that file is not in the folder the user told C# to
look for the DLL in. Why is that permitted?
3. How should I organize my DLLs and references in the project described
above?
4. What steps should I take when updating a component to make sure that
everything that needs to know about the updated version knows about it?

Recompiling and redeploying all projects that are dependent on it is the
sure fire way to make certain that they will know about it, but there is
always the question of whether you can get away with doing it with less than
that. If you haven't changed the interfaces, and you haven't strong-signed
it, then xcopy deployment should work, as if you overwrite the copy in the
directory of the assembly that uses it with the new version, then the first
place it will look is in the same directory, and will therefore just blindly
pick up the new version without knowing about it. If you *have*
strong-signed it, then it's a whole different kettle of fish. If you signed
the post-update version with the same .snk file that you signed the original
with, *and* it has got the same version number (which it won't have if you
left it at "1.0.*" - because the star means automatically increment based on
the number of half-seconds since a certain time or something), then when the
new version is successfully installed in the GAC, it will replace the old
one. But this is if, and only if, the version number *and* key are the same.
If either or both of them isn't the same, then it'll show up as a different
version in the GAC, and the old (unrecompiled) application will use the old
version it's always used.

What I personally do is to assign each component a test project, which is a
dummy interface just to test the features of the component. This will then
be the only other project in the solution of the component (or maybe there
might be some dependent ones, but they must be closely-linked), and I test
it with that until it is correct w.r.t. its "black box" nature, and then I
do a release build of it, and any other project that wants to use it
references the binary in the release folder. This is good for 3 reasons, (1)
if you have all components in the same solution, recompiling when you have
only made changes to the top level one often causes all of them to be
recompiled, causing components that are going to be GACed to generate new
version numbers, resulting in a whole host of different versions, one new
one each time they are compiled, and a new application's installer will
install a separate copy of an assembly into the GAC where it is actually the
same as the previous one - using my approach, it doesn't get recompiled so
it replaces the existing one, saving space, (2) it actually forces them to
*have* a black box nature, and (3) it makes directory structures slightly
easier and when you want to update a component, you don't have to open up a
project that you don't really want to update.
Although I think that the GAC only really comes into its own when you use
installers properly, like msi, and for really permanent components that you
really don't plan on changing hardly ever.
 
Back
Top