visual
使用.NET Framework,Microsoft Visual Basic开发人员可以创建健壮的、在先前的Visual Basic版本中很难编写的应用程序。本文将讨论使用.NET Framework的好处,并且将包括一些功能强大的、Visual Basic开发人员可以与该框架一起使用的特性,包括多线程和线程池(thread pooling)、Windows服务和文件系统监控等。
为什么使用框架
单词框架(framework)有几种含意。在这种情况中,它指的是创建和运行应用程序的基础。拥有这样的基础使得创建应用程序变得更容易,而同时使用了一个一致的、简化的程序设计模型。
作为一个Visual Basic 6.0开发人员,你对于这种程序设计语言感觉很满意,它使得创建各种应用程序变得很容易。Visual Basic语言本身提供了固有的数据类型,如 Integer, Long和String,以及一些最常用的函数,如字符串处理和数据类型转换等。当你的应用程序变得更复杂时,你可以使用Win32 API来完成标准的Visual Basic函数所不能实现的功能-如获取任意的注册键和数值。在许多情况中,你还可以使用COM(Component Object Model,组件对象模型)组件库来扩展应用程序的功能;最明显的例子是ADO(ActiveX Data Objects)库,你的应用程序可以使用它来进行数据访问。
虽然Visual Basic足够灵活,可以提供这些不同的可扩展性机制,但这种灵活性仍然需要你学习几种复杂的API体系结构。你需要了解Win32如何工作,以及如何在Visual Basic中调用它们,这可能会是一个既费时又容易出错的任务。你还需要了解如何在Visual Basic中使用各种COM组件,每个COM组件都有一个不同的对象模型。
最后,当你使用Win32 API、ADO,也可能使用许多其他COM组件,创建自己的Visual Basic应用程序时,你需要管理这些应用程序的部署以及它们的相关性。一个典型的Visual Basic应用程序的相关性列表所包括的远远多于Visual Basic运行时(runtime);它必须包括应用程序使用的所有对象库,如ADO 2.6。
公共框架背后的想法是解决这些问题,并使得用户创建健壮的应用程序变得更容易,而无需学习多种不同的API体系结构,并且无需部署和处理多种对象库的版本问题。
什么是.NET Framework
术语.NET Framework指的是构成Microsoft .NET平台开发基础的一组技术。这一组中的关键技术是运行时(runtime)和类库,如图1所示。
图 1. .NET Framework由.NET运行时和类库组成
运行时负责管理代码,在执行时向它提供服务,这与Visual Basic 6.0运行时的作用类似。.NET程序设计语言-包括Visual Basic .NET、Microsoft Visual C#、C++管理的扩展,以及多种来自不同开发商的程序设计语言-通过一组公共的统一类来利用各种服务和特性。
.NET统一类提供了创建应用程序的基础,而不管你使用何种语言。无论你只是简单地连接一个字符串,还是创建一个Windows服务或多层的基于网络的应用程序,你都要用到这些统一类。
统一类为访问平台的功能性提供了一种一致的方法。一旦你学会了使用类库,你就会发现所有任务都遵循同一个一致的体系结构。要编写自己的应用程序,你无需学习和掌握不同的API体系结构。
由于.NET Framework,部署Visual Basic .NET应用程序变得更容易了。与Visual Basic 6.0应用程序不同,你无需配置各种相关性,如单独的数据访问库、XML语法分析器和网络API,因为所有这些功能都是.NET Framework的组成部分。
通过在统一的、集成的框架上创建自己的应用程序,你可以实现学习这种框架所花费时间的最大回报,并且你将拥有更多容易部署和使用的健壮的应用程序。
.NET Framework与Visual Basic .NET
Visual Basic 6.0运行时在简化许多公共的程序设计任务方面非常重要。但是简化这一层意味着,在拥有Visual Basic可以使用的打包程序之前,你不能使用新的操作系统特性,如DirectX。作为一个Visual Basic开发人员,你从.NET Framework获得的最重要的益处是,可以使用一致的程序设计模型既直接又容易地访问.NET平台。这意味着,你可以使用Visual Basic .NET创建很难或不可能使用Visual Basic 6.0创建的应用程序。作为一个Visual Basic 6.0开发人员,现在你将对能够使用与其他平台语言相同的特性和功能而赞赏不已。例如,为了创建Windows服务,你无须再用Microsoft Visual C++来编写它,你也无须求助于黑客或组装机。你可以优雅、干净、容易地使用Visual Basic .NET完成这项工作。为了给你一些使用.NET Framwork的例子,我们将讨论在你的应用程序中可能需要执行的4个常见任务:跟踪与事件记录、多线程、文件系统监控和创建Windows服务。
跟踪与事件记录
当创建一个健壮的应用程序的时候,你必须密切注意诊断和故障排除机制。代表性地,这包括编写处理打开输出目标(事件记录或文件)的跟踪组件,编写跟踪消息和关闭输出目标。然后通过自己的代码调用关于这个组件的方法,将文本传递给记录。你将所有的时间和精力花在了创建跟踪和记录子系统上,这最终并不会对解决商务问题有所贡献,但这是创建应用程序所必需的。
.NET Framework包括类和其他数据类型,通过向你提供记录基础设施,使得记录跟踪消息变得很容易。图2给出了用于跟踪的.NET Framework类。
图2. 在使用.NET Framewok中用到的跟踪工具
类是System.Diagnostics名称空间的一部分。Trace类提供了几个共享的方法。例如,Write方法允许你记录特定消息,而Assert方法允许你在特定的条件为假的情况下记录一条消息。Trace类将消息输出到Listeners集合中的对象。这个集合中的每个对象都属于继承自TraceListener的一个类。EventLogTraceListener 将消息写入事件记录,而TextWriterTraceListener则是将消息写入到一个文本文件中,默认情况下,DefaultTraceListener的一个实例被添加到Trace类的Listeners集合中。
除了标准的监听程序以外,你可以实施自己跟踪监听程序。例如,你希望接收来自在防火墙后面的远程机器上运行的应用程序的跟踪输出。你可以编写一个跟踪监听程序,通过HTTP全球向你的服务器发送跟踪消息。这将会影响你的应用程序的性能,但只会在启用跟踪时才会对性能有所影响。
代表性地,你需要有能力在编译的二进制文件中包括或去除跟踪代码。为了在Visual Basic 6.0中做到这一点,你需要使用编译常量,并在#If语句中包含所有的跟踪代码,这使得代码很难理解和维护。利用.NET Framework,你只需在项目属性(Project Properties)对话框中将TRACE编译常量设为on或off状态;你无需在#If语句中包括跟踪代码。
另一个普遍期望的跟踪特性是跟踪水平设置,这包括不同的跟踪设置-例如, Severe(严重)、Error(错误)、Warning(警告)和Information(信息)-这些设置对记录哪些信息进行控制。你可以使用跟踪组件启动时所读取的注册表数值对此进行控制。对于.NET Framework,这是完全内置的功能。你可以设置一个注册表数值来控制你当前的应用程序的记录水平,比如,只有在跟踪水平被设置为Severe(严重)的情况下,才使用Trace.WriteIf和Trace.WriteLineIf来记录消息。
集成的跟踪和记录特性极大地增强了生产力,因为你只需使用内置的特性,将精力集中在编写真正的应用程序代码上。
多线程应用程序
.NET Framework的一个很重要的特性是,可以在不使用第三方工具或不支持的Visual Basic技巧情况下,使用Visual Basic创建多线程应用程序。.NET Framework的多线程支持是由System.Threading名称空间中的类和接口提供的,因此所有的.NET语言都能够以相同的方式创建和处理线程。System.Threading.Thread是一个核心类,提供了对创建和控制线程的支持。要创建一个线程,你可以创建一个新的System.Threading.Thread对象,将构造函数传递给ThreadStart代理。这个代理提供了这个线程开始执行的方法。当你准备启动这个新的线程时,可以调用Thread.Start() (请参阅清单1)。
当你开始创建多线程应用程序时,你很快就会认识到需要控制对共享资源的访问,如共享的类变量。.NET Framework还包括几个类和数据类型,你可以使用它们对两个线程执行的动作进行同步。
在最简单的情况中,你由一个需要从不同的线程中进行更新的共享变量。要这样做,你可以使用System.Threading.Interlocked类。例如,你可以通过编写Interlocked.Increment(num)或Interlocked.Decrement(num)分别使名为num的共享变量递增或递减。你还可以使用Interlocked将变量设为某一特定值,或检查两个变量是否相等。除了这种简单情况以外,你可以使用.NET Framework类来执行更复杂的线程同步,如事件和互斥体的同步-所有都来自于.NET Framework内部,而无须使用Win32 API。.
Imports System.IO
'The namespace System.Threading
'contains the Thread class
Imports System.Threading
Module Module1
Private count As Long
Sub Main()
'Create the ThreadStart delegate
Dim tStart As ThreadStart = New _
ThreadStart(AddressOf StartCounting)
'Create the thread
Dim t1 As Thread = New Thread(tStart)
Console.WriteLine("Enter q to quit")
t1.Start() 'start the thread
While (Console.Read() <> asc("q"))
'repeat the loop until the user enters q
End While
t1.Stop() 'tell thread to stop processing
t1.Join() 'wait until the thread finishes
End Sub
Sub StartCounting()
Do
'use Interlocked.Increment in case
'another thread is accessing the same variable
Interlocked.Increment(count)
Console.WriteLine( _
"After incrementing count is : {0}", count)
Thread.Sleep(200)
Loop
End Sub
End Module
清单1. 使用Visual Basic .NET创建线程
你创建了一个新线程,将它传递给一个ThreadStart代理。然后调用Thread.Start()启动这个线程。你可以通过调用Thread.Stop()来中止这个线程,然后调用Thread.Join()等待它完成关闭操作。一个线程可以使用System.Threading.Interlocked来使变量递增或递减。
此外,.NET Framework提供了一个方便的机制来对工作排队,并将起分配给线程池中的某个线程。在处理多个并发工作项目或工作请求的服务器应用程序中,这非常有用。例如,对于等待输入文件,然后将它们导入到数据库中去的应用程序,可能会对每个输入文件进行排队,以在线程池中的某个单独的线程上进行处理。System.Threading.ThreadPool类允许你使用共享的QueueUserWorkItem方法对工作进行排队。以前要这样做,你必须得创建和管理自己的线程池。你又需要在基础设施工作而不是在解决商务问题上花大量的时间和精力。
文件系统监控
我曾经遇到过一些应用程序,需要等待和处理某个特定目录中的文件-例如,将数据从文件导入到数据库中去的应用程序。数据文件可以从某个大型机上下载,或者被转移到某个输入目录中,该应用程序将它们导入到数据库中。你不用经常地轮询该目录检查是否有新文件,可以等待生成新文件的通知。你可以在Visual Basic 6.0中使用Win32 API来做到这一点,而在Visual Basic .NET中你可以使用.NET Framework类来做这项工作。但是在.NET中实施文件监控与在.NET中完成其他工作的方法更加一致,因此学习曲线是最小的。
你可以使用System.IO.FileSystemWatcher .NET类对文件系统进行监视。它提供了一些属性,允许你设置监控的路径,指定是对文件还是子目录层次的变化感兴趣。System.IO.FileSystemWatcher还允许你指定需要监控的文件名和文件类型(例如,*.xml是指监控所有XML文件的变化)。最后,你可以指定感兴趣的变化类型-例如,只对新建文件,文件属性的变化或文件大小的变化(请参阅清单2)感兴趣。
在你设置了监控内容后,你需要钩住用于感兴趣的各种事件的事件处理程序。FileSystemWatcher事件有Changed、Created、Deleted、Error和Renamed。要处理某个事件,首先你需要编写一个与FileSystemEventHandler代理相同声明的事件处理程序,然后将这个处理程序添加到FileSystemWatcher类中。这个基于代理的体系结构允许你为同一个事件添加多个处理程序,或者对于多个事件使用同一个处理程序-而你不能使用Visual Basic 6.0做到这一点。
'System.IO contains the
'file monitoring classes and types
Imports System.IO
Module Module1
Sub Main()
'FileSystemWatcher does the real work
Dim fw As New FileSystemWatcher()
'WaitForChangedResult is what you
'get back when a change occurs
Dim result As WaitForChangedResult
'set the path to monitor
fw.Path = "C:\WINNT\"
'tell it whether to watch files or directories
fw.Target = WatcherTarget.File
'tell it whether to include subdirs
fw.IncludeSubdirectories = False
'hook up handlers
AddHandler fw.Created, _
New FileSystemEventHandler(AddressOf OnFileNotify)
'enable the watcher
fw.Enabled = True
Do
Console.WriteLine("Beginning to monitor")
'this is where we actually wait
'waiting blocks execution for the specified timeout
result = fw.WaitForChanged(WatcherChangeTypes.All, 60000)
Console.WriteLine("Hit Enter to continue q to quit")
Loop While (Console.ReadLine <> "q")
End Sub
'This is the delegate that gets
'called when a file is created
Public Sub OnFileNotify(ByVal source As Object, _
ByVal e As FileSystemEventArgs)
Console.WriteLine( _
"Notification received for file {0}, change type is {1}", _
e.FullPath, e.ChangeType)
End Sub
End Module
清单2. 使用FileSystemWatcher监控某个文件夹是否有新文件。
你可以创建一个FileSystemWatcher,然后设置它的属性。你可以使用AddHandler将FileSystemEventHandler代理与各种FileSystemWatcher事件关联起来,如Created。然后你就可以启用FileSystemWatcher,然后调用WaitForChanged。该调用将在变化发生或达到指定的超时时返回。
创建Windows服务
当你要创建一个Windows服务时,你必须使用Visual C++或在Visual Basic中使用srvany.exe或第三方工具来创建该服务。任何一种方法,你都没有在Visual Basic中编写自己的服务,你只是正在Visual Basic运行时的外部添加更多从属组件。
如果你使用C++或C语言,在不使用活动模版库(Active Template Library)的情况下从头编写一个Windows服务,你将不得不编写一小段代码来协调你的服务与服务控制器(Service Control Manager,SCM)之间的往来通信,SCM用来处理服务的启动、暂停、继续和停止。.NET Framework通过提供System.ServiceProcess.ServiceBase类,使得实现一个服务变得很容易。要编写一个服务,你可以从这个类继承,重载它的某些方法,设置它的属性,然后就大功告成了!
你可能要重载的一些方法包括:OnStart、OnStop、OnPause和OnContinue。通常你需要载启动工作线程(worker thread)的位置重载OnStart,在需要取消这个工作线程的位置重载OnStop。在你创建了自己的服务后,你就可以使用SCM安装和注册这个服务。这是另一个领域,.NET Framework中的基类提供了大部分所需的工作。你可以创建一个继承自System.Configuration.Install.Installer的类,从System.ServiceProcess.ServiceInstaller中例示对象,然后设置它的属性,如服务启动模式和服务名称。这使得.NET安装实用工具installUtil.exe能够安装(和删除)你的服务,而你无需编写额外的代码。
当你开始使用Visual Studio .NET时,你将会发现Visual Studio .NET使得使用.NET Framework变得更容易。Visual Studio .NET允许你创建Windows服务(拥有安装程序(installer)),监控文件系统的变化,写入事件记录 - 所有都是使用设计器和组件而不是编写代码来完成。例如,要将一个安装程序添加到自己的服务项目中,你只需选中服务设计器避免,然后单击属性(Properties)窗口(见图3)底部的添加安装程序(Add Installer)。这将添加一个新模块ProjectInstaller.vb,该模块包括安装该服务所需的全部代码。你可以使用设计器(见图4),对安装选项,如启动模式进行自定义
图3. 使用Visual Studio .NET给你的服务项目添加安装程序
图4. 使用设计器,对安装选项,如StartType进行自定义
结论
.NET Framework使得你能够利用Visual Basic .NET,很容易地开发健壮地应用程序。它使得你可以将重点放在学习一种相容的程序设计模型上,并且使得你可以直接访问底层的.NET平台。利用Visual Basic .NET和.NET Framework,你可以使自己的应用程序达到前所未有的水平。