.NET versioning

.NET versioning

Post by harvey.kwo » Sat, 03 Dec 2005 07:33:01

Hi all,

We have delivered a product with version to our customers.
This product includes product.exe and library.dll. Then, the
development is continued. Now, we are at the version of We
are not ready to ship this version to our customers but we have started
another product called tools.exe which also need the assembly
library.dll. We want to ship tools.exe to our customer. However, as
the library.dll is too large, we want to just ship the tools.exe with
version only. Customers can install tools.exe only if they
have product.exe and library.dll installed and the tools.exe will only
be installed in the same folder as product.exe.

As I build my tools.exe with library.dll v2.0.0.77, if customer just
installs tools.exe, it cannot find the correct library. Is there any
way to let my tools.exe always loading the library.dll on the same
folder regardless what its version is?

Thanks in advance.

- harvey

.NET versioning

Post by Frans Boum » Sat, 03 Dec 2005 18:59:58

Yes, that's called a policy file. Please check the .NET documentation
about policy files. Basicly it comes down to you define a policy dll
with a xml file which is installed in the GAC and which redirects calls
from one version to the other.

You have to consider a couple of other options as well. I have the
feeling that and are functionally the same and have
the same interfaces, correct? It's just that doesn't contain
bugfixes which are present in ?

If that's the case, you could try to use assembly FILE versions
instead. This is also the technique Microsoft uses for hotfixes and
service packs on .NET: the version is the same ( but the file
version value in the assemblyfileversion attribute changes. You can
install a file with a newer FILE version in the GAC even if it has the
same assembly version.

The advantage is of course that if you have a bugfix release, you can
simply hand out a new build, and no recompiles have to take place nor
do you have to update policy files.


Get LLBLGen Pro, productive O/R mapping for .NET: http://www.yqcomputer.com/
My .NET blog: http://www.yqcomputer.com/
Microsoft MVP (C#)


.NET versioning

Post by harvey.kwo » Sun, 04 Dec 2005 04:40:30

Thanks Frans,

You are correct. includes some bug fixes but the interface is
the same as I have tried policy file actually. The problem
now is that

1) My supervisor doesn't want to release the library.dll v2.0.0.77. He
just wants to release tools.exe v2.0.0.77 and he thinks we should be
able to whatever library.dll installed on the customer's machine.

2) If I use policy file, I need to redirect them to use
explicitly. The problem is some of our customers are actually using

I know it is a mess. Is there any way telling .NET to forget version

- HK

.NET versioning

Post by Frans Boum » Sun, 04 Dec 2005 21:16:35

What people want is sometimes not relevant. If he wants X but X is
impossible, he can keep on wanting X but if that's impossible, it will
never happen.

If tools.exe v2.0.0.77 references library.dll v2.0.0.77, he can
release tools.exe v77 but that will never run on systems with
library.dll v66.

Your policy file should simply do something like:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity name="library"
<bindingRedirect oldVersion=""

so all references to versions below v77 will be redirect to use dll

So application.exe v66 which references dll version 66 will then use
dll v77 without problems. No recompile needed :)


