Loading Assembly Into New Domain

NETCoder

Member
Joined
Aug 9, 2007
Messages
16
Programming Experience
1-3
Hi,

I am developing an add-in inwhich I need to create a new domain to load an assembly and retrieve vb component information. Though I could load the assembly to the current domain using system.reflection.assembly, there is no way I could unload it again. Because system.reflection.assembly does not have unload method. Following is the code which is generating security permission error

Dim pAppset As AppDomainSetup
pAppset = New AppDomainSetup

pappset.applicationbase = "C:\TESTING1\bin" ' Location of the assembly I am trying to load

pappset.ApplicationName = "new domain"
Dim adevidence As System.Security.Policy.Evidence = AppDomain.CurrentDomain.Evidence

Dim pmyEv As System.Security.Policy.Evidence
pmyEv = New System.Security.Policy.Evidence(adevidence)

pAppDom = AppDomain.CreateDomain("secondappdomain", pmyEv, pAppset)

Dim pAssmName As New AssemblyName
pAssmName = AssemblyName.GetAssemblyName("C:\TESTING1\bin\TESTING3.dll"

Dim pAssm As [Assembly]
pAssm = pAppDom.Load(pAssmName) 'here I am getting error
'error message is "Request for the permission of type System.Security.Permissions.FileIOPermission, mscorlib,.......... failed"

'if I add evidence as another parameter
pAssm = pAppDom.Load(pAssmName, pmyEv) 'Here the error is
"Request for the permission of type system.security.Permissions.securitypermission, mscorlib.......... failed"


Can someone help me fix this problem. Is there a easy way to load an assembly? I apprecaite your response.
 
Try creating an AppDomain with the constructor where you only specify name, not Evidence etc. This will use default settings.
VB.NET:
Dim ad As AppDomain = AppDomain.CreateDomain("my new domain")
 
Error

This still would not solve the problem. An error, "Insufficient state to deserialize the object. More information is needed", is returned when I load the assembly.
 
It worked when loading the assembly from the current AppDomains probing path, but this was not what you wanted I see now, you were loading assembly from any given path. I also discovered something interesting, AppDomain.Load method will try to load the assembly into both domains (current and the new) which probably is unwanted, it's only meant to be called from CurrentDomain, she says. The link there to execute code in other assembly also gives some solutions. The easiest is to create a class that inherits MarshalByRefObject to do the work in new domain. For example this class has a method that loads the assembly from a path, creates an instance, then calls a method (using late binding)
VB.NET:
Class adclass
    Inherits MarshalByRefObject

    Public Function test() As String
        Dim a As Reflection.Assembly = Reflection.Assembly.LoadFrom("d:\test\classlibrary1.dll")
        Dim o As Object = a.CreateInstance("ClassLibrary1.Class1")
        Return o.returnstring("hello")
    End Function
End Class
the example class is this simple:
VB.NET:
Public Class Class1

    Public Function returnstring(ByVal input As String)
        Return input
    End Function
End Class
the code that runs the new AppDomain:
VB.NET:
Dim ad As AppDomain = AppDomain.CreateDomain("my new domain")
Dim adc As adclass = ad.CreateInstanceAndUnwrap("WindowsApplication1", "WindowsApplication1.adclass")
MsgBox(adc.test())
AppDomain.Unload(ad)
 
Loading Assembly

Thank your for putting effort to help me. Here is what I found which provide svery detailed information about code access security and loading assemblies into new domain. http://www.15seconds.com/issue/040121.htm

This article says that you can actually load assembly by creating a appdomain security policy level programmatically. Though it has not fixed my problem, I thought it might help you provide me new suggestions. Below is the modified code to load an assembly. It is now producing new exception errors. I am assuming that I not assigning permissions properly. Can you help further. This problem seems to appear in all forums.

VB.NET:
Dim pSt As System.Security.PermissionSet

Dim pFilePerm As FileIOPermission

pFilePerm = New FileIOPermission(PermissionState.Unrestricted)

pFilePerm.AddPathList(FileIOPermissionAccess.AllAccess, strDllPath1)

 

Dim pSecur As SecurityPermission

pSecur = New SecurityPermission(PermissionState.Unrestricted)

 

Dim pDomPoly As PolicyLevel = PolicyLevel.CreateAppDomainLevel()

Dim AllCodeMc As AllMembershipCondition = New AllMembershipCondition

pSt = New System.Security.PermissionSet(pDomPoly.GetNamedPermissionSet("FullTrust"))

pSt.AddPermission(pSecur)

 

pSt.AddPermission(pFilePerm)

Dim polstate As PolicyStatement = New PolicyStatement(pSt)

Dim allCodecg As CodeGroup = New UnionCodeGroup(AllCodeMc, polstate)

pDomPoly.RootCodeGroup = allCodecg

 

Dim pAppDom As AppDomain = AppDomain.CreateDomain("CustomDomain")

pAppDom.SetAppDomainPolicy(pDomPoly)

Try

pAssm = pAppDom.Load("C:\TESTING1\bin\TESTING3.dll") 
' here an exception is raised with an error message which reads like this: 
'"File or Assembly name C:\TESTING1\bin\TESTING3.dll or one of its dependencies not found " .

Can someone explain me why this exception is raised? Thanks.

Catch ex As PolicyException

MessageBox.Show(ex.Message)

Catch ex As Exception

MessageBox.Show(ex.Message)

Finally

AppDomain.Unload(pAppDom)

End Try
 
Last edited by a moderator:
As explained:
AppDomain.Load() is only meant to be called on AppDomain.CurrentDomain.
If not it will try to load the assembly into both domains, and since the path it also not in the current domains probing path it will fail. So read the reply and code suggestion (and linked articles) again and you will make it work.
 
loading and unloading assembly

Thank you. I am new to vb.net so I could not understant completely.
I want to document the assembly created by the developer.
If I load the assembly into current domain. I can not unload the assembly.
Is there any other way to retrieve all properties, methods, fieldsinfo of all classes in the compiled assembly without loading the assembly. Any help is appreciated.
 
Yes, just do like the code in post 4, run a method of a MarshalByRefObject class in a new appdomain, let it do the work of loading the assemblies and query them. When you unload the appdomain the MBRO instance and everything it loaded is also unloaded.
 
CreateInstanceFromAndUnwrap

Following code returns object. but I do not know how to call a method in this object. Is there a way to this?
VB.NET:
Dim pADC As Object = pad.CreateInstanceFromAndUnwrap([Assembly].GetExecutingAssembly.Location, "My_AppLoad.NDomain")

However following syntax throughing specified cast is not valid.
VB.NET:
Dim pADC As NDomain = pad.CreateInstanceFromAndUnwrap([Assembly].GetExecutingAssembly.Location, "My_AppLoad.NDomain")

is any thing wrong?
 
Why not use CreateInstanceAndUnwrap like example in post4?
 
I think you will have to post a sample project for us because I have no idea why it doesn't work for you. The sample in post 4 works just fine.
 
Ok, I figured it out right away, there was a slight difference in method overloads between .Net 2.0 and .Net 1.1 which I didn't initially detect (I did check for this yesterday, but missed this difference). If you take the above example and change this line:
VB.NET:
Dim adc As adclass = ad.CreateInstanceAndUnwrap("WindowsApplication1", "WindowsApplication1.adclass")
to this:
VB.NET:
Dim adc As adclass = ad.CreateInstanceAndUnwrap(Me.GetType.Assembly.FullName, GetType(adclass).FullName)
... then it should work for you too. translate 'adclass' into your own MBRO class. ("NDomain" looks like)
 
Sample project

Hi,

Here is the code in Addin I am developing to load an assembly that the developer has just compiled.

I have included your code in my addin to create new domain.
VB.NET:
    Public Sub Exec(ByVal cmdName As String, ByVal executeOption As vsCommandExecOption, _
ByRef varIn As Object, ByRef varOut As Object, ByRef handled As Boolean) Implements IDTCommandTarget.Exec
        handled = False
        If (executeOption = vsCommandExecOption.vsCommandExecOptionDoDefault) Then
            If cmdName = "MyAddin.Connect.MyAddin" Then
                handled = True
                CreateDomain() [COLOR="Red"]'here I am calling the subroutine[/COLOR]

                Exit Sub
            End If
        End If
    End Sub


    Private Sub CreateDomain()
        Try


        Dim pNewDomain As AppDomain = AppDomain.CreateDomain("TEST")
        Dim clsDomain As NDomain = pNewDomain.CreateInstanceAndUnwrap(Me.GetType.Assembly.FullName, GetType(NDomain).FullName)
[COLOR="Red"]' at this point an exception saying "file or assemblyname Myaddin, or one of its dependence not found"[/COLOR]

        Dim strinfo() As String
        Dim strCls(100, 100) As String
        MessageBox.Show(clsDomain.test("C:\TESTING1\bin\TESTING3.dll", "TESTING3", "TESTING3", strinfo, strCls))
        AppDomain.Unload(pNewDomain)
        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    End Sub


In a new class I have added..
Class NDomain
    Inherits MarshalByRefObject

[COLOR="Red"]'here the parameters are location of the dll, name of the assembly,
'name of the project, string to return inform, string array to return class Id 'information[/COLOR]

    Public Function test(ByRef strDllPath1 As String, ByRef strASSM As String, _
ByRef strProj As String, ByRef strInfo() As String, ByRef strCls(,) As String) As String

        Dim i As Long
        Dim att() As Object
        Dim GuidAtt As System.Runtime.InteropServices.GuidAttribute
        Dim titleAttr As System.Reflection.AssemblyTitleAttribute
        ' <Assembly: AssemblyDescription("My Assembly Description")> 
        Dim descAttr As System.Reflection.AssemblyDescriptionAttribute
        ' <Assembly: AssemblyCompany("My Company")> 
        Dim companyAttr As System.Reflection.AssemblyCompanyAttribute
        ' <Assembly: AssemblyProduct("My Product Name")> 
        Dim productAttr As System.Reflection.AssemblyProductAttribute
        ' <Assembly: AssemblyCopyright("My Copyright")> 
        Dim copyrtAttr As System.Reflection.AssemblyCopyrightAttribute
        ' <Assembly: AssemblyTrademark("My Trademark")> 
        Dim trademkAttr As System.Reflection.AssemblyTrademarkAttribute
        'following are variables to retrieve versions information of the dll
        'Assembly version shown in the assemblyinfo.vb
        Dim AssVer As System.Reflection.AssemblyVersionAttribute
        'Following two versions (product version and five version of dll)
        'are not shown in the assemblyinfo.vb file.
        'file version of dll
        Dim FileVerAttr As System.Reflection.AssemblyFileVersionAttribute
        'Product version
        Dim ProdVer As System.Reflection.AssemblyInformationalVersionAttribute  ' AssemblyInformationalVersionAttribute
        Dim onetype As System.Type
        Dim twname As String
        Dim strNotSame As String
        Dim onename As String
        Dim cnt As Integer
        Dim pVerInfo As FileVersionInfo
        Dim stritem As String
        Dim strFileVer() As String
        Dim strAssVer As String
        Dim pAssNam As System.Reflection.AssemblyName
        Dim strReturn As String
        Try
            Dim pAssm As Reflection.Assembly = Reflection.Assembly.LoadFrom(strDllPath1)
            att = pAssm.GetCustomAttributes(GetType(System.Runtime.InteropServices.GuidAttribute), False)
            If att.Length > 0 Then
                GuidAtt = DirectCast(att(0), System.Runtime.InteropServices.GuidAttribute)
            End If

            pAssNam = pAssm.GetName()
            If Not pAssNam.Name = strASSM Then
                strReturn = "AssemblyName" & vbNewLine
            End If

            For Each oneModule As Reflection.Module In pAssm.GetLoadedModules()
                'onename &= oneModule.Name & vbNewLine
                For Each onetype In oneModule.GetTypes()
                    If Not InStr(onetype.Name, "_", CompareMethod.Text) > 0 Then
                        If Not Left(onetype.FullName, InStr(onetype.FullName, ".", CompareMethod.Text) - 1) = strProj Then
                            strReturn = "Root Namespace" & vbNewLine
                        End If

                        strCls(cnt, cnt) = onetype.FullName
                        For Each oneField As Reflection.FieldInfo In onetype.GetFields()
                            'onename &= "Field: " & oneField.ToString() & vbNewLine
                            If oneField.Name = "ClassId" Then
                                strCls(cnt, cnt + 1) = "{" & CType(oneField.GetValue(Nothing), String) & "}"
                            End If
                        Next oneField
                        cnt = cnt + 1
                    End If
                Next onetype
            Next oneModule

            'gets the applications resources info
            For Each twname In pAssm.GetManifestResourceNames()
                strCls(cnt, cnt) = twname
                cnt = cnt + 1
            Next


            'get the other assembly attribute of the built assembly
            att = pAssm.GetCustomAttributes(GetType(System.Reflection.AssemblyTitleAttribute), False)
            If att.Length > 0 Then
                titleAttr = DirectCast(att(0), AssemblyTitleAttribute)
                ReDim Preserve strInfo(i)
                strInfo(i) = titleAttr.Title
                i = i + 1
            End If

            ' Get the Description Attribute 
            att = pAssm.GetCustomAttributes(GetType(System.Reflection.AssemblyDescriptionAttribute), False)
            If att.Length > 0 Then
                descAttr = DirectCast(att(0), AssemblyDescriptionAttribute)
                ReDim Preserve strInfo(i)
                strInfo(i) = descAttr.Description
                i = i + 1
            End If

            ' Get the Company Attribute 
            att = pAssm.GetCustomAttributes(GetType(AssemblyCompanyAttribute), False)
            If att.Length > 0 Then
                companyAttr = DirectCast(att(0), AssemblyCompanyAttribute)
                ReDim Preserve strInfo(i)
                strInfo(i) = companyAttr.Company
                i = i + 1
            End If
            Return "true"
        Catch ex As Exception
            MessageBox.Show(ex.Message)
            Return "false"
        End Try

    End Function
End Class
 

Attachments

  • Loadassembly.zip
    24.8 KB · Views: 27
Last edited:
Addin Project

Hi,

Attached is addin project. I could not send both of them together. Since addin project comes with setup project, the size of the zip file is big and I could attach it. So, I removed it and sending it. Still you should be able to see the code.

Again, I really appreciate your effort you are putting to help me. Hope if this problem could be fixed. Thanks.
 

Attachments

  • addin1.zip
    27.4 KB · Views: 22
Back
Top