Net Remoting(应用程序域) - Part1.pdf
《Net Remoting(应用程序域) - Part1.pdf》由会员分享,可在线阅读,更多相关《Net Remoting(应用程序域) - Part1.pdf(8页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、.Net Remoting(应用程序域)-Part.1.Net Remoting(应用程序域)-Part.1 引言 引言 在互联网日渐普及,网络传输速度不断提高的情况下,分布式的应用程序是软件开发的一个重要方向。在.Net 中,我们可以通过 Web Service 或者 Remoting 技术构建分布式应用程序(除此还有新一代的 WCF,Windows Communication Foundation)。本文将简单介绍 Remoting 的一些基本概念,包括 应用程序域、Remoting 构架、传值封送(Marshal by value)、传引用封送(Marshal by reference)
2、、远程方法回调(Callback)、分别在 Windows Service 和 IIS 中寄宿宿主程序,最后我们介绍一下远程对象的生存期管理。理解 Remoting 理解 Remoting 1.应用程序域基本概念 1.应用程序域基本概念.Net 中的很多概念都是环环相扣的,如果一个知识点没有掌握(套用一下数据结构中“前驱节点”这个术语,那么这里就是“前驱知识点”),就想要一下子理解自己当前所直接面临问题,常常会遇到一些障碍而无法深入下去,或者是理解的浅显而不透彻(知道可以这样做,不知道为什么会是这样。如果只是应急,需要快速应用,这样也未尝不可)。为了更好地理解 Remoting,我们也最好先了
3、解一下 Remoting 的前驱知识点-应用程序域。我们知道所有的.Net 应用程序都运行在托管环境(managed environment)中,但操作系统只提供进程(Process)供程序运行,而进程只是提供了基本的内存管理,它不了解什么是托管代码。所以托管代码,也可以说是我们创建的.Net 程序,是无法直接运行在操作系统进程中的。为了使托管代码能够运行在非托管的进程之上,就需要有一个中介者,这个中介者可以运行于非托管的进程之上,同时向托管代码提供运行的环境。这个中介者就是 应用程序域应用程序域(Application Domain,简写为 App Domain)。所以我们的.Net 程序,
4、不管是 Windows 窗体、Web 窗体、控制台应用程序,又或者是一个程序集,总是运行在一个 App Domain 中。如果只有一个类库程序集(.dll 文件),是无法启动一个进程的(它并非可执行文件)。所以,创建进程需要加载一个可执行程序集(Windows 窗体、控制台应用程序等.exe 文件)。当可执行程序集加载完毕,.Net 会在当前进程中创建一个新的应用程序域,称为 默认应用程序域默认应用程序域。一个进程中只会创建一个默认应用程序域,这个应用程序域的名称与程序集名称相同。默认应用程序域不能被卸载,并且与其所在的进程同生共灭。那么应用程序域是如何提供托管环境的呢?简单来说,应用程序域只
5、是允许它所加载的程序集访问由.Net Runtime 所提供的服务。这些服务包括托管堆(Managed Heap),垃圾回收器(Garbage collector),JIT 编译器等.Net 底层机制,这些服务本身(它们构成了.Net Runtime)是由非托管 C+实现的。在一个进程中可以包含多个应用程序域,一个应用程序域中可以包含多个程序集。比如说,我们的 Asp.Net 应用程序都运行在aspnet_wp.exe(IIS5.0)或者 w3wp.exe(IIS6.0)进程中,而 IIS 下通常会创建多个站点,那么是为每个站点都创建一个独立的进程么?不是的,而是为每个站点创建其专属的应用程序
6、域,而这些应用程序域运行在同一个进程(w3wp.exe 或 aspnet_wp.exe)中。这样做起码有两个好处:1、在一个进程中创建多个 App Domain 要比创建和运行多个进程需要少得多系统开销;2、实现了错误隔离,一个站点如果出现了致命错误导致崩溃,只会影响其所在的应用程序域,而不会影响到其他站点所在的应用程序域。2.应用程序域的基本操作 2.应用程序域的基本操作 在.Net 中,将应用程序域封装为了 AppDomain 类,这个类提供了应用程序域的各种操作,包含 加载程序集、创建对象、创建应用程序域 等。通常的编程情况下下,我们几乎从不需要对 AppDomain 进行操作,这里我们
7、仅看几个本文会用到的、有助于理解和调试 Remoting 的常见操作:1.获取当前运行的代码所在的应用程序域,可以使用 AppDomain 类的静态属性 CurrentDoamin,获取当前代码所在的应用程序域;或者使用Thread 类的静态方法 GetDomain(),得到当前线程所在的应用程序域:AppDomain currentDomain=AppDomain.CurrentDomain;AppDomain currentDomain=Thread.GetDomain();NOTE:NOTE:一个线程可以访问进程中所包含的所有应用程序域,因为虽然应用程序域是彼此隔离的,但是它们共享一个托
8、管堆(Managed Heap)。2.获取应用程序域的名称,使用 AppDomain 的实例只读属性,FriendlyName:string name=AppDomain.CurrentDomain.FriendlyName;3.从当前应用程序域中创建新应用程序域,可以使用 CreateDomain()静态方法,并传入一个字符串,作为新应用程序域的名称(亦即设置FriendlyName 属性):AppDomain newDomain=AppDomain.CreateDomain(New Domain);4.在应用程序域中创建对象,可以使用 AppDomain 的实例方法 CreateInsta
9、nceAndUnWrap()或者 CreateInstance()方法。方法包含两个参数,第一个参数为类型所在的程序集,第二个参数为类型全称(这两个方法后面会详述):DemoClass obj=(DemoClass)AppDomain.CurrentDomain.CreateInstanceAndUnWrap(ClassLib,ClassLib.DemoClass);ObjectHandle objHandle=AppDomain.CurrentDomain.CreateInstance(ClassLib,ClassLib.DemoClass);DemoClass obj=(DemoClass
10、)objHandle.UnWrap();5.判断是否为默认应用程序域:newDomain.IsDefaultAppDomain()3.在默认应用程序域中创建对象 3.在默认应用程序域中创建对象 开始之前我们先澄清一个概念,请看下面一段代码:class Program static void Main(string args)MyClass obj=new MyClass();obj.DoSomething();此时我们说 obj 是服务对象服务对象,Program 是客户程序客户程序,而不管 obj 位于什么位置。接下来我们来看一个简单的范例,我们使用上面提到基于 AppDomain 的操作,
11、在当前的默认应用程序域中创建一个对象。我们先创建一个类库项目 ClassLib,然后在其中创建一个类 DemoClass,这个类的实例即为我们将要创建的对象:namespace ClassLib public class DemoClass private int count=0;public DemoClass()Console.WriteLine(n=DomoClass Constructor=);public void ShowCount(string name)count+;Console.WriteLine(0,the count is 1.,name,count);/打印对象所在的
12、应用程序域 public void ShowAppDomain()AppDomain currentDomain=AppDomain.CurrentDomain;Console.WriteLine(currentDomain.FriendlyName);接下来,我们再创建一个控制台应用程序,将项目命名为 ConsoleApp,引用上面创建的类库项目 ClassLib,然后添加如下代码:class Program static void Main(string args)Test1();/在当前 AppDomain 中创建一个对象 static void Test1()AppDomain cur
13、rentDomain=AppDomain.CurrentDomain;/获取当前应用程序域 Console.WriteLine(currentDomain.FriendlyName);/打印名称 DemoClass obj;/obj=new DemoClass()/常规的创建对象的方式 /在默认应用程序域中创建对象 obj=(DemoClass)currentDomain.CreateInstanceAndUnwrap(obj=(DemoClass)currentDomain.CreateInstanceAndUnwrap(ClassLib,ClassLib.DemoClassClassLib
14、,ClassLib.DemoClass););obj.ShowAppDomain();obj.ShowCount(Jimmy);obj.ShowCount(JImmy);运行这段代码,得到的运行结果是:ConsoleApp.exe =DomoClass Constructor=ConsoleApp.exe Jimmy,the count is 1.Jimmy,the count is 2.现在运转良好,一切都没有什么问题。你可能想问,使用这种方式创建对象有什么意义呢?通过 CreateInstanceAndUnwrap()创建对象和使用 new DemoClass()创建对象有什么不同呢?回答
15、这个问题之前,我们再来看下面另一种情况:4.在新建应用程序域中创建对象 4.在新建应用程序域中创建对象 我们看看如何 创建一个新的 AppDomain,然后在这个新的 AppDomain 中创建 DemoClass 对象。你可能会想,这还不简单,把上面的例子稍微改改不就 OK 了:/在新 AppDomain 中创建一个对象 static void Test2()AppDomain currentDomain=AppDomain.CurrentDomain;Console.WriteLine(currentDomain.FriendlyName);/创建一个新的应用程序域-NewDomain A
16、ppDomainAppDomain newDomain=AppDomain.CreateDomain(newDomain=AppDomain.CreateDomain(NewDomainNewDomain););DemoClass obj;/在新的应用程序域中创建对象 obj=(DemoClass)newDomain.CreateInstanceAndUnwrap(obj=(DemoClass)newDomain.CreateInstanceAndUnwrap(ClassLib,ClassLib.DemoClassClassLib,ClassLib.DemoClass););obj.ShowA
17、ppDomain();obj.ShowCount(Jimmy);obj.ShowCount(Jimmy);然后我们在 Main()方法中运行 Test2(),结果却是得到了一个异常:类型“ClassLib.DemoClass”未标记为可序列化。类型“ClassLib.DemoClass”未标记为可序列化。在把 ClassLib.DemoClass标记为可序列化(Serializable)之前,我们想一想为什么会发生这个异常。我们看看声明 obj 类型的这行代码:DemoClass obj,这说明了 objDemoClass obj,这说明了 obj是在当前的默认应用程序域,也就是 AppCon
18、sole.exe 中声明的;然后我们在往下看,类型的实例(对象本身)却是通过 是在当前的默认应用程序域,也就是 AppConsole.exe 中声明的;然后我们在往下看,类型的实例(对象本身)却是通过 newDomain.CreateInstanceAndUnwrap()在新创建的应用程序域-NewDomain 中创建的。newDomain.CreateInstanceAndUnwrap()在新创建的应用程序域-NewDomain 中创建的。这样就出现了一种尴尬的情况:对象的引用(类型声明)对象的引用(类型声明)位于当前应用程序域(AppConsole.exe)中,而对象本身(类型实例)位于新
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Net Remoting应用程序域 Part1 Remoting 应用程序
限制150内