Get LLBLGen Pro, productive O/R mapping for .NET: http://www.yqcomputer.com/
My .NET blog: http://www.yqcomputer.com/
Microsoft MVP (C#)

.NET versioning

Post by Richard Gr » Mon, 05 Dec 2005 05:12:58

This will work with hotfixes, because Microsoft know what they are
doing, and anyway, they control the operating system. You *should not*
do this yourself because it is a return to Win32 DLL Hell.

The reason is that the new version will overwrite the old version. The
GAC recognises *only* the .NET version, not the version in the
VERSIONINFO unmanaged resource, so gacutil just thinks you are inserting
the same assembly into the GAC and hence it overwrites what's there.
(When you use gacutil it will put the file in a special folder with a
name constructed line this: <.net version>_<culture>_<publickeytoken>
and since these will be the same for both versions, the later one will
over write the former.)

So you have two assemblies installed into the GAC and two uninstall
processes, and yet there is only one physical file in the GAC. This
means that after the first uninstall has been run *all* applications
that remain that use this library will stop working. You can get around
this issue with GAC references.

However, since this is just DLL Hell being applied to .NET, I would
recommend that this 'solution' should not be used.

Versioning Workshop http://www.yqcomputer.com/
Security Workshop http://www.yqcomputer.com/

.NET versioning

Post by Frans Boum » Mon, 05 Dec 2005 20:34:50

ichard Grimes wrote:

Isn't that the intention? You have version and you have a
bugfix release. So you release a new version of the dll, same assembly
version. You copy the file into the gac, it overwrites the old one and
all your apps using the version use now the bugfixes.

I said 'bugfixes' thus not new features.

No install processes, you copy the files.

Uninstalling indeed removes the file, but that's not the point here.
The point is that with a bugfix you otherwise have to produce policy
files and / or recompiles.

That's great but what's your 'solution' then? It's always nice to see
people saying "I Don't recomment this!!" and at the same time they
don't have an answer to the question: what to do instead?

Because if you sign your assemblies, and you simply use buildnumbers
for bugfixes, you have to use policy files to be sure everything keeps
on working, OR Recompile everything else.

policy files require an installer, while with fileversions you can
just drag/n/drop the dll into the gac and be done with it: for example
in the situation where you leave it to the user to store the dlls in
the GAC or keep them local to the application. So, for the users who
want the dlls in the gac (or need to, because of some issues with
fusion's loader, like Oracle's ODP.NET dlls can confuse the loader and
it suddenly forgets probing paths) they can simply add them to the gac,
and for the people who don't want to do that, they can simply avoid the
GAC altogether. After all, Microsoft themselves state that if you can
avoid the GAC you should.


Get LLBLGen Pro, productive O/R mapping for .NET: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)

.NET versioning

Post by David Levi » Tue, 06 Dec 2005 12:05:46

"Frans Bouma [C# MVP]" < XXXX@XXXXX.COM > wrote in message
news: XXXX@XXXXX.COM ...

If this isn't dll hell then it's awfully close. What would you then do if it
turned out that the "bugfixed" version was buggy itself, but with different
bugs? You could not roll it back because the original version was

This also creates a situation where different versions of the same dll can
exist without any way to tell them apart (well, any good way). Relying on
the timedate stamp or the VERSIONINFO block to tell them apart it is not a
good way to handle it either. Typically the assembly version and the
VERSIONINFO contain the same version number, but the runtime does not
evaluate the VERSIONINFO information for binding purposes, so the app will
bind to the copy of the file that runtime evaluates first. A support person
will have a hard time distinguishing between the different versions of the
same assembly, and this really isn't a story I'd want to tell a customer
("yes I know it 'says' its the same version, but trust me, it's a different

Even if using publisher policy is ugly (I don't like it much myself) it is
still better then this.

Are you suggesting that an install program manually copy the new "fixed"
versions directly over the existing files in the GAC? whew...

This is really going to get even more complicated when 64 bit gacs are in
used, along with other variants of the gac, along with all the distinctions
in naming conventions used for the subdirectories. There are already
multiple system gacs installed on systems. Also, how will this work on a
system with both v1.1 and v2.0 installed? Which gac will you overwrite?

I think that bypassing the GAC install/uninstall APIs is not a good way to

That's exactly the point. Even an update that contains only bugfixes is
still a new assembly that may destabilize applications that use them. I've
experienced far too many updates that did more damage then they fixed to be
willing to overwrite a previous version...I may need it back again.

For assemblies in the GAC use publisher policy or recompile...this does not
seem to be any worse then your proposal, and I think it is better in many
respects. An even better solution is to avoid using the GAC whevever

I prefer to avoid using the system GAC. I wrote my own version of a local
GAC that is deployed with my app and is xcopy deployable; it's mainly a
mechanism to ensure that shared assemblies get loaded correctly. It doesn't
do all the things that the global GAC does, but it does not need to. Updates
will only affect that application.

I think the natural tendency will be to make the system GAC become a dumping
ground for assemblies that really ought to be private but are public and
global. There will be many reasons for this, some good and some not so good.
IMO, over time the GAC will become the same sort of management nightmare
that the registry turned into.


Writing a simple program that invokes the GAC API is fairly trivial, and you
can install and remove assemblies from the GAC quite easily.

Versioning and compatibility is an extremely difficult problem. What .net
offers is not the end of the story, there's a lot more work that needs to be


.NET versioning

Post by Frans Boum » Tue, 06 Dec 2005 19:41:06

avid Levine wrote:

Agreed, but you take it out of context. My context was clearly
1) above all: keep the dlls locally to the application, so you have
xcopy deployment, which thus means avoid the GAC if possible.
2) if required, and if you really have to, copy the files to the GAC.

