|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
GetAssemblies SerializationExceptionI 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 |
|||||||||||||||||||||||