Why Assembly.Load get returns wrong assembly.

G

Guest

Background:
I created a windows service with .NET 1.1 that is a shell that simply loads
assemblies and then loads a certain type there and calls a method. Those
dynamically loaded assmeblies meant to be upgardable. I wrote a code that
replaced assemly files with the new version and then windows service supposed
to load new version of the assembly and run it.

Problem:
While trying to implement this auto-upgrade feature, I ran into this
sequence of events that leads to a strange result:
- My windows service dynamically load an assembly "A" of version
1.0.1234.0000; run it for a while;
- Then assmebly "A" dll file gets replaced with assembly "B" file of version
1.0.5678.000.
- When service attempts to load assembly "B", for some reason returned
reference points to assembly "A".

I tried both
Assemly.Load(AssembyName.GetAssemblyName(newAssemblyPath))
and
Assembly.LoadFrom(newAssemblyPath)
with the same result - both return reference to "A" of version 1.0.1234.000.
Remarkably, AssembyName.GetAssemblyName(newAssemblyPath) returns correct
AssemblyName object - the one for the new assembly "B". Then feeding this
AssemblyName to Assemly.Load() still results in returned reference pointing
to assembly "A".

How to make sure Assemly.Load() and Assembly.LoadFrom() actually load the
assembly I specify?

Thank you,
 
M

Michael Nemtsev

Hello Vlad,

Problem is not in how to load assembly - how to unload them correctly.
First, you can't unload specific assembly - only whole domain, thus u need
to load your interchangeable asms into separate app domain.
Second, when u use Assembly class to load asm it loads into the default domain.
There is no way to unload asm from default domain without unload the whole
app.

I recommend u to look at App Domain class to realize loading asms into separate
domains.

VH> My windows service dynamically load an assembly "A" of version
VH> 1.0.1234.0000; run it for a while;
VH> - Then assmebly "A" dll file gets replaced with assembly "B" file of
VH> version
VH> 1.0.5678.000.
VH> - When service attempts to load assembly "B", for some reason
VH> returned
VH> reference points to assembly "A".
VH> I tried both
VH> Assemly.Load(AssembyName.GetAssemblyName(newAssemblyPath))
VH> and
VH> Assembly.LoadFrom(newAssemblyPath)
---
WBR,
Michael Nemtsev :: blog: http://spaces.live.com/laflour

"At times one remains faithful to a cause only because its opponents do not
cease to be insipid." (c) Friedrich Nietzsche
 
J

Jeffrey Tan[MSFT]

Hi Vlad,

Based on my understanding, your .Net Windows Serivce applicaion wanted to
support auto-updating function for some assemblies, so that the
administrators/users can replace the new version of assembly without
stopping the Windows Service. If I have misunderstood you, please feel free
to tell me, thanks.

When a .Net application loads an assembly into the memory, this on-disk
assembly will be locked by the system. So can you tell me how do you replace
the same assembly with the new version? Do you changed the assembly name so
that it will not "replace" the old assembly, but just being added into
certain directory? I hope you can explain your updating logic more clear.
This will help us identify your problem better. Thanks.

If you wanted to explicitly load the assembly B whatever, you should use
Assembly.LoadFrom. Note: you should pass the pathname to the method *with*
the file extension. Also, you should not provide the strong-name
information, that is, the string can't contain version, culture, or public
key information. Once you obey these rules, you should can load the extra
assembly B without any problem.

Finally, as "Michael Nemtsev" has pointed out, although can you load the new
version of assembly, the old version of assembly can not be unloaded, if you
are using single AppDomain. This is because we can not unload an assembly
from an AppDomain, however, we can unload an AppDomain explicitly. So the
recommended solution to implement auto assembly updating is using more than
1 AppDomain. There are several key points to implement the solution:
1. Since the old version will be locked by the system, you should
ShadowCopyFiles property to shadow copy the old version of assembly. By
donig this, the runtime will copy the assembly to a cache directory, and
then open that one. That leaves the original file unlocked, and gives us the
ability to update an assembly that's in use. ASP.NET uses this facility.
2. You may use FileSystemWatcher class to monitor the assembly directory so
that whenever the new version assembly is replacing the old one, your
application will be notified with events.
3. Creating a new AppDomain to load the assembly so that while updating, you
can unload the entire AppDomain and create a new AppDomain to load the new
version.

There is a MSDN article demonstrating this technology:
"AppDomains and Dynamic Loading"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp05162002.asp

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notifications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support Engineer
within 1 business day is acceptable. Please note that each follow up
response may take approximately 2 business days as the support professional
working with you may need further investigation to reach the most efficient
resolution. The offering is not appropriate for situations that require
urgent, real-time or phone-based interactions or complex project analysis
and dump analysis issues. Issues of this nature are best handled working
with a dedicated Microsoft Support Engineer by contacting Microsoft Customer
Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Thanks to all who replied. I ended up using AppDomain, which allowed me to
achieve desired result. A couple of things worth mentioning:
- Countrary to what I expected and what Jeffrey described, my
dynamically-loaded assemlies were not locked. I had no problem deleting them
even though they were loaded. I don't know if that has to do with late
binding, but with and without AppDomain, replacing assemblies was
straightforward.
- Prior to using AppDomain I tried both Assembly.Load and Assembly.LoadFrom
in all their forms with the same strange result - returned Assembly reference
was pointing to the old version of the assembly. Whatever the rules that make
such behavior valid, they are not intuitive at all.
 
