Simplest Example


As I’ll do throughout this book, I’ve written the simplest example I could think of to demonstrate the operation of the .NET Framework. You can download this sample and all the other code examples in this book from http://www.introducingmicrosoft.net. For this sample I wrote a .NET object server, the .NET replacement for an ActiveX DLL in Visual Basic 6, and its accompanying client. The server provides a single object exposing a single method, called GetTime, that provides the current system time in the form of a string, either with or without the seconds digits. Even though I wrote the server in Visual Basic and the client in C#, I didn’t have to use Visual Studio. In fact, I wrote both applications in Notepad and built them with the command line tools provided in the .NET Framework SDK. I do show examples of using Visual Studio .NET in other sections of this chapter. Note: You can download a copy of the .NET Framework SDK at http://www.msdn.microsoft.com/net.

A .NET Framework object sample begins here.

You’ll notice when we begin looking at the code that it seems, at least superficially, quite similar to the classic Visual Basic code you are already familiar with. However, Microsoft made a number of important changes to the .NET version of Visual Basic to enable it to use the .NET common language runtime classes and interoperate correctly with the other common language runtime languages. A full discussion of these changes is far beyond the scope of this book, but here are two examples. The text string displayed in a button is now stored in a property called Text (as for a TextBox) rather than in the Caption property used in Visual Basic 6. This change will break your existing app’s compilation but is trivial to fix once the compiler shows it to you. Other changes won’t break your compilation, but they can change your program’s behavior in subtle and far-reaching ways. For example, a Visual Basic 6 object is destroyed immediately when its reference count reaches zero, but a zero- reference Visual Basic .NET object won’t actually be destroyed until a garbage collection occurs, some indeterminate amount of time later. (See the discussion later in this chapter.) Your app might be able to live with the new behavior, or it might require a redesign. These changes mean that you cannot simply compile your existing Visual Basic code in Visual Studio .NET and expect it to work correctly. It will take some effort to port; probably not an enormous amount, but more than the zero-level you were hoping for.

Visual Basic .NET contains a number of critical language differences from Visual Basic 6.

Note

Visual Studio .NET contains an upgrade tool that runs automatically when you open a Visual Basic 6 project. It flags the changes that it detects and suggests fixes. The language has definitely gotten more powerful. If you want the cool Internet features of .NET, you’ll probably think it’s worth the effort to switch. Even if you’re just writing single-user desktop form applications, you may still find the versioning support and the easier deployment and cleanup to be worth it.

Listing 2-1 shows the code listing for my sample object server. Looking at this code, we first see the Imports directive. This new feature of Visual Basic .NET tells the compiler to “import the namespaces.” The term namespace is a fancy way to refer to the description of a set of prefabricated functionality provided by some class somewhere. It is conceptually identical to a reference in your Visual Basic 6 project. The names following Imports tell the engine which sets of functionality to include the references for. In this case, Microsoft.VisualBasic is the one containing the definition of the Now function that I use to fetch the time. If you use Visual Basic from within Visual Studio .NET, the Microsoft.VisualBasic namespace is imported automatically without needing an explicit Imports statement.

Listing 2-1: Visual Basic code listing of simplest object server.

start example
‘ Import the external Visual Basic namespace, allowing me to ‘ access the Now function by its short name. Imports Microsoft.VisualBasic ‘ Declare the namespace that clients will use to access ‘ the classes in this component. Namespace TimeComponentNS ‘ Declare the class(es) that this DLL will provide to a client. ‘ This is the same as Visual Basic 6. Public Class TimeComponent ‘ Declare the function(s) that this class will provide to a client. ‘ This, too, is the same as VB6. Public Function GetTime(ByVal ShowSeconds As Boolean) As String ‘ The formatting of dates, and the returning of values of ‘ functions, changed somewhat in Visual Basic .NET. If (ShowSeconds = True) Then Return Now.ToLongTimeString Else Return Now.ToShortTimeString End If End Function End Class End Namespace
end example

We next see the directive Namespace TimeComponentNS. This is the declaration of the namespace for the component we are writing, the name that clients will use when they want to access this component’s functionality. I discuss namespaces later in this chapter. Again, if you are using Visual Studio .NET, this declaration is made automatically.

Next come the class and function declarations, identical to Visual Basic 6. Finally, I put in the internal logic of fetching the time, formatting it into a string and returning it to the client. These too have changed slightly. The property Now still fetches the date, but formatting it into a string is now done with a method of the new .NET class DateTime rather than a separate function. Also, a Visual Basic function specifies its return value using the new keyword Return instead of the syntax used in earlier versions.

This section describes the code of my .NET object server.

