The preceding discussion about locating and loading assemblies refers to assemblies that are known at compile time through the application's references. There is an alternative method of locating and loading an assembly that is useful for certain scenarios.
In this technique, the location of the assembly is supplied by the application, using a URL or filename. The normal rules for locating the assembly do not apply — only the location specified by the application is used.
The location is just a string variable, so it may come from a configuration file or a database. In fact, the assembly to be loaded may be newly created, and perhaps did not even exist when the original application was compiled. Because the information to load the assembly can be passed into the application on the fly at run time, this type of assembly loading is called dynamic loading.
The Assembly class has a shared method called LoadFrom that takes a URL or filename and returns a reference to the assembly at that location. Here's a code example of LoadFrom in action, getting an assembly reference from a URL:
Dim asmDynamic As [Assembly] asmDynamic = [Assembly].LoadFrom("http://www.dotnetmasters.com/DynamicWindows.dll")
As previously discussed, the brackets around Assembly are needed because it is a reserved keyword in Visual Basic. The brackets indicate that the word applies to the Assembly class, and the keyword is not being used.
After these lines are executed, the code contains a reference to the assembly at the given location. That enables the reflection operations discussed earlier for finding types in the assembly. Recall that one such operation is getting a reference to a particular type (which could be a class, a structure, or an enumeration) in the assembly.
For dynamic loading, normally the GetType method of the Assembly class is used to get the reference, using a string that represents the identification of the type. The identification consists of the full namespace path that uniquely identifies the type within the current application. Once a reference to a type is obtained, an instance of the type can be created, even though the assembly was loaded dynamically.
For example, suppose that you wanted to get an instance of a certain form in the assembly, with a namespace path of MyProject.MainWindow. The following line of code would get a reference to the type for that form:
Dim typMyWindow As Type = formAsm.GetType("MyProject.MainWindow")
The type reference can then be used to generate an instance of the type. To do this, you need another class in the System namespace called the Activator class. This class has a shared method called CreateInstance, which takes a type reference and returns an instance of that type. You could, therefore, get an instance of the form with these lines:
Dim window As Object window = Activator.CreateInstance(typeMyWindow)
CreateInstance always returns a generic object. That means it may be necessary to coerce the returned reference to a particular type to gain access to the type's interface. For example, assuming that you knew the object was actually a WPF window, you could cast the preceding instance into the type of System.Windows.Window and then do normal operations available on that window:
Dim FormToShow As Form = CType(objForm, Window) FormToShow.MdiParent = Me FormToShow.Show()
At this point, the form will operate normally. It will behave no differently from a form that was in a referenced assembly.
If the newly loaded form needs to load other classes in the dynamic assembly, nothing special needs to be done. For example, suppose that the form just shown needs to load an instance of another form, named Window2, that resides in the same dynamically loaded assembly. The standard code to instantiate a window will work fine. The CLR will automatically load the Window2 type, because it already has a reference to the assembly containing Window2.
Furthermore, suppose that the dynamically loaded form needs to instantiate a class from another DLL that is not referenced by the application. For example, suppose that the form needs to create an instance of a Customer object, and the Customer class is in a different DLL. As long as that DLL is in the same folder as the dynamically loaded DLL, the CLR will automatically locate and load the second DLL.
To see dynamic loading in action, try the following step-by-step example:
Imports System.Reflection
Private Sub Button_Click_1(sender As Object, e As RoutedEventArgs) Dim sLocation As String = "C:TempProVB2012_DynamicWindows.dll" If My.Computer.FileSystem.FileExists(sLocation) Then Dim sType As String = "ProVB2012_DynamicWindows.MainWindow" Dim DynamicAssembly As [Assembly] = _ [Assembly].LoadFrom(sLocation) Dim DynamicType As Type = DynamicAssembly.GetType(sType) Dim DynamicObject As Object DynamicObject = Activator.CreateInstance(DynamicType) ' We know it's a form - cast to form type Dim WindowToShow As Window = CType(DynamicObject, Window) WindowToShow.Show() Else MsgBox("Unable to load assembly " & sLocation & _ " because the file does not exist") End If End Sub
Notice that the ProVB2012_DynamicWindows.dll was created and compiled after the ProVB2012_Ch17.exe project that loaded it. It is not necessary to recompile or even restart ProVB2012_Ch17.exe to load a new assembly dynamically, as long as ProVB2012_Ch17.exe knows the location of the assembly and the type to be loaded from it.
The previous code examples include hard-coded strings for the location of the assembly and the identification of the type. There are uses for such a technique, such as certain types of Internet deployment of an application. However, when using dynamic loading, it is common for these values to be obtained from outside the code. For example, a database table or an XML-based configuration file can be used to store the information.
This enables you to add new capabilities to a .NET application on the fly. A new assembly with new functionality can be written, and then the location of the assembly and the identity of the type to load from the assembly can be added to the configuration file or database table. Of course this same behavior is completely unacceptable in a fully managed environment such as Windows RT.
Unlike application assemblies automatically located by the CLR, which must be in the application's directory or a subdirectory of it, dynamically loaded assemblies can be anywhere the application knows how to access. Possibilities include the following:
The security privileges available to code vary, depending on where the assembly was loaded from. Code loaded from a URL via HTTP has a very restricted set of privileges by default compared to code loaded from a local directory.