Assembly.LoadFrom HTTP and the Download Cache
In the .Net Framework there is a lot of powerful things. One of those is "Reflection". With reflection you can dynamically load an assembly, instanciate an object and call methods or access properties on that object.
On a project I worked in, the deployment method was Reflection based. That means that all the DLLs were only on the server. On the client side, when an assembly is need, it is dynamically loaded from the server (over HTTP) and instanciated. This works great and the DLLs are always only on the server side.
Even if this is a good way to deploy assemblies, there is 2 problems with this approach. We discovered them while on production.
First problem : Download Cache
When you use Assembly.LoadFrom and pass it an URL instead of a URI, the downloaded DLLs are placed in the "Download Cache". This is the .Net equivalent to the "Temporary Internet Files". When a DLL is first downloaded, the .Net Framework puts it in its download cache to avoid going to the server another time to get the same DLL. This is good for performance, but when you need to deploy a new version of that DLL the Framework might reuse that DLL. When it happens you have to clear your download cache and then restart the application so the DLL can be redownloaded again. This works almost everytime but because HTTP involves IIS, Download Cache and Temporary Internet Files and Wininet Cache, the Dlls are sometimes stuck somewhere and you never get the new version of the DLL you have deployed to the server. You try to every cache, restart IIS, clear the download cache again but sometimes you have to reboot the server and the client. This can be a real pain if, like us, you continuously deploy newer versions of DLL on your production server.
This problem will never happen if you load you DLLs over the file protocol (with a path like C:\assembly.dll or \\server\share\assembly.dll) because IIS and caches and not involved in the process.
Everytime you will load an assembly with a LoadFrom with a UNC path or local path you will have the right version of your DLL. We you can use this approach, use this one, but there is times where you can't and you have to use HTTP (like when you deploy over the web...). The only thing I have to say about this approach is when you load assemblies with a UNC path, the assembly gets locked on the server so when you have to put another version of the DLL, you need to try to rename the DLL (most times it works) or reboot the server.
In general rule, when you do an Assembly.LoadFrom, you will have the right version, but not 100% of the time.
Second problem : Download Cache
This other problem is slightly different than the first. The first problem was with the DLLs that were directly loaded, but the second problem is with the DLLs that are referenced by loaded DLLs, thus getting loaded dynamically by the .Net Framework itself (the .Net Framework checks the codebase folder of the current DLL for the DLL named like the referenced one in the current assembly.
Because references in an assembly is only the strong name, when the framework detects that an assembly referenced needs to be loaded, it checks on the GAC and if it does not find the assembly in the GAC it checks on the folder of the current application and than on the folder of the codebase of the current assembly (following the probing process). When the current DLL or application was started or loaded over HTTP, the .Net Framework checks the Download Cache to see if the DLL he wants is in it, BEFORE going to the server. If the framework finds the correct DLL in the Download Cache, it takes that one and never go to the server to check if there's a newer version. That behavior is different than the one with LoadFrom because when you do an explicit LoadFrom, the Framework goes to the server even if there's a version in the download cache.
Real case problem
So let's say that we have a set of DLLs (A) that can be dynamically loaded from the server over HTTP at runtime. All of those DLLs reference some common DLLs (B) that contains global routines. You always load your "A" DLLs by a LoadFrom, and "B" DLLs are always loaded automaticaly by the .Net Framework. One day you update "A" DLLs. All the clients gets the new versions the next time they load them (except if you get the first problem...).
Another day you update the "B" DLLs and, surprise, no one gets the new versions... Yeah, this is frustrating when you discover this when testing it on production... !
Microsoft Support
Because we thought that was a bug and that there might be a fix, we called the Microsoft Premier Support. An Indian called us a few days after and I've explained the problem to him and showed him a working example... after 1 week the only thing we got for a response is that it is "by design". It might be "by design", but in that case it bugs us a lot so we needed to find a real quick solution.
Real case solution
We decided to do the next 2 things.
1. Clear the Download Cache when the client application starts
2. Explicitly load referenced DLLs with LoadFrom
Because the automatic LoadFrom process of the .Net Framework does not go to the server, but the explicit LoadFrom goes to the server, we decided that when we LoadFrom a DLL explicitly, we check all the references and the go to the server to load every referenced DLLs explicilty.