A quote from MSDN: http://msdn.microsoft.com/en-us/library/6kac2kdh.aspx
One or more managed threads
(represented by
System.Threading.Thread) can run in
one or any number of application
domains within the same managed
process. Although each application
domain is started with a single
thread, code in that application
domain can create additional
application domains and additional
threads. The result is that a managed
thread can move freely between
application domains inside the same
managed process; you might have only
one thread moving among several
application domains.
I tried to write code with 2 application domains that share one thread. But i gave up. I have really no idea how this is possible. Could you give me a code sample for this?
This can be done by simply creating an object which is MarshalByRef in a separate AppDomain and then calling a method on that object.
Take for example the following class definition.
public interface IFoo
{
void SomeMethod();
}
public class Foo : MarshalByRefObject, IFoo
{
public Foo()
{
}
public void SomeMethod()
{
Console.WriteLine("In Other AppDomain");
}
}
You can then use this definition to call into a separate AppDomain from the current one. At the point the call writes to the Console you will have 1 thread in 2 AppDomains (at 2 different points in the call stack). Here is the sample code for that.
public static void CallIntoOtherAppDomain()
{
var domain = AppDomain.CreateDomain("Other Domain");
var obj = domain.CreateInstanceAndUnwrap(typeof(Foo).Assembly.FullName, typeof(Foo).FullName);
var foo = (IFoo)obj;
foo.SomeMethod();
}
Call a method on an object of the other app domain.
Related
I have a helper-class for my unit-tests that share a reference to an COM-object in memory:
public class UnitTestGeometryProvider
{
public static readonly IGeometry Geometry = Deserialize();
}
The geometry is deserialized from a Xml file which is stored as a resource file and appended to the project. Afterwards it is wrapped into a COM object:
public static IGeometry Deserialize()
{
return (IGeometry) new XMLSerializerClass().LoadFromString(myXDoc.OuterXml, null, null);
}
Now I have two test-methods that use the geometry stored within this class:
[TestClass()]
public class MyTest
{
[TestMethod()]
public void FirstTest()
{
var p = UnitTestGeometryProvider.Geometry;
}
[TestMethod()]
public void SecondTest()
{
var p = UnitTestGeometryProvider.Geometry;
}
}
When running the second one I get a COMException:
COM object that has been separated from its underlying RCW cannot be used
I wonder why the reference to the COM-object is released as it is marked static in UnitTestGeometryProvider and I do not explicitly release it. So even if the managed resource to the instance would go out of scope (which is does not at it is static), the underlying COM object should go away only when all my tests finished or more general when the application terminates, or do I miss anything?
I am using ArcObjects and Visual NUnit.
Due to the comments by Hans Passant I found the actual problem.
Obviously the Visual-NUnit-Framework decides to create a separate thread for every test. Thus whenever I create a COM-object - be it static or not - this object lives on this single thread and cannot be used in another one. If the thread dies also does the COM-object or to be more precise the reference to it. This leads to the GC kicking in throwing the COM-object away as no more managed references to it exist within that thread.
The solution is pretty straitforward: I changed the static field to instance-members and created an instance-member of type UnitTestGeometryProvider within my test-class. Thus a new provider is generated by every test.
However this solution is quite annoying because the Geometry-property has to be initialized and therefor the Deserialize-method runs for every test instead of only once for all tests.
I donĀ“t know if there is a thread-safe solution to not kill the reference to the COM-object when the first thread that intialized it dies.
We have some background processes that run on IIS ASP.NET websites. To prevent these processes from dying when the application recycles, we implemented an instance of IRegisteredObject, where we wait for work on a server to finish before unloading the appdomain (see contrived example below).
Our code is working as expected, however as we do deployments - old appdomains persist until the work we want is completed (which we want) - however, with frequent deployments / lots of work - we run into a situation where resources on our virtual machines are almost exhausted.
Is there an external way to force an unload (regardless of IRegisteredObject existence) / kill older appdomains? or a way that we can communicate with an older appdomain to tell it to terminate within code?
internal class ShutdownHelper : IRegisteredObject
{
public ShutdownHelper() {
HostingEnvironment.RegisterObject(this);
}
void IRegisteredObject.Stop(bool immediate)
{
if (immediate)
{
WaitForAllWorkToComplete(TIMEOUT /* Some arbitrary timeout*/); // This function returns when all processing on the server has completed
HostingEnvironment.UnregisterObject(this);
}
else
{
// Similar logic as immediate but run asynchronously and we only unload if the task completes (in a continuation)
}
}
}
You can enumerate all domains using this piece of code Enumerating AppDomains
Then, you can execute code on the remote AppDomain using AppDomain.CreateInstanceAndUnwrap method. The domain should have the assembly containing this shared type loaded.
CrossAppDomainExecuteStopper stopper = (CrossAppDomainExecuteStopper)appDomain.CreateInstanceAndUnwrap(typeof(CrossAppDomainExecuteStopper).Assembly.FullName, typeof(CrossAppDomainExecuteStopper).FullName);
stopper.StopWork();
and CrossAppDomainExecuteStopper must inherits from MarshalByRefObject
public class CrossAppDomainExecuteStopper : MarshalByRefObject
{
public void StopWork()
{
// force stop the work
}
}
I would like to know if there is any way to get an event (or something else) that tells you when a new thread was created on your appdomain (C# application)? The basic idea is that when a new thread is created I need to "initialize" the thread with some settings.
I do not want to go all over my code and do that, as I don't know what future will hold.
Create a thread static variable, and initialize anything you need in the constructor.
class ThreadEnvironmentSettings
{
[ThreadStatic]
public static readonly ThreadEnvironmentSettings Settings =
new ThreadEnvironmentSettings();
public ThreadEnvironmentSettings()
{
SetupJavaEnvironment();
}
public void EnsureSetup(){
// Doesn't do anything but required to 'touch' the thread variable
}
}
Then before calling any methods that require an established environment:
ThreadEnvironmentSettigns.Settings.EnsureSetup();
I assume that java loaders execute on the other process. And .NET code just specifies correct arguments for the command line - then you can use environment variables for the whole process.
Environment variables are global to the whole process (that is all threads will have access to them even newly created ones). Here's how to set a variable in C#.
Basically, from what I've understood of the little I've managed to search up on the internet, threads can pass between AppDomains. Now, I've written the following code:
const string ChildAppDomain = "BlahBlah";
static void Main()
{
if (AppDomain.CurrentDomain.FriendlyName != ChildAppDomain)
{
bool done = false;
while (!done)
{
AppDomain mainApp = AppDomain.CreateDomain(ChildAppDomain, null, AppDomain.CurrentDomain.SetupInformation);
try
{
mainApp.ExecuteAssembly(Path.GetFileName(Application.ExecutablePath));
}
catch (Exception ex)
{
// [snip]
}
AppDomain.Unload(mainApp);
}
}
else
{
// [snip] Rest of the program goes here
}
}
This works fine and everything is clicking into place... The main thread passes through into the new version of my program and starts running through the main application body. My question is, how would I go about getting it to go back out to the parent AppDomain? Is this possible? What I'm trying to achieve is sharing an instance of a class between the two domains.
You cannot share instances of classes directly between AppDomains. To do so, you should derive the class from MarshalByRefObject and use remoting to access the instance from the other AppDomain.
An object in .Net can only exist in one AppDomain. It is not possible for it to exist in 2 AppDomains at the same time.
However you can use .Net Remoting to push a proxy of a .Net object into several AppDomains at once time. This will give your object the appearance of being in multiple domains. I believe this is what you are looking for.
There are many tutorials available online. Google for ".Net Remoting Tutorial" and that will put you on teh right track.
http://www.beansoftware.com/NET-Tutorials/NET-Remoting-Tutorial.aspx
http://msdn.microsoft.com/en-us/library/72x4h507(VS.80).aspx
I have a windows service that starts a thread in the OnStart method.
Basically I want to be able to stop the service if something goes really wrong (like an unhandled exception).
Currently I'm using ServiceBase.Stop() but that involves having a ServiceBase instance somewhere visible to the thread, which in turn involves having my instance be declared as public static in the main program.
Is there any "better way" to stop the service? If it isn't ... is it safe to do it that way?
The easiest and, in my opinion, cleanest way is to use a public static property of the service class. The only time this won't work is if you are using the same service class to run multiple services in the same process, something that is very rare.
private static MyService m_ServiceInstance;
public static MyService ServiceInstance
{
get { return m_ServiceInstance; }
}
public MyService()
{
InitializeComponents();
//Other initialization
m_ServiceInstance = this;
}
Injecting the service instance into every method that could possibly need it is an alternative but it can quickly get messy and it has no real advantages over just using a static property.
Check out the example here on how to use the ServiceController class to start and stop services.
Alternatively, you could pass your service instance to the thread when you create it (or set it as an instance variable in the thread class, etc.) without having to make your service class static.
A short example for completeness:
ServiceController sc = new ServiceController("MyService");
sc.Stop();