.NET DLL Hell?

  • Thread starter Thread starter Joshua Frank
  • Start date Start date
J

Joshua Frank

Hi,

Maybe I'm doing something wrong here, but I'm having a very frustrating
time trying to make the VS.NET IDE happy with references. Suppose I
have projects A.exe, B.dll, and C.dll all in one solution. Suppose A
references B and C, and B references C. If I have all projects in one
IDE and I update the references so that all references refer to the
loaded projects, everything's fine. But if I remove one of the
projects, I have to find all the references to it and readd the
reference to the compiled DLL. This is annoying; VB6 let you set binary
compatibility and when you remove the project from the IDE, it
automatically found the right DLL.

But worse than this is that the IDE constantly gets confused about
references. If I do reasonable things like remove project B from the
solution and then recompile project C, all my references get messed up
and I get errors like:

Warning: The dependency 'BIS.Exceptions, Version=1.0.0.27,
Culture=neutral' in project 'BIS.PubsDirect.Cleaner' cannot be copied to
the run directory because it would overwrite the reference
'BIS.Exceptions, Version=1.0.3.3, Culture=neutral'.

I also get this one all the time:

Warning: The dependency 'BIS.PubsDirect.Shared.dll, Version=1.0.0.1,
Culture=neutral' in project 'BIS.PubsDirect.Shared' cannot be copied to
the run directory because it
would overwrite the reference 'BIS.PubsDirect.Shared.dll,
Version=1.0.0.0, Culture=neutral'

When I have add projects, as I often do, the problem increased
exponentially and I wind up recompiling everything in sight all the
time. This sucks.

So the question is, how can I have something like binary compatibility
so that I can build a component (without changing the interface) and
components that use it will continue to work without the IDE
complaining? Note that I'm using well defined version numbers, like
1.2.3.4, and I am updating the build number on every build (via a macro).

Any help would be greatly appreciated as this is making me crazy. Thanks.

Cheers,
Josh
 
When you are making the references in the first place, are you setting
Project References, or are you browsing to the assembly and selecting it
that way?
 
Hi Joshua,

commented inline.
Hi,

Maybe I'm doing something wrong here, but I'm having a very frustrating
time trying to make the VS.NET IDE happy with references. Suppose I
have projects A.exe, B.dll, and C.dll all in one solution. Suppose A
references B and C, and B references C. If I have all projects in one
IDE and I update the references so that all references refer to the
loaded projects, everything's fine. But if I remove one of the
projects, I have to find all the references to it and readd the
reference to the compiled DLL. This is annoying; VB6 let you set binary
compatibility and when you remove the project from the IDE, it
automatically found the right DLL.

But worse than this is that the IDE constantly gets confused about
references. If I do reasonable things like remove project B from the
solution and then recompile project C, all my references get messed up
and I get errors like:

Warning: The dependency 'BIS.Exceptions, Version=1.0.0.27, ==========
Culture=neutral' in project 'BIS.PubsDirect.Cleaner' cannot be copied to
the run directory because it would overwrite the reference
'BIS.Exceptions, Version=1.0.3.3, Culture=neutral'. ========

I also get this one all the time:

Warning: The dependency 'BIS.PubsDirect.Shared.dll, Version=1.0.0.1, =======
Culture=neutral' in project 'BIS.PubsDirect.Shared' cannot be copied to
the run directory because it
would overwrite the reference 'BIS.PubsDirect.Shared.dll,
Version=1.0.0.0, Culture=neutral' ========

When I have add projects, as I often do, the problem increased
exponentially and I wind up recompiling everything in sight all the
time. This sucks.

So the question is, how can I have something like binary compatibility
so that I can build a component (without changing the interface) and
components that use it will continue to work without the IDE
complaining? Note that I'm using well defined version numbers, like
1.2.3.4, and I am updating the build number on every build (via a macro).

I suppose your macro is doing something strange.
Like changing the version *during* a rebuild.
Any help would be greatly appreciated as this is making me crazy. Thanks.

- add references to existing *projects* and not to their output (DLLs)
- don't change files during the rebuild

bye
Rob
 
But worse than this is that the IDE constantly gets confused about
references. If I do reasonable things like remove project B from the
solution and then recompile project C, all my references get messed up
and I get errors like:
I am fighting with the same problem here.

For some reason the copying of the changed dll's goes wrong, it looks like
the project gets build in a incorrect order or something like this.
And when it really gets stuck even when the clean and 'rebuild all' does not
solve it anymore, then I must remove the assemblies from the references and
reload them again.
The references to the assemblies are pointing to other opened projects I
have created.

Another trick that sometimes helps, is I delete all projects release and
debug files of all my projects using a batch file.
The big problem is that the rebuild (C++) takes 10-20 minutes so I lose
development time dramatically.

So in order to speed up development time, I ported some of my code to C#,
because the build is seconds opposed to minutes of C++.
I cannot complain about the .NET itself, it is only VS.NET that gives me a
hard time.
 
One tip that often helps, especially with Joshua's original problem:

When you make a reference to a DLL, you are given a choice: to reference the
DLL that lives in the /bin directory or the DLL that lives in the /obj
directory.

So which one to choose? The dll itself is identical. So why does MS give
you two of them?

