appdomain.unload

S

sam.m.gardiner

I have a service that used to be written using .net 1.1 and is now
using .net 2 with minimal changes. the service has a pluiggable
architecture that uses appdomains to do the loading/unloading of
resources. the issue I have is with AppDomain.Unload. Or at least, I
think that is the issue.

The service uses a file watcher to see when new plugins DLLs are
dumped.. it waits a bit using a timer to see if the new files have
stopped coming and then hits the Appdomain.Unload to get rid of the
old assemblies, copies the new files to another folder then loads
them. if the app has just started then the appdomain can be unloaded
with no problems. If it has been running for a while then the
appdomain.unload call fails and no exception is caught. I think I have
some problem with non-managed resources locking my appdomain as this
app is a dumping ground and calls into all kinds of stuff; homemade
DCOM stuff, MS office, crystal reports etc etc. Also, I am in a
multithreaded app, and I think that the threading has been done a
little bit crappily, is that going to have an impact? I know that
there are some posts on the web about having the unload call throw an
exception because of being unable to unwind threads.

I read on msdn that the .net 2 version didn't throw exceptions on
other threads, but this feels like that is what is happening..
 
A

Alvin Bruney [MVP]

Not likely, unload causes rude aborts which forces all threads to terminate.
The appdomain will then be unloaded. I suspect that you may have loaded the
app domain incorrectly. Care to post the appdomain load code?

--
Regards,
Alvin Bruney
------------------------------------------------------
Shameless author plug
Excel Services for .NET is coming...
https://www.microsoft.com/MSPress/books/10933.aspx
OWC Black Book www.lulu.com/owc
Professional VSTO 2005 - Wrox/Wiley
 
S

sam.m.gardiner

code for loading

