CLR via C# 读书笔记 6-2 不同AppDomain之间的通信 z
跨AppDomain通信有两种方式
1.Marshal By reference : 传递引用
2.Marshal By Value : 把需要传递的对象 通过序列化反序列化的方式传递过去(值拷贝)
只有标记为 可序列化 Serializable 的类才能通过 Marshal By Value的方式通信
以下代码描述了几种跨域通信的情况
1.AppDomain是CLR的内部行为,windows完全不清楚有AppDomain的存在
2.在新的域中加载Assembly和Type最好用完整限定名(如果直接加载Type, CLR会自动加载Type所在的和所用到的Assembly)
3.默认情况下新建的应用程序域使用和当前域一样的权限设置,如果你需要手动指定权限,那么构造一个PermissionSet参数传给CreateDomain
4.同样的,如果想给应用程序设置不同的配置,构造一个AppDomainSetup传给他(可以设置配置文件,程序路径,影像拷贝什么的..)
5.跨域访问的时候不会发生线程的上下文切换
6.CreateInstanceAndUnwrap 默认调用对象的无参构造函数,当然,有些重载允许你调用有参构造函数
7.只有继承了System.MarshalByRefObject的对象才能以引用方式传递 (这是一个基类....c#又不允许多继承....还是挺麻烦的)
8.只有标记了了Serializable 的对象才能以值方式传递(内部的序列化反序列化) ,这里有比较严重的性能损耗
代码 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Runtime.Remoting; namespace TestConsole
{
publicclass Program
{
staticvoid Main(string[] args)
{ // 获取一个指向应用程序域的引用
AppDomain adCallingThreadDomain = Thread.GetDomain();
// 每一个应用程序域都会被分配一个名字帮助调试 ,以下代码获取引用程序域的名字
String callingDomainName = adCallingThreadDomain.FriendlyName;
// 获取应用程序域的完整名
String exeAssembly = Assembly.GetEntryAssembly().FullName;
AppDomain ad2 =null; // ************************************************************************************************************
// 使用Marshal-by-Reference的方式跨域通信
Console.WriteLine("{0}Demo #1", Environment.NewLine);
// 建立一个域,安全和配置均使用当前域的设置
ad2 = AppDomain.CreateDomain("AD #2", null, null);
MarshalByRefType mbrt =null;
// 加载Assembly到新的域,new一个对象并且返回到当前域 (实际上返回的是一个引用代理)
mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, "TestConsole.MarshalByRefType");
Console.WriteLine("Type={0}", mbrt.GetType()); // CLR 对GetType做了一些手脚,返回的是被代理数据的真实类型
// 以下代码证明我们获取的是一个代理对象
Console.WriteLine("Is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
// 我们调用了代理类的SomeMethod() , 代理类跨域访问真正的对象
mbrt.SomeMethod();
// 卸载新建的那个应用程序域
AppDomain.Unload(ad2);
// mbrt refers to a valid proxy object; the proxy object refers to an invalid AppDomain
try
{
// 再次调用代理类的SomeMethod() , 由于域已经被卸载 抛出一个异常
mbrt.SomeMethod();
Console.WriteLine("Successful call.");
}
catch (AppDomainUnloadedException)
{
Console.WriteLine("Failed call.");
} // ************************************************************************************************************
// 使用Marshal-by-Value 的方式跨域通信
Console.WriteLine("{0}Demo #2", Environment.NewLine);
// 新建域
ad2 = AppDomain.CreateDomain("AD #2", null, null);
// 加载程序集并创建代理类
mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, "TestConsole.MarshalByRefType");
// 该方法返回了一个值的拷贝 marshaled by value (not be reference).
MarshalByValType mbvt = mbrt.MethodWithReturn();
// 证明返回值不是一个代理类
Console.WriteLine("Is proxy={0}", RemotingServices.IsTransparentProxy(mbvt));
// 查看返回值是谁创建的
Console.WriteLine("Returned object created "+ mbvt.ToString());
// 卸载应用程序域
AppDomain.Unload(ad2);
// 由于是值传递,那么卸载域对函数没有影响 // marshaled by value
try
{
//不会有异常抛出
Console.WriteLine("Returned object created "+ mbvt.ToString());
Console.WriteLine("Successful call.");
}
catch (AppDomainUnloadedException)
{
Console.WriteLine("Failed call.");
}
// ************************************************************************************************************
// non-marshalable type 跨域通信
Console.WriteLine("{0}Demo #3", Environment.NewLine);
ad2 = AppDomain.CreateDomain("AD #2", null, null);
mbrt = (MarshalByRefType)ad2.CreateInstanceAndUnwrap(exeAssembly, "TestConsole.MarshalByRefType");
// 没有标记为 Serializable 的类型对象 不能通过marshaled by value 跨域通信
NonMarshalableType nmt = mbrt.MethodArgAndReturn(callingDomainName); }
} //即使没有标记为Serializable 也可以通过 marshaled-by-reference 的方式跨域通信
publicsealedclass MarshalByRefType : MarshalByRefObject
{
public MarshalByRefType()
{
Console.WriteLine("{0} ctor running in {1}",
this.GetType().ToString(), Thread.GetDomain().FriendlyName);
}
publicvoid SomeMethod()
{
Console.WriteLine("Executing in "+ Thread.GetDomain().FriendlyName);
}
public MarshalByValType MethodWithReturn()
{
Console.WriteLine("Executing in "+ Thread.GetDomain().FriendlyName);
MarshalByValType t =new MarshalByValType();
return t;
}
public NonMarshalableType MethodArgAndReturn(String callingDomainName)
{
// NOTE: callingDomainName is [Serializable]
Console.WriteLine("Calling from ‘{0}’ to ‘{1}’.",
callingDomainName, Thread.GetDomain().FriendlyName);
NonMarshalableType t =new NonMarshalableType();
return t;
}
} //只有标记为 Serializable 的类型 才能用marshaled by value 的方式跨域通信
[Serializable]
publicsealedclass MarshalByValType : Object
{
private DateTime m_creationTime = DateTime.Now; // NOTE: DateTime is [Serializable]
public MarshalByValType()
{
Console.WriteLine("{0} ctor running in {1}, Created on {2:D}",
this.GetType().ToString(),
Thread.GetDomain().FriendlyName,
m_creationTime);
}
publicoverride String ToString()
{
return m_creationTime.ToLongDateString();
}
} // 没有标记为 Serializable 的类型 不能用marshaled by value 的方式跨域通信
// [Serializable]
publicsealedclass NonMarshalableType : Object
{
public NonMarshalableType()
{
Console.WriteLine("Executing in "+ Thread.GetDomain().FriendlyName);
}
}
}
CLR via C# 读书笔记 6-2 不同AppDomain之间的通信 z的更多相关文章
- 10月9日Android学习笔记:活动与服务之间的通信
最近在照着<第一行代码>这本书来学安卓,顺便记下笔记.主要的内容是Android中服务的第二种启动方式,通过活动绑定服务来启动服务,实现活动与服务之间的通信. 一. 首先创建一个服务类 p ...
- CLR via C# 读书笔记---常量、字段、方法和参数
常量 常量是值从不变化的符号.定义常量符号时,它的值必须能在编译时确定.确定后,编译器将唱两只保存在程序集元数据中.使用const关键字声明常量.由于常量值从不变化,所以常量总是被视为类型定义的一部分 ...
- Clr Via C#读书笔记---I/O限制的异步操作
widows如何执行I/O操作 构造调用一个FileStream对象打开一个磁盘文件-----FileStream.Read方法从文件中读取数据(此时线程从托管代码转为本地/用户模式代码)- ...
- Clr Via C#读书笔记---计算限制的异步操作
线程池基础 1,线程的创建和销毁是一个昂贵的操作,线程调度以及上下文切换耗费时间和内存资源. 2,线程池是一个线程集合,供应你的用程序使用. 3,每个CLR有一个自己的线程池,线程池由CLR控制的所有 ...
- Clr Via C#读书笔记---CLR寄宿和应用程序域
#1 CLR寄宿: 开发CLR时,Microsoft实际是将他实现成包含在一个dll中的COM服务器.Microsoft为CLR定义了一个标准的COM接口,并为该接口和COM服务器分配了GUID.安装 ...
- Clr Via C#读书笔记---程序集的加载和反射
#1 加载程序集 Assembly.Load: public class Assembly { public static Assembly Load(AssemblyName assemblyRef ...
- Clr Via C#读书笔记---垃圾回收机制
#1 垃圾回收平台的基本工作原理: 访问一个资源所需的具体步骤: 1)调用IL指令newobj,为代表资源的类型分配内存.在C#中使用new操作符,编译器就会自动生成该指令.2)初始化内存,设置资源的 ...
- Clr Via C#读书笔记---线程基础
趣闻:我是一个线程:http://kb.cnblogs.com/page/542462/ 进程与线程 进程:应用程序的一个实例使用的资源的集合.每个进程都被赋予了一个虚拟地址空间. 线程:对CPU进行 ...
- CLR via C# 读书笔记-26.线程基础
前言 这俩个月没怎么写文章做记录分享,一直在忙项目上线的事情,但是学习这件事情,停下来就感觉难受,clr线程这章也是反复看了好多遍,书读百遍其义自见,今天我们来聊下线程基础 1.进程是什么,以及线程起 ...
随机推荐
- away3d打包到IOS锯齿问题解决办法
很多ios设备是高清屏,一个像素顶普通设备四个像素.从这点上也许可以入手解决. 先把<requestedDisplayResolution>high</requestedDispla ...
- CenOS6.4 系统升级内核
获取要升级的内核版本的包 #wget -c https://www.kernel.org/pub/linux/kernel/v3.x/内核版本 若得到的内核的压缩格式为tar.xz,则需要两步解压 # ...
- javascript函数基础
Function类型 由于函数是对象,因此函数名实际上是一个指向函数对象的指针,不会与函数绑定 所以没有重载这个概念!!!!!!!!!!!!!!!!!!!!!!!!!! function sum1() ...
- 怎么预防sql注入攻击
假设sql是搜索用户A的文章,sql会是这样: select * from table where owner='A'; sql注入攻击者会修改用户名来实现攻击,例如把A 改成A' or 1='1 组 ...
- ASP.NET 学习小记 -- “迷你”MVC实现(1)
ASP.NET 由于采用了管道式设计,具有很好的扩展性.整个ASP.NET MVC应用框架就是通过扩展ASP.NET实现的.通过ASP.NET的管道设计,我们知道,ASP.NET的扩展点主要是体现在H ...
- 【JSF框架】 是一种标准
典型的JSF应用程序包含下列部分: 一组JSP页面 一组后台bean(为在一个页面上的UI组件定义的属性和函数的JavaBean组件) 应用程序配置资源文件(定义页面导航规则.配置bean和其它的自定 ...
- 制作第一个UI图集
按钮分有两种形式,一种是普通按钮,也就是一张没有文字的按钮图片,在需要用时,就在上面写上不同的.当前所需要的文字.量一种按钮则是图片按钮,这种按钮的特点是整个按钮就是一张图片,它既是按钮也是图片. 在 ...
- Android Learning:微信第三方登录
这两天,解决了微信第三方授权登录的问题,作为一个新手,想想也是一把辛酸泪.我想着,就把我的遇到的坑给大家分享一下,避免新手遇到我这样的问题能够顺利避开. 步骤一 微信开发者平台 我开始的解决思路是,去 ...
- mvc3.0中[ValidateInput(false)]失效的问题
在asp.net mvc3.0中[ValidateInput(false)]特性失效了,只需要在网站根目录中的web.config中做如下配置即可: <system.web> <ht ...
- Pentaho Data Integration笔记 (四):Kitchen
官方网站: http://wiki.pentaho.com/display/EAI/Kitchen+User+Documentation Kitchen Kitchen是一个可以执行Spoon编辑的J ...