As microsoft states: the GAC should be avoided if possible.

so, you're hereby claiming that what Microsoft is doing with their
service packs for .NET is bad practise? hmm.

strange, MS doesn't use that feature themselves, even if they can
perfectly do so.

The resemblance of DLL hell is not going away with a policy file btw.
There you too direct calls to one single dll, for all versions of the
range defined in the policy file. DLL hell is the phenomenon where you
install an app and it overwrites an existing dll with an OLDER version
(or different version) and existing applications which expect a newer
version (because the dll overwritten contains a COM object not defined
in the now existing dll). That can't happen here, as the GAC prevents
that. Unless you do a bad job versioning your interfaces of course (by
adding a lot of code and not increasing the assembly version).

No, I suggest that you should read better. I defined a context in
which I suggested a manually copy. Manual copy: you put the files in
the GAC. I also stated that the GAC should be avoided, because MS says
so themselves. IF possible, keep the files locally to the application.

Why would I care? The user puts the files in the gac
(c:\windows\assembly) and not something/one else. Keep the files
locally to the application, not in the GAC and you don't have this mess.

I think using the GAC in general is not a good way to go.

That's up to the developer and the software vendor. If a version has a
spec and the spec says "if you specify 'true' for that parameter, ABC
happens" and just AB happens, it's a bug. If the user of that version
RELIES on the fact AB happens and not ABC, who's fault is that? The
vendor can't withhold a bugfix so fixes it, and by kicking the version
number, the vendor REQUIRES a policy file.

Now, what will that do to 'xcopy deployment' ? You can't simply upload
a new assembly to the website's bin folder and be done with it, you
have to recompile everything, OR use a redirect in your own .config

OR you have to use the GAC. Which Microsoft says you should avoid, and
you perhaps need to avoid because you don't have access to the gac
(shared hosting environments for example)

the assembly file version doesn't require a recompile nor a policy
file. Just a new dll. With xcopy deployment, that's the most efficient
way to do it.

I agree with avoiding the GAC, which is also what MS states and what I
also said in my posting and which you apparently ignored.

so to solve it is to re-invent the wheel? I prefer spending time on
solving other problems than to re-solve problems which are already

it already is, though often it's not a big problem: avoid it.

It also depends on your release policy of course. We have a release
often/release plenty policy because we don't want our customers to wait
3/4 months for a bugfix rollup. So if builds increase each time, you
have a bit of a problem with that policy. I'm not sure if you use a lot
of 3rd party gui controls, but it can be a real pain if controls are
updated regularly with different buildnumbers each tim

.NET versioning

Post by David Levi » Wed, 07 Dec 2005 20:58:02

"Frans Bouma [C# MVP]" < XXXX@XXXXX.COM > wrote in message
news: XXXX@XXXXX.COM ...

My statement is completely within the context of your proposal, as your
restatement makes clear; you propose overwriting assemblies in the GAC when
you think it is warranted. It is correct to try to keep DLLs local to the
app, but you immediately follow that by stating that if required (and who
determines when that is, and what criteria do they use?) you will overwrite
DLLs in the GAC, and without even going through the GAC API.

It is my position that this is worse then not fixing the bug; at least then
you know what you are dealing with. If you overwrite assemblies in the GAC
then there is no easy way to determine which version of the assembly you are
dealing with; this would quickly turn into a support nightmare. You would
need to examine something other then the assembly's baked-in version number
to determine the "real" version of the assembly. This is something no one
with any .net experience would be expecting, it is arcane and not obvious,
and there is no guarantee that any method you used to mark the assemblies
(such as set the VERSIONINFO to a different value) would be handled
correctly, or even consistently, between multiple sub-versions of the
assembly version. Would the info in the VERSIONINFO field be correct and
different? Would we compare the file size or time-date stamps? Inspect it to
look at the mvid? A combination of all these?

There's nothing in your proposal that indicates this would be limited to a
single assembly; presumably you could have many assemblies that have been
updated in this manner. This creates a situation that becomes increasingly
difficult to support, because if a customer has a problem you may need to
duplicate their environment...how do you do that? The number of different,
untested combinations of assemblies will increase exponentially.

Automated tools would not be expecting this, so it would be difficult or
impossible to use management tools to help you manage these assemblies. For
example, I've written a small app that compares the contents of the GAC on
different machines and allows you to copy assemblies from one machine to
another; this would confuse it because it would think the assemblies were
identical when in fact they were different.

