Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create App Domain to use with plugins: "Type in assembly is not marked as serializable

I'm trying to enable the capability of using plugins in my WPF application. As far as my understanding goes, I need (well, not need, but it's suggested) to create an additional app domain.

For this, I'm doing the following on startup in my App.xaml.cs:

    private void LoadPlugins()
    {
        // Create and polish plugin app domain
        AppDomain pluginAppDomain = AppDomain.CreateDomain("MyProject Plugin Container", null);
        pluginAppDomain.UnhandledException += PluginAppDomain_UnhandledException;

        //TODO: Load plugins from dlls
    }

    private void PluginAppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Logger.FatalException("PluginAppDomain", e.ExceptionObject as Exception);
    }

But attaching the UnhandledException event fails with exception:

Type 'MyProject.App' in assembly 'MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1337' is not marked as serializable.

What could be the issue?

like image 895
SeToY Avatar asked Oct 07 '13 09:10

SeToY


1 Answers

.NET Remoting needs to access PluginAppDomain_UnhandledException from the child AppDomain. PluginAppDomain_UnhandledException is an instance method and so the child AppDomain needs to access it through the current object (this) from this class. There are two ways to do this. One is to have the class derive from MarshalByRefObject which will allow it's instances to be accessed from other AppDomains via proxies. The other way it to decorate the class with the SerializableAttribute and let .NET Remoting know that instance of this class can be serialized to other AppDomains. This is why you get the serializable error. Your class does not 1) derive from MarshalByRefObject and 2) is not marked as Serializable.

As far as I know it isn't a very good idea to subscribe to this event from a different AppDomain. You see even if you make this class and the class of Logger to be derived from MarshalByRefObject you will still be a long way from a good solution because you are passing exceptions between AppDomains. So for this to work you will need all exceptions passed between the AppDomains to be serializable and their assemblies loaded in both AppDomains. This might be a problem if you want to isolate plugins.

If I were you I would first make my application plugin-aware without dealing with separate AppDomains. The whole thing with concering AppDomains and UnhandleExceptions is quite complicated.

Then I might try your approach but with MarshalByRefObject derived objects (only the Logger is enough if the PluginAppDomain_UnhandledException is made static) and pass only strings to the Logger's methods.

Otherwise I would just give a separate log to the plugin or use the Windows Event Log.

like image 122
Panos Rontogiannis Avatar answered Oct 18 '22 20:10

Panos Rontogiannis