.Net组件程序设计之远程调用(一)app
咱们知道咱们写的C#代码是在操做系统逻辑体系结构中最上层的,然而操做系统自己是不会认识C#代码的,它只认识机器代码。那咱们写的程序通过编译后是编译成IL的,是怎么运行的呢?实际是在一个托管的环境下运行的,是.NET提供的支持,操做系统是不会识别IL的,这中间就须要一个桥梁:应用程序域。操做系统中的进程是资源单位,应用程序域的执行使用固然也要占用空间使用资源了,因此是物理进程承载着应用程序域的,并且这种承载关系并非一对一的。框架
图:应用程序域分布式
使用应用程序域这样的机制,是有许多好处的。好比说客户端在调用其余组件的时候能够建立一个应用程序域,而后在新建的应用程序域中加载组件进行操做等等,即便被调用的组件发生一些致命的错误也不会致使客户端崩溃,有效的进行了错误隔离。还有一些数据交互传输上的性能差别等等,这里不作详细的阐述了。函数
.NET Remoting是一种基于.NET平台的分布式系统框架,所了解的就是用于数据传输。 说几句它被使用的局限性很大,受到了平台的限制,固然若是仅仅是这样是不可否定它的强大和几乎无限扩展的框架体系,不管在哪个环节你均可以本身来实现一些自定义的功能。会在下个篇幅稍做讲解。性能
在.NET中用AppDoMain类来表示应用程序域,也提供了获取当前应用程序域的方法,能够直接使用AppDoMain类的静态属性CurrentDomain来获取到当前程序所在的应用程序域,这是一种方法,还额外提供一种了,就是Thread类的GetDomain()静态方法也是能够获取到的。优化
1 namespace RemoteServer 2 public class class1 3 { 4 private string appDoMainName; 5 6 public class1() 7 { 8 appDoMainName = AppDomain.CurrentDomain.FriendlyName; 9 } 10 11 public void Writer() 12 { 13 Console.WriteLine(appDoMainName); 14 } 15 }
class1中构造函数是获取当前应用程序域的名称,而且是在Writer()方法中输出到控制台界面中,spa
using RemoteServer; namespace RemoteCase { AppDomain appDoMain = AppDomain.CurrentDomain; class1 cls1 = (class1)appDoMain.CreateInstanceFromAndUnwrap("RemoteServer.dll", "RemoteServer.class1"); cls1.Writer(); }
图3-1操作系统
这里使用了AppDomain中的静态方法CreateInstanceFromAndUnwrap(),由于当前项目已经引用了RemoteServer程序集,因此第一个参数只是一个显示的名称,并非全路径,在调用方法的时候,应用程序域会加载程序集,用于获取到元数据。设计
1 namespace RemoteServer 2 public class class1:MarshalByRefObject 3 { 4 private string appDoMainName; 5 6 public class1() 7 { 8 appDoMainName = AppDomain.CurrentDomain.FriendlyName; 9 } 10 11 public void Writer() 12 { 13 Console.WriteLine(appDoMainName); 14 } 15 }
1 using RemoteServer; 2 3 AppDomain appDoMain = AppDomain.CurrentDomain; 4 AppDomain newDoMain = AppDomain.CreateDomain("NewDoMain"); 5 class1 cls1 = (class1)newDoMain.CreateInstanceFromAndUnwrap("RemoteServer.dll", "RemoteServer.class1"); 6 cls1.Writer();
图3-2代理
图3-3-1
这段代码是3.2中的代码,cls1并非class1类型自己,而是代理,访问远程对象都是经过代理完成的,这么屌炸天的.NET固然提供优化,将建立远程对象和在客户端创建代理分离,这样能够在你建立了一个远程对象以后再创建代理。 AppDomain类提供了一套CreateInstance()方法来建立对象,可是都以ObjectHandle的形式返回一个远程对象句柄(意思就是远程对象的惟一标示,这个句柄能表明远程对象)
ObjectHandle对象实现了System.Runtime.Remoting命名空间下的IObjectHandle接口:
1 namespace RemoteServer 2 public class class1:MarshalByRefObject 3 { 4 private string appDoMainName; 5 6 public class1() 7 { 8 appDoMainName = AppDomain.CurrentDomain.FriendlyName; 9 } 10 11 public void Writer() 12 { 13 Console.WriteLine(appDoMainName); 14 } 15 16 }
1 using RemoteServer; 2 3 AppDomain appDoMain = AppDomain.CurrentDomain; 4 AppDomain newDoMain = AppDomain.CreateDomain("NewDoMain"); 5 IObjectHandle objecthandle; 6 objecthandle = newDoMain.CreateInstance("RemoteServer", "RemoteServer.class1"); 7 8 RemoteServer.class1 cls1 = objecthandle.Unwrap() as RemoteServer.class1; 9 10 cls1.Writer();
通常状况下是不须要手动拆包对象句柄的,这样作的好处只是能够推迟加载RemoteServer程序集,只有在 objecthandle.Unwrap()的时候才会创建代理,而创建代理必须须要对象元数据。
通常状况下,被引用对象和客户端同在一个应用程序域,这样的状况下不涉及到代理,也不会用到什么远程调用,
而是直接引用对象,若是当你须要调用另外一个应用程序域里的对象时会是什么样的?默认状况下.NET是不容许对象跨应用程序域访问的,
不论是不是在同一个进程内。可是呢若是要访问,也不是不行的,.NET提供了两种数据传递方式,一种是值传递,一种是引用传递
当应用程序域A调用应用程序域B中的对象时,应用程序域B中的对象会被拷贝一个克隆到应用程序域A,这时候两个对象是不存在任何关系的,这种状况叫作按值封送 通常状况下都是使类型使用Serializable特性,支持序列化,经过序列化来达到按值封送的目的,在被调用方序列化,到调用方反序列化。
这种状况就是当应用程序域A调用应用程序域B的对象时,应用程序域A得到的是应用程序域B中对象的引用,
这个引用挂在哪里呢?挂在应用程序域A的对象代理上,这种状况就叫引用封送 引用封送就比按值封送有意思多了,想要知足能够引用封送的要求,则对象必须继承自MarshalByRefObject,MarshalByRefObject类型给出的解释就是 容许在支持远程处理的应用程序中跨应用程序域边界访问对象,这样做为它的子类一样的也享受这样的优待。在引用封送中会有两种远程对象激活模式,这个内容在下一个篇幅中会有详细的示例代码。
做者:金源
出处:http://www.cnblogs.com/jin-yuan/
本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面