What would happen when that assembly had been processed by ngen.exe? Would
the system use the new version or the ngen'd version?

This will also affect applications that were using that assembly but which
did not experience a problem - you may now break apps that were working just

I really think you ought to reconsider your prosal.

We are in complete agreement on this.

There are vast differences between your proposal and a service pack. If you
update the entire GAC to a new, known-good configuration I would be less
opposed (still oppposed but not as much). One of the problems with your
proposal is that it is piecemeal...update an assembly here, try it out,
ooops that wasn't it, try another one, etc. When MSFT does a service pack
they update the entire operating system to that service pack level, and when
it is done all files are working with other files that they have been tested

I made no claims about how good or bad previous practice has been; don't put
words in my mouth.

They update the entire runtime, not one assembly at a time. Just becau

.NET versioning

Post by Richard Gr » Thu, 08 Dec 2005 06:52:39

No, throughout this discussion I have been referring to your suggestion
of overwriting a GAC version with another version that has the same .NET
name but different VERSIONINFO. Yes, using private assemblies is the
best situation in most cases, I never said anything against that. Of
course anyone reading the archives will see that.

No. We were talking about you're incorrect, and dangerous 'solution' to
the original poster's problem. Don't try to change the subject.

<sheesh> you do find it difficult to grasp a concept, don't you? Just
read through the posts in this thread and you'll find I have been
consistent. You've been wandering around aimlessly.

Gosh, you've got a huge ego haven't you? I have been consistent in
talking about the OP's problem and correcting your reply. Frankly I
don't really care what *you* do. (Judging by your arguments, I would not
have too much confidence in your code anyway.)

Go on, you enjoy it don't you? Repeat it again, just for me. I love the
way that you say it <g>. Pratt.

It's generally known. But for your benefit, here's something from Alan


Yup. That's right. See Alan's blog entry.

Yup. You're learning.

No, according to Microsoft, as stated by Alan Shi.

No. Your problem was suggesting a hack that would bring back DLL Hell.


.NET versioning

Post by Frans Boum » Thu, 08 Dec 2005 18:50:16

ichard Grimes wrote:

But my solution is one to solve a real world problem, which you cut
away in your reply and you didn't address it at all. THATs the issue.
There is a real world problem, but all you keep on doing is running in
circles with the same sentences. I _KNOW_ what's best in theory, yet it
won't help with the real world problem you ignored completely.

huh? I just say something can be not so irrelevant for others as it is
for you, as in: a real world problem to which assemblyfileversion is
'a' solution but if you simply IGNORE the problem, then yes, it seems

Sure Richard, personal attacks really help you in your arguments. So
this is your argument? "Shame on you", my code sucks etc. ? Isn't that
a little childish? And who's having a big ego here?

I'm not a native english speaker so what 'pratt' means I don't know
but I guess it's not a compliment. Again a personal attack.

What you apparently fail to understand is that the TS hinted at a real
world problem I described again in an example and which you ignore
completely. Pointing to the theory doesn't help, I know the theory
behind singed assemblies and what not but others out there don't. So
relying on them to have that knowledge is not helping because they'll
come to the vendors of the libraries which rely on THEM to have the
knowledge to find out assembly redirects in their own code.

You can keep on insulting ME till you see blue in the face, Richard,
fact is that whatever you have proposed here doesn't solve the problem
I described.

Which is sad, because no-one is helped by insulting others, but by
using solutions for problems at hand. So, what will it be, Richard,
what's the solution to the 3-assembly chain versioning problem?

ah, a 1.5 year old blogpost. Of course! essential part of the
reference documentation!

You really expect people to wade through all the msdn.com blogs for
info not in the docs? And besides that, you thus hereby declare that
for example Oracle and IBM use policy files completely for the wrong

Well, I can tell you, Richard, because they DO use policy files, a LOT
of developers don't have to deal with problems caused by an increased
version number on the ado.net provider assemblies when a bugfix was
released by either of the two.

Oracle even redirects 9.2.x.x to 10.1.x.x, because it's just one code

But, following your reasoning, Oracle shouldn't do this. They
shouldn't release policy files for their ODP.NET assemblies. So, when
they released and people compiled against that version, those
developers should be stuck with that version and when came
out, all those developers should simply go back to their vs.net and
recompile every code they have because of the version increase of
ODP.NET with essential bugfixes?

Oh no, wait! they should go into reflector, find out the public
keytoken from the Oracle.DataAccess.dll and construct an assembly
redirect in their own *.config files!

