Infosys Microsoft Alliance and Solutions blog

« Software Factory: Business Semantics based Meta-Models | Main | WPF Application Default Assembly Version »

Creating and Working with Applications in AppDomains

We all have read that AppDomains are light weight processes that .net uses to run applications, but I hardly ever played with AppDomains directly. Recently I decided to give this a try and following are my findings. If you want to get more information on AppDomains, check this excellent blog by Chris Brumme.

To create a new AppDomain, you use the static method CreateAppDomain and can give a friendly name to the AppDomain at this time. Once the domain is created, you can call ExecuteAssembly to load and run an assembly from its entry point. The code will look something like the following. For my testing, I worked with an application that can execute on its own.

            AppDomain ad = AppDomain.CreateDomain("test");

            ad.ExecuteAssembly("DummyApp.exe");

Note that the above assumes that the DummyApp.exe is in the same path is the calling application, else complete path will need to be specified.

In .net 2.0 a new method ExecuteAssemblyByName has been added and is the preferred method to use. As documented, these methods execute the entry point, but not on a different thread. This means that while the loaded assembly is executing, the application that started it, will not execute further, since the primary thread is busy executing the assembly loaded in the new AppDomain. You will have to close the assembly (in case of applications) or unload the AppDomain to continue ahead with your main application.

In case you want to work with both the applications, you can create the AppDomain on a different thread. The code will look something like the following

        {

            Thread th = new Thread(new ThreadStart(func1));

            th.Start();

        }

 

        private void func1()

        {

            AppDomain ad = AppDomain.CreateDomain("test");

            ad.ExecuteAssembly("DummyApp.exe");

        }

To close the newly created AppDomain in this case, you can do a thread abort or upload the AppDomain. In my code, when working with .net Winform applications, i had issues in unloading the AppDomains and hence I had to work with thread abort. However thread abort it abrut and brute force method to kill that AppDomain and the executing assembly may not close gracefully.

If that assembly is an application, you will have multiple options to handle this thread abort and try and exit gracefully. The various event handlers that you can handle are as below. First place to write handlers is in the MainForm and handle deactivation and handledestroyed events.

        protected override void OnDeactivate(EventArgs e)

        {

            //do your clean up logic here

            base.OnDeactivate(e);

        }

 

        protected override void OnHandleDestroyed(EventArgs e)

        {

            //handle already destroyed. be careful of what you want to clean up here

            base.OnHandleDestroyed(e);

        }

The other option is to handle the ThreadAbortException in the Program.cs file from where the application has been started.  

        static void Main()

        {

            Application.EnableVisualStyles();

            Application.SetCompatibleTextRenderingDefault(false);

            Form1 frm = new Form1();

            try

            {

                Application.Run(frm);

            }

            catch (ThreadAbortException ex)

            {

                //form is Inaccessible by this time and is disposed

                MessageBox.Show(ex.Message);

            }

        }

I also tried the same with WPF applications. A few issues with WPF and AppDomains are listed here. I could get things working with WPF applications as well. I am not sure at this time if all will work well or not, since I haven't done any extensive testing.

A key thing to note with WPF however is setting the correct thread apartment state, else while trying to execute a WPF application in a new AppDomain, you will get an error which reads something like following

"Cannot create instance of 'Window1' defined in assembly 'DummyApp, Version=1.0.2739.17241, Culture=neutral, PublicKeyToken=null'. Exception has been thrown by the target of an invocation.  Error in markup file 'Window1.xaml'."

This may sound tricky since the WPF application on its own runs without issues. It turns out that finding the solution to this issue is also fairly simple since the inner exception states this - "{"The calling thread must be STA, because many UI components require this."}". Hence prior to starting the thread, we need to set the apartment state of the thread as shown below

            Thread th = new Thread(new ThreadStart(func1));

            th.SetApartmentState(ApartmentState.STA);

            th.Start();

With this in place, I found that the WPF application loaded in the AppDomain worked fine. Surprisingly, the AppDomain.Unload method also worked, which had thrown error when working with Winform applications.

As I mentioned earlier, I haven't done extensive testing on this. If you have any other experience or comment to make, do write back.

Comments

My winform apps are published with ClickOnce to our iis6.
When I try to start winform2 from winform1 with the Appdomain.Execute Assembly, I get an error msg:
"request for the WebPermission ... failed.."
What should I do?

Application deployed using click once will be treated as applications from the web and will have restricted security access. You will need to provide for necessary security permissions. I will need to dig up to find out what specific permissions are required.

Thanks for this post... it was very helpful in my WPF project

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter