No Touch Deployment: Force Refresh of Assembly Download Cache

G

Gregg Walker

My applications are being run using no touch deployment from a hosting web server. The client program calls
AppDomain.ExecuteAssembly to start execution of the application.

Most of the time everything works fine. However, my applications make use of a third party component and everytime they make a new
version available they don't change their assembly version number but just the file version number. So whenever new features are
added and one of my apps begins using the new feature the no touch deployment of the app is broken because the newer version is not
detected on the web server and loaded over the previous version in the assembly download cache.

Is there a way I can force ExecuteAssembly to not compare assembly version numbers and just overwrite all existing assemblies it
needs to load? I don't want all my users to have to run 'gacutil /cdl' every time I make use of a new version from component
vendor.

Any other suggestions on how to solve this issue would be greatly appreciated.

Sincerely,
Gregg Walker
 
F

Felix Wang

Hi Gregg,

I have tested your situation on my side. It seems the .Net runtime not only
compares the AssemblyVersion of the assembly in the download cache with the
one on the server (this is formally documented), it also compares something
else (probably date) to determine whether they are the same one.

I am running .Net 1.1 and download the assembly from a HTTP server on the
LAN. Although I do not increase the version of the assembly on the HTTP
server, my client program always download it correctly. On the other hand,
if I change the assembly on the HTTP server to one with an older timestamp,
it will not be downloaded. This can be fixed by cleaning the IE temp files.

Could you let me know your detailed configuration? I hope the information
is useful to you.

Regards,

Felix Wang
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
D

Dave

Felix Wang said:
Hi Gregg,

I have tested your situation on my side. It seems the .Net runtime not only
compares the AssemblyVersion of the assembly in the download cache with the
one on the server (this is formally documented),

Where is this documented? Unless they drastically changed the Fusion layer
from 1.0 this is not the case.
it also compares something
else (probably date) to determine whether they are the same one.
The docs that I have seen (and the experiments I have run) indicate that
*all* that is compared is the time-date stamp of the files. The runtime does
not actually examine the assembly version until after the file has been
downloaded to the local download cache.
 
D

Dave

Gregg Walker said:
My applications are being run using no touch deployment from a hosting web
server. The client program calls
AppDomain.ExecuteAssembly to start execution of the application.

Most of the time everything works fine. However, my applications make use
of a third party component and everytime they make a new
version available they don't change their assembly version number but just
the file version number. So whenever new features are
added and one of my apps begins using the new feature the no touch
deployment of the app is broken because the newer version is not
detected on the web server and loaded over the previous version in the assembly download cache.

Is there a way I can force ExecuteAssembly to not compare assembly version
numbers and just overwrite all existing assemblies it
needs to load? I don't want all my users to have to run 'gacutil /cdl'
every time I make use of a new version from component
vendor.

Any other suggestions on how to solve this issue would be greatly appreciated.
Felix stated that the runtime examined the assembly version of the file on
the server but I do not believe this is the case. The problem that you
describe is very similar to the one that I ran into. This article describes
the problem in greater detail..
http://msdn.microsoft.com/msdnmag/issues/02/07/NetSmartClients/default.aspx

There's no mechanism I am aware of that forces ExecuteAssembly to always
download the file - that would bypass all the optimizations that the Fusion
layer uses to avoid needlessly downloading bits from a server.

The solution that I came up with was to write a small service that returns
to the client a list of all files on the server, their time-date stamps, and
their assembly version numbers (if present). The client then compares that
list to the list of files in its local store and then downloads all the
files that are different or non-existent.

This completely changed the deployment model (security zone of loaded
assemblies and when bits are copied) but the advantage is that it always
works. It also added some other benefits, such as the ability to download
data files and files in subdirectories; these would not ordinarily be
automatically downloaded from a server.

IMO the current implementation of Fusion needs to be reworked because all it
takes to break the deployment model is for someone to change the time-date
stamp of a file on a server to an earlier date.

Dave
 
F

Felix Wang

Hi Dave,

