If you can control the threads created in the other AppDomain, you can also handle exceptions by using catch-all blocks in the thread main method.
Other than that, as long as you use the default host, I believe that your assumption is correct. However, if you host the runtime yourself, you can also handle unhandled exceptions.
From a forum post on the topic:
Well, it is possible. You'd have to
create your own CLR host. That starts
with ICorBindToRuntimeEx(). You get
to have full control of AppDomains
that throw exceptions. And it's being
used by MSFT software like ASP.NET and
SQL Server 2005. When you write a
service, you are working with the
default CLR host implementation and it
terminates the process when any
unhandled exception is raised,
regardless of what AppDomain caused
the exception.
Problem is, hosts like ASP.NET and SQL
server have a very well defined code
execution path. In a web server,
managed code runs because of a page
request. In a dbase server, it runs
because of a query. When something
bad happens, they have the luxury of
simply aborting everything that the
request started (killing the
AppDomain) and returning a "sorry,
couldn't do it" status back to the
client. You might have seen it,
crashing the forums server on the old
web site was pretty trivial but didn't
stop it from serving other requests.
Not actually 100% sure about that.
Your service implementation is
probably not nearly as clean. I can't
tell, you didn't say anything about
it. It general, there's a problem
with aborting a thread. You always
have to abort a thread when there's an
unhandled exception. A service
typically has one thread, started by
the OnStart() method. Aborting it
kills the server until somebody stops
and starts it again.
You can definitely make it more
resilient than that, you could start a
"master" thread that launches child
threads in response to external events
that makes your service do its job.
Having a child thread terminated
because of an unhandled exception is
something you could possibly recover
from. But then, if you make that next
step, why not have the child thread
catch an exception and pass it back to
the master thread so it can make an
intelligent decision about what to do
next.
The cold hard fact of the default CLR
host is: if you are not willing to
deal with failure, it is not going to
do the job for you. And it shouldn't,
the .NET 1.x behavior to threads that
died with exceptions was a major
mistake that got corrected in .NET
2.0.
You know what to do: handle failure.
Or write you own host. Or accept that
things could be beyond your control
and log a good error message so you
can tell your customer what to do.
I'd strongly recommend the latter.