Probably every developer on the planet has heard the term "thin client". Citrix Systems heard it and came up with WinFrame. Microsoft borrowed that idea and came up with Windows Terminal Services. Developers apply the concept to Web programming where the browser plays the role of thin client. Occasionally, thin client is applied to Windows programming. Well, the verse I am singing about today is one that illustrates an avenue for the revitalization of real, thin client programming with Windows Forms in .NET.
I quickly picked up on the nuance of this verse after my own exploration with Reflection and Assemblies in my-soon-to-be-released book "Visual Basic .NET Unleashed". But, it was David White at Microsoft that pointed out the power of Assemblies as they relate to Windows thin client programming, and Billy Hollis' article the "Death of the Browser" that cleared up some of the technical aspects for me. In this article I am singing a verse that has its origins at Microsoft and whose melody I first heard from David White, and later, vicariously from Billy Hollis.
A thin client application is an application that has a very small kernel or presentation layer and the actual presentation and business logic is rendered and presented in that client. In Web programming the browser is the thin client and the business logic and presentation is derived programmatically across the Web. Traditionally Windows thin client meant that the forms contained the presentation layer but the logic resided somewhere else, usually in DLLs.
The benefit of Web applications is that users browse to your site and they request a page. There is no setup, no configuration, and no patches to disseminate. If you wanted to update you program then update the Web pages on your server and the consumer got the updated page next time they used the site. The detractor is that historically Web pages haven't provided as many opportunities for a rich presentation layer as Windows Forms, and as good as ASP.NET is, try creating a shaped form in ASP.NET. That is to say, ASP.NET is much better than ASP, but you can still greater richer presentations in Windows Forms.
The benefit of Windows application programming is exactly that you can create a rich presentation layer, and Windows programming felt like programming; Web programming used to be a combination of scripting and programming. The bad side of Windows programming was "DLL Hell", deployment, configuration, and sending patches.
Optimally, we would want to combine the good things about Web programming and Windows Programming, ease of deployment and a rich presentation layer, while getting rid of the bad things, "DLL Hell" and a convoluted implementation model. This is exactly what this article is about. You can create Windows Applications in VB.NET that provide all the richness of Windows components and forms and ease of deployment of the web. How you ask? The answer is simple: dynamically loading assemblies from the Web.
The idea is straight forward. The developer writes a very thin startup application. The user starts the application, which in turn downloads the rest of the application seamlessly from the Web. The implications are that clients have the .NET Framework installed and a connection to the Internet. That is all that is required of clients. If they are running any .NET applications then they will have the .Net Framework installed, and even if consumers do not have external access to the Internet, they certainly can have internal HTTP access to your network.
The upshot is that you can use HTTP automatic updating on an internal network or over the Internet, and the technical requirements are the same.
All you have to do is get a nugget-sized application loader to your clients, which can itself be downloaded from the Internet. To be clear here, I am not talking about applications that load and display a dialog that indicates you should check the Internet for updates and patches, download the patches, install them and re-boot. I am specifically talking about seamless and automatic updating.
Why all of the literary foreplay? Well, there are a lot of pretenders to thin client development and there are a few real-deals. This is the real deal.
Automatically Updating Windows Forms Applications
To create a thin client application with Windows Forms you will need to create an application loader. This could be a splash screen or application launcher; all the loader has to have in it is the code to request the assembly from the IIS server hosting the DLLs.
The parts of the client downloaded from the Web will contain the forms and classes that implement your solution. The loader will use Reflection and the Assembly class to seamlessly request the rest of your application, which will be compiled into DLL assemblies on the Web host. If your application has already requested DLLs and they are stored in the cache on a particular client then they will not be nor need be retrieved from the Web host.
Listing 1 demonstrates a complete listing of a simple loader and DLL that contains a form. You can test the example by compiling the application and DLL, and copying the DLL to an IIS server on your PC or network.
Listing 1: Thin client application representing the main form and the supporting forms defined in an assembly downloaded from the Web.
1: ' HttUpdated.dll - A class library containing a single 2: ' form that we will download on demand from the Web 3: 4: Public Class Form1 5: Inherits System.Windows.Forms.Form 6: 7: #Region " Windows Form Designer generated code "[...] 8: 9: Private Sub Button1_Click(ByVal sender As System.Object, _ 10: ByVal e As System.EventArgs) Handles Button1.Click 11: MsgBox("Updated from the web!") 12: End Sub 13: 14: End Class 15: 16: ' ThinClient.exe - A Windows Forms-based 17: ' application that plays the role of main form and loader 18: 19: Imports System.Reflection 20: 21: Public Class Form1 22: Inherits System.Windows.Forms.Form 23: 24: #Region " Windows Form Designer generated code "[...] 25: Private Sub MenuItem4_Click(ByVal sender As System.Object, _ 26: ByVal e As System.EventArgs) Handles MenuItem4.Click 27: 28: Const AssemblyName As String = _ 29: "HTTP://localhost/WindowsForms/HttpUpdated.dll" 30: 31: Dim A As [Assembly] = _ 32: [Assembly].LoadFrom("HTTP://localhost/WindowsForms/HttpUpdated.dll") 33: 34: Dim Form As Form = A.CreateInstance("HttpUpdated.Form1") 35: Me.AddOwnedForm(Form) 36: 37: Form.Show() 38: End Sub 39: 40: End Class
Lines 1 through 14 represent the form in the HttpUpdated.dll that represents the part of the application to be updated from the Web. Lines 16 through 41 represent the Windows Forms application that plays the role of loader. The ThinClient.exe application acts as a common menu-based main form. When the user clicks a menu item the form representing some functionality of the system is displayed. What the user does not see is that the form is dynamically being requested using HTTP.
Line 28 defines the path to the DLL on the Web. In the example program I am using the IIS server running on my PC, but it works equally well over the Internet. Of course, you could store the path in an external location like the registry or even request it from the user. On lines 28 and 29 the shared method Assembly.LoadFrom is used to load the assembly. Think of this as LoadLibrary for DOTNET. Assembly is both a reserved word and a class. When we use a reserved word we have to place it in brackets, otherwise we will get an error indicating that the keyword does not name a type.
Line 31 loads the assembly. The client's cache is checked first. If the cache on the client machine contains the assembly then it is loaded from the cache; if not, then the assembly is loaded from the Internet. (An unavailable connection would raise an exception. You will have to anticipate this by writing an exception handler.) Line 34 creates an instance of the type using the namespace and class name, "HttpUpdated.Form1". We wrote both sets of code, so we know what these will be. (Alternatively, we could use Reflection to inquire about available types. This latter approach isn't applicable here as we want the application to appear as if the form were a homogenous part of our application.)
Line 34 creates the instance of the form, adds it to the loader form's list of owned forms, and shows the HTTP-loaded form. From the perspective of the user everything appears to be normal. Depending on the connection speed to the Internet users may notice a slight delay the first time a form is cached from the Web.
How many features you include in your applications depends on your needs. There are no limitations simply because the forms are downloaded from a Web server. However, if your DLLs are huge then the initial delays may appear to make the application seem a little sluggish.
One strategy is to partition your application into reasonable chunks of behavior. For example, if MS-Word were partitioned to download from the Web (instead of asking for install disks) then the Spell Checker might be in a partition separate from the Macros tools.
An added benefit is that you only need download the primary assembly. Related assemblies can be referenced on the Web server. When the initially downloaded assembly tries to interact with a referenced assembly it will automatically return to its original source—in this example, http://localhost/WindowsForms—to look for the referenced assembly.
The net result is that if the loader downloads the main assembly, then the downloaded assembly can refer to additional forms in other assemblies as if they were local to the client. .Net is smart enough to go get additional assemblies from the web without your interdiction. Plainly put, you only have to request the initial assembly using the LoadFrom method and everything is business as usual.
There are only a couple of things that will trip you up: permissions and security. You will need to create a virtual directory in IIS. The permissions should be set up to allow Reading, and Execute Permissions should be Script only (use the following figure as a guide).
Figure 1: Permissions to facilitate downloading assemblies for Windows Forms applications.
The other step you will likely have to take in production is to request security permissions. Essentially, you will need to request the permissions your specific application needs. This will mean some coordination with administrators when you deploy your application.
Security is a huge topic in itself. While we don't have time to go in-depth about security issues here, look to future articles for information on the Policy Manager and Security.
About the Author
Paul Kimmel is a freelance writer for Developer.com and CodeGuru.com. Look for cool Visual Basic .Net topics in his upcoming book Visual Basic .Net Unleashed available in January of 2002. Paul founded Software Conceptions, Inc. in 1990. Contact Paul Kimmel at firstname.lastname@example.org for help building VB.NET applications or migrating VB6 applications to .NET.