And if they happen to write assemblies which are used by yet other
people, they are just out of luck and their problems are simply not

There's a better solution however, Richard. It's that Fusion is
slightly changed. Now a version is 4 different elements (a.b.c.d),
which effectively don't have a separate meaning: change one and the
version changes, even if it's the least significant element.

What if fusion simpl

.NET versioning

Post by Richard Gr » Fri, 09 Dec 2005 02:39:00

One that is wrong and bad.

The OP should recompile, period. Your 'solution' is bad and will cause

Well, at least I know that I am not 'advising' someone to do something
that is bad and will break.

No. I said the OP has no choice but to recompile. Your 'solution' is bad
and will break.

Oh come on, it is just as relevant now as it was then. How old do you
think the documentation is at msdn.microsoft.com/library?

Now you are straying from the point again. I never mentioned Oracle, not
IBM. Nor did I say that people should wade through MSDN blogs.

No. VERSIONINFO is for unmanaged files, the strong name is for managed
files. Yes, a managed file is a PE file and can have unmanaged
resources, but as far as .NET ignores the unmanaged VERSIONINFO
resource. That makes sense because the two resources have equivalent
items and so you will get problems if the two get out of sync.

Keep unmanaged resources in the unmanaged world, and managed resources
in the managed world.

I do not want to get off topic, if you want to talk about another topic
then start a new thread.


.NET versioning

Post by Frans Boum » Fri, 09 Dec 2005 19:03:16

ichard Grimes wrote:

Ok, let's get one thing straight first: I don't *like* the 'solution'
I proposed any more than you do. However there's a problem and if
you're confronted with that problem (and doing a search on
assemblyfileversion or assembly versioning on google reveals I'm
definitely not alone) you want to solve it.

I'll briefly describe it here and I hope you then understand that 'you
should recompile' isn't an option.

Library A, which is signed. A is referenced by library B, also signed.
A and B are from different vendors. Application C is written by
referencing B. All are version

The developer of C discovers that B behaves weird. This developer
contacts the developer of B and explains the behavior. It turns out the
bug is in A. The developer of A is contacted and A is updated to

Ok, now your proposed situation: no policy files. The developer of C
installs A v1.0.0.1. Nothing works anymore, because B can't load A
v1.0.0.1. B has to be updated as well to refer to this new reference
version. So B is recompiled as well to v1.0.0.1.

Now the developer of C recompiles his application with the new B and
it now works again.

Though, B is updated. The latest build of B is now Perhaps
the vendor of B has thousands of customers. This opens up a big problem:
B v1.0.0.0 works with A v1.0.0.0
B v1.0.0.1 works with A v1.0.0.1

B perhaps uses other 3rd party libraries as well. This increases this

Ok, the vendor of B is of course not perfect and discovers a bug in B
as well. This is fixed. B v1.0.0.2 is released.

Which version of A does B v1.0.0.2 reference?
Pretty unclear from the position of the developer of C.

Ok, now WITH policy files.
A gets a policy file, because it is always installed in the GAC. Due
to the bugfix, v1.0.0.1 is released and a new policy file which
redirects references to

No B recompilation has to be performed, as installing the bugfix
version of A (v1.0.0.1) is enough to fix the problem for C. C also
doesn't have to be recompiled, as C references the same B. This is
fortunate for the developer of C, because C is distributed to thousands
of customers and they can now simply update a KB article and refer to
the update of A.

As stated above, B also contains a bug and gets a bugfix. But because
B isn't installed in the GAC, it doesn't have a policy file as well.
Furthermore, because it's a library, it doesn't have a .config file as
well with accompanying assembly redirects.

So let's follow your policy again: no assemblyfileversion. B gets
version The developer of C runs into the bug in B so the
developer of B has to use the new B. He copies the new B into the C's
bin folder and C fails to start... it can't load the assembly. The
developer of C scratches his head and asks B what's wrong? B's
developer tells the developer of C to put an assembly redirect in the
config file of C. This is new stuff for the developer of C so he needs
some guidance. As B has thousands of customers, this will give a lot of
problems for the support department of B, even with a KB article and
proper documentation.

What if B did use a file version? B then got a new assemblyfileversion
but kept its assembly version. C simply kept on running without a
problem. The developer of C doesn't have to recompile.

Now, I'm in the position of B. And with me a lot of other people. In
2003 we were