Because you would perform the "xcopy deployment" from the /bin directory,
while you should use the contents of the /obj directory for making
references.

Of course, this is not typically explained. However, this is the root cause
of many of these problems.

Solution:
Always, when making a reference to a dll that you compiled in another
project, always, always, always, use the contents of the /obj directory for
your reference.

I am not 100% certain that this is your problem, but it really sounds like
it is. Drop and remake your references.

The reason why this is a problem is a bit complicated. One of these day's,
I'll put a description of it into my blog.

--- Nick
 
One tip that often helps, especially with Joshua's original problem:
...

Because you would perform the "xcopy deployment" from the /bin directory,
while you should use the contents of the /obj directory for making
references.
You are probably right about this, but I have a mixture of C++ with C#
projects in my solution, and C++ does not have a bin or obj folder, but
something like Debug and Release..

Another issue is that I do not get this choice you are refering to as obj or
bin. I right click on the references, get this dialog box "add reference"
where you can select between .NET, COM and Projects, So I select Projects,
and then I select the project I want the reference to point to and press OK.
So I guess that VS.NET is intelligent enough to take the dll in the obj
folder instead of the bin folder? But it is here that I get this version
problem.

Anoher big issue (probably related to this) is that if I create a Visual
control in one project, than use it on a form in another project, this
control just dissapear, from my form. I always have to put it back manually.
Very anoying so far.
 
Thanks for the replies. I don't think these suggestions get at the
problem though. When the other project is in the IDE, I always
reference that project, not the DLL on disk. If you do this and look at
the reference properties, it shows the reference to the obj file, not
the bin.

Also, the macro doesn't do anything to the disk file. It just looks in
the AssemblyInfo.vb file and increments the build number.

I'm starting to think that the real problem is that what I want to do
doesn't make complete sense. Suppose we have the versions:
A,1.2.3.4
B,2.3.4.5
C,3.4.5.6

Again suppose A uses B and C, and B uses C. So A goes in the bin
directory and B and C are copied there as well. If I rebuild C and the
new version 3.4.5.7 overwrites the old one, then the version of C that B
was using is gone, so of course this could cause a problem. At runtime
..NET seems to be smart enough to get B to use the new version of C
(unless something important in C was deleted, which is reasonable), but
at design time I get all these warnings and errors.

I wonder if it would work to make the following directory structure for A:

A
\bin
\B
\2.3.4.5\B.dll
\C
\3.4.5.6\C.dll
\3.4.5.7\C.dll

turn Copy Local to False, deploy all versions beneath the bin directory
in this way, and let .NET probe to find the guaranteed correct dll.

Or alternatively, I could rename each DLL appropriately: compile B.dll
and use a post-build macro to rename it to B.2.3.4.5.dll and use that.

I gather this is basically the purpose of the GAC, but I really want to
maintain xcopy deployment by not using any systemwide resources.


What do people think?

Cheers,
Josh
 
I get the control disappearing problem, but I think you can usually get
by without recreating it. Since the control is persisted right in code,
you'll have some line like:

Dim WithEvents ctlExample As Library.Control
....
ctlExample = New Library.Control
....
Form.Controls.Add(ctlExample)

But when the reference is lost, these lines start giving compile errors
and the control doesn't show up in the designer. But usually I find
that when you get the references sorted out, the errors go away and the
control reappears. But if you open the designer and save it, it
regenerates the hidden code and you can lose the code for objects that
it can't load. So the important thing is to get the references sorted
out *before* doing anything in the designer. I've had this work pretty
reliably since I realized it. Hope that helps.

Cheers,
Josh
 
Hi Joshua,
Again suppose A uses B and C, and B uses C. So A goes in the bin
directory and B and C are copied there as well. If I rebuild C and the
new version 3.4.5.7 overwrites the old one, then the version of C that B
was using is gone, so of course this could cause a problem.

The VS environment would then recompile B, which would find the new version
of C. It would do this because you have project references. So there is no
need for your complicated "directory structure with version number"
solution.

Personally, if I were maintaining an app with such a structure for building
the app, I'd spend a week up front fixing the problem before going any
further.

Take it from someone who maintains apps... I'd rather you fix the problem
than work around it in a way that someone like me cannot use.

There's a problem here that can be fixed. Working around it rather than
fixing it is not preferable.
I know that you are trying to minimize the issue by using symbolics, but I
wonder, is there another layer to your dependencies? Does C depend on a dll
that A or B also depend upon... something that is outside the project? If
so, are they all referring to the same DLL?

--- Nick
 
Perhaps I wasn't as clear as I should have been. VS would only
recompile B if B was loaded in the solution. But the problem happens
when you remove B because you're not working on it any further (at the
moment anyway). So then you reference the fixed B.dll file. But then
when you change the code in project C, it gets recompiled and overwrites
the previous version. But now the version of C that B was expecting
isn't there, and the IDE complains about this as I described. I'm
*trying* to fix the DLL reference problem up front; that's why I started
this thread.
 
You need NANT.

You would provide the fixed dependencies in NANT and when you recompile C,
and call NANT, it would recompile both A and B, in the proper order, and
your problem goes away.

--- Nick
 
Back
Top