<code>
Dim setup As New AppDomainSetup
setup.ApplicationName = "Running Job AppDomain"
setup.ApplicationBase = Me.m_jobs_dir ' this is a folder
with the pluggable components
setup.ShadowCopyDirectories =
AppDomain.CurrentDomain.BaseDirectory ' this is the host application
that contains other refs.. is this needed?
setup.ConfigurationFile = "file:///" &
[Assembly].GetExecutingAssembly.Location() & ".config"
m_appdomain = AppDomain.CreateDomain("Running Job
AppDomain", Nothing, setup)
</code>


code for unloading..
<code>

Private Sub close_appdomain()
ErrorLog.Log(head & "close_appdomain called",
ErrorLog.ErrorLevel.Verbose)
Dim closing_exception As Exception
Dim try_count As Integer = 0

Do
ErrorLog.Log(head & "close_appdomain loop started",
ErrorLog.ErrorLevel.Verbose)
Try
try_count += 1
closing_exception = Nothing

ErrorLog.Log(head + "garbage collect",
ErrorLog.ErrorLevel.Verbose)
System.GC.Collect()
ErrorLog.Log(head + "trying to unload appdomain, try
#" & try_count.ToString, ErrorLog.ErrorLevel.Verbose)
AppDomain.Unload(m_appdomain)
ErrorLog.Log(head + "unload appdomain succeeded",
ErrorLog.ErrorLevel.Verbose)
Catch aduex As AppDomainUnloadedException
ErrorLog.Log(head + "caught unloaded app domain
exception, it must be gone!", ErrorLog.ErrorLevel.Verbose)
closing_exception = Nothing
Catch e As Exception
ErrorLog.Log(head + "exception caught in
close_appdomain", ErrorLog.ErrorLevel.Error)
closing_exception = e
ErrorLog.Log(head + e.ToString,
ErrorLog.ErrorLevel.Verbose)
ErrorLog.Log(head + "sleeping while we wait for the
exception to go away, normally an unterminated thread",
ErrorLog.ErrorLevel.Error)
Thread.Sleep(SLEEP_WHILE_JOBS_FINISH)
End Try
Loop Until closing_exception Is Nothing Or try_count > 11

If closing_exception Is Nothing Then
ErrorLog.Log(head & "close_appdomain succeeded after " &
try_count.ToString & " tries", ErrorLog.ErrorLevel.Verbose)
Else
ErrorLog.Log(head & "close_appdomain failed after " &
try_count.ToString & " tries", ErrorLog.ErrorLevel.Verbose)
End If


End Sub

</code>

the last line in the log is the "trying to unload appdomain, try #1".
there is no exception caught and execution doesn't proceed onto the
next line in a "timely" way.. when other threads call in to other
parts of the code they find that they immediately throw an "appdomain
unloaded" exception..

i know that it is ugly and hacky. I'd prefer working to
beautiful.. ;-). Another issue I suspect is that unload is called by
a timer thread.. could this be an issue? I'm running in a service
rather than a form so I don't really have a "root" thread to marshall
to (correct me if I'm wrong, I don't have a deep understanding of
threading..).

I should say that this has been running in production as a net 1.1
application for about 2 years and has successfully unloaded a lot of
times (maybe 100 times?) So I suspect that the changes to .net 2 are
connected. Also the application has become more heavily used with more
plugins so maybe that is also a problem.

You suggest I've loaded "incorrectly".. how would I load or unload
incorrectly? what would be the causes and what would the symptoms be?
(apart from not working, of course). I notice that if the service has
jsut been started and run a few items, then the unloading/loading of
new plugins is OK but if I try it after the service has been up for a
day then it fails.. that may be timing or it may be that there is just
one thing that is locked and causing a problem..

thanks for any help, this is a knotty one for me and I think i'm going
to have to debug on the production machine to find it...
 
G

Guest

After you create the domain, are you calling load to load the assembly into
the new domain? I don't see that in your code snippet.

sam.m.gardiner said:
code for loading

<code>
Dim setup As New AppDomainSetup
setup.ApplicationName = "Running Job AppDomain"
setup.ApplicationBase = Me.m_jobs_dir ' this is a folder
with the pluggable components
setup.ShadowCopyDirectories =
AppDomain.CurrentDomain.BaseDirectory ' this is the host application
that contains other refs.. is this needed?
setup.ConfigurationFile = "file:///" &
[Assembly].GetExecutingAssembly.Location() & ".config"
m_appdomain = AppDomain.CreateDomain("Running Job
AppDomain", Nothing, setup)
</code>


code for unloading..
<code>

Private Sub close_appdomain()
ErrorLog.Log(head & "close_appdomain called",
ErrorLog.ErrorLevel.Verbose)
Dim closing_exception As Exception
Dim try_count As Integer = 0

Do
ErrorLog.Log(head & "close_appdomain loop started",
ErrorLog.ErrorLevel.Verbose)
Try
try_count += 1
closing_exception = Nothing

ErrorLog.Log(head + "garbage collect",
ErrorLog.ErrorLevel.Verbose)
System.GC.Collect()
ErrorLog.Log(head + "trying to unload appdomain, try
#" & try_count.ToString, ErrorLog.ErrorLevel.Verbose)
AppDomain.Unload(m_appdomain)
ErrorLog.Log(head + "unload appdomain succeeded",
ErrorLog.ErrorLevel.Verbose)
Catch aduex As AppDomainUnloadedException
ErrorLog.Log(head + "caught unloaded app domain
exception, it must be gone!", ErrorLog.ErrorLevel.Verbose)
closing_exception = Nothing
Catch e As Exception
ErrorLog.Log(head + "exception caught in
close_appdomain", ErrorLog.ErrorLevel.Error)
closing_exception = e
ErrorLog.Log(head + e.ToString,
ErrorLog.ErrorLevel.Verbose)
ErrorLog.Log(head + "sleeping while we wait for the
exception to go away, normally an unterminated thread",
ErrorLog.ErrorLevel.Error)
Thread.Sleep(SLEEP_WHILE_JOBS_FINISH)
End Try
Loop Until closing_exception Is Nothing Or try_count > 11

If closing_exception Is Nothing Then
ErrorLog.Log(head & "close_appdomain succeeded after " &
try_count.ToString & " tries", ErrorLog.ErrorLevel.Verbose)
Else
ErrorLog.Log(head & "close_appdomain failed after " &
try_count.ToString & " tries", ErrorLog.ErrorLevel.Verbose)
End If


End Sub

</code>

the last line in the log is the "trying to unload appdomain, try #1".
there is no exception caught and execution doesn't proceed onto the
next line in a "timely" way.. when other threads call in to other
parts of the code they find that they immediately throw an "appdomain
unloaded" exception..

i know that it is ugly and hacky. I'd prefer working to
beautiful.. ;-). Another issue I suspect is that unload is called by
a timer thread.. could this be an issue? I'm running in a service
rather than a form so I don't really have a "root" thread to marshall
to (correct me if I'm wrong, I don't have a deep understanding of
threading..).

I should say that this has been running in production as a net 1.1
application for about 2 years and has successfully unloaded a lot of
times (maybe 100 times?) So I suspect that the changes to .net 2 are
connected. Also the application has become more heavily used with more
plugins so maybe that is also a problem.

You suggest I've loaded "incorrectly".. how would I load or unload
incorrectly? what would be the causes and what would the symptoms be?
(apart from not working, of course). I notice that if the service has
jsut been started and run a few items, then the unloading/loading of
new plugins is OK but if I try it after the service has been up for a
day then it fails.. that may be timing or it may be that there is just
one thing that is locked and causing a problem..

thanks for any help, this is a knotty one for me and I think i'm going
to have to debug on the production machine to find it...
 

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