Hi,

I am attempting to write a plugin framework, this in itself is not too
difficult. What I would like to achieve is a plugin framework where the
plugins can be updated on the fly. The problem that this presents is
once the plugin files are loaded into an application domain the plugin
files on the disk stay locked until that application domain is
unloaded, even if no instances of the plugins are running.

So to get around this the plugins must *only* be ever loaded into an
application domain that can be unloaded. This is where it gets
complicated. Normally I obtain a reference to an assembly using
system.reflection.assembly.loadfrom and pass the filename as a
parameter, however this loads it into the current application domain.

After many frustrating days, trying to load an assembly into a specific
app domain (ie not the current app domain), I have simplified my code
right down to the following:

Two subs from the class that manages the plugins, one lists the
assemblies in an app domain, the other tries to load an assembly into
an app domain.

Public Overridable Sub ListAssembliesInDomain(ByVal Domain As
System.AppDomain)
Dim ContainedAssembly As System.Reflection.Assembly
Dim Assemblies() As System.Reflection.Assembly

Try
Debug.WriteLine(vbCrLf & "Assemblies in Domain " &
Domain.SetupInformation.ApplicationName)
Assemblies = Domain.GetAssemblies()

For Each ContainedAssembly In Assemblies
Debug.WriteLine(ContainedAssembly.ToString & " " &
ContainedAssembly.CodeBase)
Next
Debug.WriteLine("")

Catch ex As Exception
Debug.WriteLine(ex.ToString)
End Try

End Sub ' ListAssembliesInDomain




Public Overridable Sub CheckForNewPlugins()
Dim strAllFolders() As String
Dim strPluginFolder As String
Dim strAllFiles() As String
Dim strPluginFile As String

Try
' See if we need to initialize the plugin folders
If strFolderPluginsNew = "" Or strFolderPluginsStore = "" Or
strFolderPluginsRunning = "" Then

' Read the folder paths from the app.config file
strFolderPluginsNew =
System.Configuration.ConfigurationSettings.AppSettings(keyPluginsNew)
strFolderPluginsStore =
System.Configuration.ConfigurationSettings.AppSettings(keyPluginsStore)
strFolderPluginsRunning =
System.Configuration.ConfigurationSettings.AppSettings(keyPluginsRunning)

' Ensure that the paths exist and have a trailing \
Vigilant.Common.InitializeFolder(strFolderPluginsNew)
Vigilant.Common.InitializeFolder(strFolderPluginsStore)
Vigilant.Common.InitializeFolder(strFolderPluginsRunning)
End If

' Get the sub folders of the new plugin folder
strAllFolders =
System.IO.Directory.GetDirectories(strFolderPluginsNew)

' Check that we have some sub folders of the new plugin folder
If Not strAllFolders Is Nothing Then

' Loop through each sub folder
For Each strPluginFolder In strAllFolders

' Create an application domain that we can load any plugins
' found in this folder into, once we are finished we can
' unload the application domain and the plugin files will
' no longer be locked. Once they are unlocked we can
' move them to the appropriate location.
objPluginDomainTemp = System.AppDomain.CreateDomain("Temp
Plugin Domain", AppDomain.CurrentDomain.Evidence,
AppDomain.CurrentDomain.SetupInformation)
objPluginDomainTemp.AppendPrivatePath(strPluginFolder)

' Get a list of all the exe's in this plugin folder
strAllFiles = System.IO.Directory.GetFiles(strPluginFolder,
"*.exe")

' Check that we found some exe's in this plugin folder
If Not strAllFiles Is Nothing Then

' Loop through the list of exe's in the plugin folder
For Each strPluginFile In strAllFiles

' For debugging purposes list the assemblies that are
' currently loaded in the temporary plugin app domain
ListAssembliesInDomain(objPluginDomainTemp)

Try

' Attempt to execute the assembly within the temp plugin
app domain
'
' NB: The aim of this is just to load the assembly into
the temp plugin app domain
' other ways have been tried, but are less straight
forwards, so during the
' process of trying to track this bug down, I reached the
conclusion that
' the most straight forwards way to load the assembly
into a different app domain
' was by causing it to be executed.
objPluginDomainTemp.ExecuteAssembly(strPluginFile,
objPluginDomainTemp.Evidence)

Catch ex As Exception
Debug.WriteLine(ex.ToString)
End Try

' For debugging purposes, we want to now see if the
assembly
' we executed is now listed in the temp plugin app domain
'
' It's within this call that an exception is thrown
ListAssembliesInDomain(objPluginDomainTemp)


Next
End If

If Not objPluginDomainTemp Is Nothing Then
AppDomain.Unload(objPluginDomainTemp)
End If

Next
End If

Catch ex As Exception
Debug.WriteLine(ex.ToString)
End Try

End Sub ' CheckForNewPlugins


The Plugin File is just a console app with the following code

Module Module1

Sub Main()
Debug.WriteLine("Plugin Executed")
End Sub

End Module

I've got dbmon running and get the following debug output:

3600:
Assemblies in Domain aab4bae7
3600: mscorlib, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
file:///c:/windows/microsoft.net/framework/v1.1.4322/mscorlib.dll
3600:
3600: Plugin Executed
3600:
Assemblies in Domain aab4bae7
3600: System.Runtime.Serialization.SerializationException: Insufficient
state to deserialize the object. More information is needed.

Server stack trace:
at System.UnitySerializationHolder.GetRealObject(StreamingContext
context)
at
System.Runtime.Serialization.ObjectManager.ResolveObjectReference(ObjectHolder
holder)
at System.Runtime.Serialization.ObjectManager.DoFixups()
at
System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler
handler, __BinaryParser serParser, Boolean fCheck, IMethodCallMessage
methodCallMessage)
at
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream
serializationStream, HeaderHandler handler, Boolean fCheck,
IMethodCallMessage methodCallMessage)
at
System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeObject(MemoryStream
stm)
at
System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeMessageParts(MemoryStream
stm)
at
System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage.FixupForNewAppDomain()
at
System.Runtime.Remoting.Channels.CrossAppDomainSink.SyncProcessMessage(IMessage
reqMsg)

Exception rethrown at [0]:
at
System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage
reqMsg, IMessage retMsg)
at
System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&
msgData, Int32 type)
at System.AppDomain.GetAssemblies()
at VMFacilitator.VMPluginManager.ListAssembliesInDomain(AppDomain
Domain) in C:\Visual Studio Projects\OBM\Vigilant
Auditing\Monitoring\VMFacilitator\VMPluginManager.vb:line 38

Line 38 is:

Assemblies = Domain.GetAssemblies()

Can anyone help / does anyone have any suggestions with why this is
happening?

TIA,
Alex