I next compiled my code into a DLL, named TimeComponent.dll, using the command line tools that come with the .NET Framework SDK. Anyone who cares to can find the command line syntax in Makecomponent.bat, which you can download from the book’s Web site. The result may look like a plain old DLL to you, but it’s actually very different inside. The Visual Basic .NET compiler didn’t convert the Visual Basic code to native code; that is, to specific instructions for the microprocessor chip inside your PC. Instead, the DLL contains my object server’s logic expressed in MSIL (again, for Microsoft Intermediate Language; IL for short), the intermediate language that I introduced in the “Solution Architecture” section in this chapter. All common language runtime language compilers produce this IL rather than native processor instructions, which is how the runtime can run seamlessly with so many different languages. The DLL also contains metadata that describes the code to the common language runtime system. This metadata is in a runtime- required format that describes the contents of the DLL: what classes and methods it contains, what external objects it requires, what version of the code it represents, and so on. Think of it as a type library on steroids. The main difference is that a COM server could sometimes run without a type library, whereas a .NET object server can’t even begin to think about running without its metadata. I discuss this metadata further in the section “Assemblies” later in the chapter.

Compiling the Visual Basic code produces a DLL containing intermediate language and metadata.

Having written my server, I next need a client to test it. To demonstrate the fact that .NET works between different languages, I wrote this client in C#. Rather than convert from Visual Basic 6 to Visual Basic .NET, many of my customers are converting directly to C#. If you look at the code in Listing 2-2, you’ll see that it’s fairly easy to understand at this level of simplicity. In fact, given the enhancements to Visual Basic .NET to support the common language runtime’s object-oriented features such as inheritance (described later in this chapter), I’ve heard programmers after a few beers describe C# as “VB with semicolons” or occasionally “Java without Sun.” Either one of these can start a fistfight if you say it too loudly in the wrong bar in Redmond or Sunnyvale.

Visual Basic and C# resemble each other more than either community likes to admit.

Listing 2-2: C# code listing of simplest object client.

start example
// Import the namespaces that this program uses, thereby allowing // us to use the short names of the functions inside them. using System ; using TimeComponentNS ; class MainApp { // The static method "Main" is an application’s entry point. public static void Main() { // Declare and create a new component of the class // provided by the VB server we wrote. TimeComponent tc = new TimeComponent ( ) ; // Call the server’s GetTime method. Write its // resulting string to a console window. Console.Write (tc.GetTime (true)) ; } }
end example

Our client example starts with importing namespaces, which in C# requires the directive using. Our sample client imports the System namespace (described in detail later in this chapter), which contains the description of the Console.Write function, and also imports our time component’s namespace. Additionally, we have to explicitly tell the compiler in which DLL it will find our component’s namespace, which we do in the compiler batch file Makeclient.bat (not shown). Visual Studio provides an easy user interface for this.

Execution of any C# program begins in a static (shared) method called Main. In that method, we can see that our client program uses the C# new operator to tell the runtime engine to find the DLL containing our TimeComponent class and create an instance of it. The next line calls the object’s GetTime method and then uses the System namespace’s Console.Write method to output the time string in a command line window. The C# compiler in this case produces an EXE file. Like the server DLL, this EXE does not contain native instructions, but instead contains intermediate language and metadata.

The C# client also compiles to intermediate language.

When I run the C# client executable, the system loader notes that the executable is in the form of managed code and loads it into the runtime engine. The engine notes that the EXE contains IL, so it invokes the just-in- time compiler, or JITer. As I discussed earlier, the JITer is a system tool that converts IL into native code for whichever processor and operating system it runs on. Each different architecture will have its own JITer tailored to that particular system, thereby allowing one set of IL code to run on multiple types of systems. The JITer produces native code, which the common language runtime engine will begin to execute. When the client invokes the new operator to create an object of the TimeComponent class, the common language runtime engine will again invoke the JITer to compile the component DLL’s IL just-in-time and then make the call and report the results. The output is shown in Figure 2-3.

click to expand
Figure 2-3: Console output of sample TimeClient program.

This run-time compilation model works well for some classes of applications, such as code downloaded from the Internet for a page you just surfed to, but not for others, say, Visual Studio, which you use all day, every day, and update once or twice a year. Therefore, an application can specify that JIT compilation is to be performed once, when the application is installed on a machine, and the native code stored on the system as it is for non-.NET applications. You do this via the command-line utility program Ngen.exe, the native image generator, not shown in this example.

The IL is compiled just-in- time when the client and its component are run.

When the client used the new operator to create the object, how did the loader know where to find the server DLL? In this case, the loader simply looked in the same directory as the client application. This is known as a private assembly, the simplest type of deployment model in .NET. A private assembly can’t be referenced from outside its own directory. It supports no version checking or any security checking. It requires no registry entries, as a COM server would. To uninstall a private assembly, all you have to do is delete the files, without performing any other cleanup. Obviously, this simple case, while effective in situations like this, isn’t useful in every situation—for example, when you want to share the same server code among multiple clients. I discuss these more complex scenarios in the section on assemblies later in this chapter.

The loader finds the DLL requested by the client by looking in the client application’s directory.




Introducing Microsoft. NET
Introducing Microsoft .NET (Pro-Developer)
ISBN: 0735619182
EAN: 2147483647
Year: 2003
Pages: 110

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net