Thanks for correcting me. In fact I refered to "Versioning" section of the
following article:

Death of the Browser?
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/ht
ml/vbnet10142001.asp?frame=true

It seems that I had some misunderstanding on the meaning of the word
"version". I am sorry for this.

Regards,

Felix Wang
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
G

Gregg Walker

Hey Guys,

Thanks for the responses. I haven't had a chance to test out the timestamp reason that you stated. I didn't think that was the
cause of problems in my environment but it may very well be. Actually if that is the case it's much easier to remedy than relying
on third party vendors changing assembly version numbers. Anyway I'll get back to you when I try this out.
The solution that I came up with was to write a small service that returns
to the client a list of all files on the server, their time-date stamps, and
their assembly version numbers (if present). The client then compares that
list to the list of files in its local store and then downloads all the
files that are different or non-existent.

This completely changed the deployment model (security zone of loaded
assemblies and when bits are copied) but the advantage is that it always
works. It also added some other benefits, such as the ability to download
data files and files in subdirectories; these would not ordinarily be
automatically downloaded from a server.

I like what you are doing Dave and I may end up doing something similar although I don't know when I'll find the time.
IMO the current implementation of Fusion needs to be reworked because all it
takes to break the deployment model is for someone to change the time-date
stamp of a file on a server to an earlier date.

Agreed. We as developers need more control over when and if assemblies are deployed locally.

Thanks again,
Gregg Walker
 
F

Felix Wang

Hi Gregg,

Dave is right. As long as the time stamp of the file is newer, the assembly
will be downloaded from the server.

Regards,

Felix Wang
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
G

Gregg Walker

Do you happen to know which time stamp? Creation time or Modified time? If it's the creation time then that would explain the
problems I'm seeing.

Thanks,
Gregg Walker
 
G

Gregg Walker

Sorry guys. Either you are wrong about the timestamp thing or I must be missing something. I've changed modification and creation
time stamps on an assembly and newer version will not be downloaded unless the assembly version changes. Apparently when assembly
version changes it actually creates a separate subfolder for that version in the download cache. So each application assembly gets
its own subfolder and then new folders are added to that folder for each assembly version. It definitely appears to me that
assembly version numbers are being checked.

Any more ideas?

Thanks,
Gregg Walker
 
G

Gregg Walker

Just a thought. Does it make a difference in how assemblies are downloaded depending on whether or not they are strong named? The
third party components I'm having a problem with are strong named and are made to be stored in GAC on developers machine. Maybe
strong named assemblies always have their assembly versions inspected before being downloaded???

Thanks,
Gregg Walker
 
D

Dave

If the assembly already exists in the GAC then it wont be downloaded. There
is also no way to download an assembly and have it automatically placed into
the GAC.

Gregg Walker said:
Just a thought. Does it make a difference in how assemblies are
downloaded depending on whether or not they are strong named? The
third party components I'm having a problem with are strong named and are
made to be stored in GAC on developers machine. Maybe
strong named assemblies always have their assembly versions inspected before being downloaded???

Thanks,
Gregg Walker

"Gregg Walker" <[email protected]> wrote in
message news:[email protected] something. I've changed modification and
version in the download cache. So each application assembly
 
G

Gregg Walker

Hi Dave,

The assembly is not in the GAC on the client machine. It's just that it is
strong named. That's my question is if that is treated differently?

Thanks,
Gregg Walker
 
D

Dave

The article link I provided earlier answered this; the assembly's time-date
stamp is compared first and only if the file is of a later date is it
downloaded. After it is downloaded the assembly is examined for its strong
name and version, and if either does not match the requirements then the
binding attempt fails. Once a failure has occurred the fusion layer stops
all further attemps to locate an assembly and a failure exception is
generated.

Note the first statement - prior to any checking of strong names, version,
etc. the assembly is first downloaded if, and only if, the time-date stamp
requires it.
 
G

Gregg Walker

Hi Dave,

Sorry if I sound ignorant on this topic because I am... :) This is a learning process for me.