J

Jeffrey Tan[MSFT]

Hi Vlad,

#1, it is interesting that the file is not locked when you are using
Assembly.Load to load it into memory. Based on my experience, the loader
will always place a lock on the assembly file.

#2, I am not sure why Assembly.LoadFrom does not work in your application.
Is it possible for you to create a little sample project to demonstrate the
problem? Then I will help you to troubleshoot the root cause.

Additionally, since .Net CLR uses fusion to lookup the assembly, you may
use Fuslogvw.exe(Assembly Binding Log Viewer) to examine the
Assembly.LoadFrom() probing path. The log may reveal more information about
the failure.

Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Thanks, Jeffrey.

I probably won't bother trying to reproduce Assembly.Load issue - using
AppDomain solved the issue and even though I would love to get to the bottom
of it, my schedule is too tight - I spent more time working on assembly
upgradeability feature than I thought I would. My only complaint is that it
was hard to find the problem because I expected Assembly.Load to throw an
exception if specified assembly didn't get loaded for some reason, instead of
quiely returning the reference to another assembly.

Thanks again,
 
J

Jeffrey Tan[MSFT]

Hi Vlad,

Thanks for your feedback.

Yes, I understand that. Schedule sometimes forbids us to go deeper to find
out the root cause.

I was also surprised to find that Assembly.Load/Assembly.LoadFrom methodes
do not work in your application, since I have tried the similar approach
several times in other applications. And I always use Fuslogvw.exe to check
the problem.

Sorry, without reproducing this strange behavior on my side, I can not
provide more information for the root cause of this problem. Thanks for
your understanding.

Anyway, I think your current solution of using AppDomain is a good one,
since it allows you to unload the old version of assemblies from memory,
while the old approach can not get this done. I recommend you go with this
AppDomain solution.

If you need help on this issue when you have time, please feel free to
post, I will work with you. Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

I have tripped again on what seems to be another protuberance of LoadFrom()
issue: Visual Studio setup/MSI projects won't work correctly in upgrade mode
if you have cusom actions done using .NET installer classes. According to
http://support.microsoft.com/kb/906766 LoadFrom() can't tell old custom
action assembly from the new one despite them being in differrent locations.
I tried signing/strong-naming the assmbly but still have issues in upgrade
mode.
 
S

Steven Cheng[MSFT]

Hello Vlad,

From your description, you have an VS 2005 built setup program that has new
version which will uprade the original installed application. However, you
encountered the following issue and can not get it work through the
workaround provided in it, correct?

http://support.microsoft.com/kb/906766

For the assembly signing, are you perform the strong-name signing on your
custom assembly? I suggest you use the Fuslogvw.exe utility to trace the
assembly binding to see how did the MSI setup program look for the custom
action assembly,(check whether the assembly identifier contains the
assembly name you've strong-named).

also, if possible, can you produce a simplified dummy setup program to
demonstrate the behavior you met? Then, I'll be able to perform some local
tests against it.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Steven,

I need to investigte the issue a bit further becasue I cannot reproduce the
problem on a simplified test solution. In my real project MSI fails to load
some of the custom action assembliy's dependency assemblies, even though they
are all signed/strongly named too. I will post my findings after I get to the
bottom of it.

Meanwhile, why MSI (or whoever that is who's loading .NET custom action
assemblies when MSI runs) does not load old and a new custom actions
assemblies into differrent AppDomains? This way MSI could have unload old
custom actions after uninstallation is done and load new ones. No signing
would be necessary.

Let me also vent a bit: this custom action upgrade issue migrated from .NET
Framework 1.1 to 2.0 even though it's been know for a few years now
(http://support.microsoft.com/kb/555184). It's hard to understand why it's
not being addressed in such a long time.
 
G

Guest

I was able to establish that my "real" setup project acts as if the custom
action assembly was not signed: it keeps launching custom steps from previous
version unless I give the assembly name that is differrent from the previous
version, which is not acceptable in my case. In simple test setup case
signing did solve the problem.

I could send MSI files with both old and new versions so you could see
yourself that custom actions assembly and all its dependencies are indeed
signed.
 
S

Steven Cheng[MSFT]

Thanks for your reply Vlad,

Yes, as you mentioned that the siging approach does work in simple test
case and that confirms to what I've researched. So far I think the problem
should be specific to the particular custom action and dependencies of your
setup program. Due to the complexity of this scenario, I would suggest you
consider contacting CSS for further troubleshooting on this. And you can
reference the kb article to the product support engineer to confirm whether
this does be an know issue that violate the documented behavior.

http://msdn.microsoft.com/subscriptions/support/default.aspx

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


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