I think we are talking apples and oranges here. Yes it is clear from the article that the main assembly exe will only be
redownloaded when it's date time stamp is newer than that currently in the download cache. No problem with that.

What I'm talking about is my exe's assemblies that it references. If you look at the part of the article that talks about "Related
Files" then that describes my situation. The third party control my application references has an assembly version that never
changes (whenever they make updates/patches) and will never be downloaded again unless the download cache is cleared. My
application sees an assembly in the download cache with the (assembly) version it was built with and assumes that it has the correct
version. Therefore no need to go back to the AppBase to find it.

I'm currently trying to get the third party control vendor to change their assembly version whenever they make changes to control.
Not sure how successful I will be at that so I'm looking at other ways to work around problem. I think I'm currently leaning
towards doing what you've done and write a web service that I can use to download all the needed files and create my own "local"
cache for executing the applications.

Thanks for your great help in pointing me in the right direction.

Sincerely,
Gregg Walker
 
D

Dave

Gregg Walker said:
Hi Dave,

Sorry if I sound ignorant on this topic because I am... :) This is a
learning process for me.

Same here :)
I think we are talking apples and oranges here. Yes it is clear from the
article that the main assembly exe will only be
redownloaded when it's date time stamp is newer than that currently in the
download cache. No problem with that.
What I'm talking about is my exe's assemblies that it references. If you
look at the part of the article that talks about "Related
Files" then that describes my situation. The third party control my
application references has an assembly version that never
changes (whenever they make updates/patches) and will never be downloaded
again unless the download cache is cleared.

That's a problem all right. They're violating the "rules" they should be
following. They are purposely defeating all the mechanisms MSFT built into
the fusion layer for handling versioning and app compatibility.
My
application sees an assembly in the download cache with the (assembly)
version it was built with and assumes that it has the correct
version. Therefore no need to go back to the AppBase to find it.
Correct.


I'm currently trying to get the third party control vendor to change their
assembly version whenever they make changes to control.
Not sure how successful I will be at that so I'm looking at other ways to
work around problem.

You might point out that other users will be less likely to want to purchase
a component that makes it so difficult to handle remote deployment. Is this
a .net component they are providing?
I think I'm currently leaning
towards doing what you've done and write a web service that I can use to
download all the needed files and create my own "local"
cache for executing the applications.

It was actually more difficult to discover what the root cause of the
problem was then to write the code. This was back in the 1.0 days when
information was not as widely available as it is today.

If you do this then you may want to run your launcher/app updater in one
appdomain (e.g. the default) and the actual application in another appdomain
that you can unload. This allows you to unload the running app, update the
bits, and then restart the app, all without exiting the "launcher"
application.
Thanks for your great help in pointing me in the right direction.

Glad I could help.

Dave
 
F

Felix Wang

Hi Gregg,

I am also reading the article. According to that article, the situation
that version will be checked include the following:

1. Reference other assemblies implicitly as part of the manifest. For
example, in VS.Net, we "Add Reference" to a strong-named DLL assembly.

2. Or explicitly via the Assembly.Load method. For example:

SampleAssembly = Assembly.Load("Assembly text name, Version, Culture,
PublicKeyToken");

If we only use "AppDomain.ExecuteAssembly()" here (as you mentioned
earlier), like the following:

AppDomain.CurrentDomain.ExecuteAssembly("http://sha-felwa-test/WindowsApplic
ation1.exe");

I don't think that the version of the EXE file matters. In fact, the
runtime shall always go to the remote server to check the availibility and
timestamp of the assembly (WindowsApplication1.exe here). Even though we
have one WindowsApplication1.exe in the download cache, if we disconnect
ourselves from the remote web server, we will still get a
FileNotFoundException when trying to call
"http://sha-felwa-test/WindowsApplication1.exe".

I have also learned a lot from this issue. Could you let us know how you
make reference to the remote file? Maybe we can discuss more on the topic
with this information.

Regards,

Felix Wang
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top