22.15 .NET上下文
22.15.1 简介
我们已经看到AppDomain能够在运行期间实现类 型、安全和异常层面的隔离。然而还存在着比AppDomain更加细粒度的用于存储.NET对象的实体。一个.NET AppDomain能够包含多个这种叫做.NET上下文的实体。在本章,只要不会与COM+上下文概念发生混淆,我们就把它们称作上下文,这两个概念是完 全不同的(COM+上下文在8.8节介绍)。某些作者使用托管上下文(managed context)或者执行上下文(execution context)来指代.NET上下文,而非托管上下文则指代COM+上下文。所有.NET对象都存在于上下文中,每个AppDomain中至少存在一个 上下文。这个上下文称为AppDomain的默认上下文,它在AppDomain创建的时候就创建了。图22-7总结了它们之间的关系。
图22-7 进程、AppDomain和上下文
上下文的概念使得拦截对象的调用成为可能。拦截调用意味着我们可以对每个输入或输出参数做一个或多个转换。这些转换是通过消息接收器来完成的。这样做主要是为了让客户端在调用对象的方法时不会察觉到调用被拦截了以及在方法处理的前后对参数做了转换。
22.15.2 上下文绑定和上下文灵活对象
根 据上一节的内容,上下文可以看作AppDomain中一个包含对象和消息接收器的区域。对上下文里的对象的调用会转换成可以被消息接收器拦截和处理的消 息。我们知道要把调用转换成消息,必须通过透明代理这个中介。而且,仅当对象是MarshalByRefObject的子类的实例并被其所在的 AppDomain以外的实体调用时,CLR才会为它创建透明代理。这里,我们希望对所有调用使用消息接收器机制,即使是那些同一个AppDomain中 的实体所执行的调用。这个时候我们就需要用到System.ContextBoundObject类了。继承自ContextBoundObject的类 的实例同样仅能由透明代理访问。此时,甚至这个类的方法中所使用的this引用也是透明代理而不是对这个对象的直接引用。让 ContextBoundObject类继承自MarshalByRefObject是合理的,因为它很好地强调了该类的特性——它告诉CLR这个类将会 通过透明代理使用。
ContextBoundObject的子类的实例被视为是上下文绑定的。没有继承自 ContextBoundObject的类的实例则被视为是上下文灵活的。上下文绑定的对象永远在其上下文中执行。只要不是远程对象,上下文灵活的对象总 是在执行这个调用的上下文中执行。图22-8说明了以上内容。
图22-8 上下文绑定的对象与上下文灵活的对象
22.15.3 上下文attribute和上下文属性
下面我们将介绍用于在上下文层面注入消息接收器的技术。首先介绍上下文attribute和上下文属性的概念。
1.上下文attribute
上 下文attribute是指应用在上下文绑定类上的.NET attribute。上下文attribute类实现了System. Runtime.Remoting.Contexts.IContextAttribute接口。上下文绑定的类可以应用多个上下文attribute。 在这个类的对象创建期间,这个类的每个上下文attribute都要判断这个对象的创建者所在的上下文是否适用。下面这个方法执行了这个操作。
只要其中一个上下文attribute返回false,CLR就必须创建一个新的上下文来容纳这个新的对象。这样,每个上下文attribute都可以在这个新的上下文中注入一个或多个上下文属性。这些注入可以通过以下方法实现。
2.上下文属性
上 下文属性是实现System.Runtime.Remoting.Contexts.IContextProperty接口的类的实例。每个上下文可以包 含多个属性。上下文属性在上下文创建的时候通过上下文attribute注入。一旦每个上下文attribute都注入了它的属性,那么就会为每个属性调 用下面的方法。此后就无法在这个上下文中注入另外的属性了。
然后,CLR通过调用下面的方法判断新的上下文能否满足每个属性。
每个上下文属性都有一个通过Name属性定义的名称,如下所示:
上下文中承载的对象的方法可以通过调用下面的方法访问上下文属性。
这一点很有意思,上下文中的对象通过它们所在的上下文的属性可以共享信息并访问服务。不过,上下文属性的主要作用并不在于此。上下文属性的主要作用在于向相关上下文中的消息接收器区域注入消息接收器。
对 消息接收器区域的介绍是下一小节的主题。在此之前,让我们先通过示例演示上下文attribute和上下文属性的概念。对于那些读过信道那节的读者,上下 文attribute的角色相当于在信道中注入提供程序的配置文件。同样地,上下文属性的角色相当于消息接收器提供程序。
3.使用上下文attribute和属性的示例
下 面的程序定义了LogContextAttribute类和LogContextProperty类。应用了LogContext- Attribute的类的所有实例都将承载在具有LogContextProperty类型的属性的上下文中。于是,该实例就可以访问这个属性提供的服务 了。这个服务允许通过调用LogContextProperty. Log(string)方法向文件写入一个字符串。文件名是LogContextAttribute的参数。这样,我们就可以让每个类都拥有一个配置文 件。当应用了LogContextAttribute的类的新实例创建好后,boolLogContextAttribute. IsContextOK(Context)方法将判断调用构造函数的实体所在的上下文是否包含带有相同文件名的LogContextAttribute的 实例。如果不是,则会创建一个新的上下文。LogContextAttribute.GetPro- pertiesForNewContext(IConstructionCallMessage ctor)方法创建一个LogContextProperty的实例。在这个方法返回时,CLR自动把新的属性注入新的上下文。下面是程序的代码。
例22-33
该程序输出:
obj1和obj3这两个对象位于同一个上下文中,因为obj3是在obj1所在的上下文中创建的。
22.15.4 消息接收器区域
消 息接收器区域有以下四种:服务器区域、对象区域、信使区域和客户端区域。要理解区域概念,必须考虑上下文绑定的对象是否被位于另一个上下文中的实体调用。 这个实体可以是一个静态方法或者另一个对象。在我们关于区域的讨论中,我们把这个实体所在的上下文称为调用方上下文,而把被调用对象所在的上下文称为目标 上下文。目标上下文中的每个属性都可以在这些区域中注入消息接收器。
• 注入服务器区域的消息接收器拦截所有从另一个上下文发往目标上下文中所有对象的调用消息。于是,每个目标上下文有一个服务器区域。
• 注入对象区域的消息接收器拦截所有从另一个上下文发往目标对象中特定对象的调用消息。于是,上下文中每个对象会有一个对象上下文。
• 注 入信使区域的消息接收器拦截所有从另一个上下文发往目标对象中特定对象的调用消息。于是,上下文中的每个对象都有一个信使区域。信使区域和对象区域的不同 点是信使区域位于调用方上下文而不是包含对象的目标上下文。我们使用信使区域把调用方上下文的信息传递给目标上下文的消息接收器。
• 注入客户端区域的消息接收器拦截所有从目标上下文发往位于其他上下文的对象的调用消息。于是,每个目标上下文有一个客户端区域。
图22-9说明了区域的概念。目标上下文包含名为OBJ1和OBJ2的两个对象。我们选择在目标上下文中放置两个对象而不是一个是为了更好地说明对象区域和信使区域是在对象层面与消息的拦截关联起来的,而服务器区域和客户端区域则是在上下文层面与消息的拦截关联起来的。
我 们在每个区域中放置了两个自定义消息接收器是为了更好地说明一个区域能包含零个、一个或多个消息接收器。具体地说,所有自定义消息接收器都通过目标上下文 的属性注入区域,即使这个区域不属于目标上下文。因为上下文属性类是可以自定义的,所以我们可以选择哪个区域必须注入消息接收器。
你可能注意到,每个区域包含一个用于通知CLR退出区域的系统终结器接收器,不过不需要太在意它。
当调用方上下文和目标上下文处在同一个AppDomain中时,CLR会使用mscorlib.dll中CrossContextChannel内部类的实例作为信道。这个实例会使得当前线程的Context属性发生切换。图22-9展示了这些实例。
图22-9 上下文和区域
22.15.5 使用区域的示例
我们想通过例22-34的程序说明以下内容。
• 自 定义上下文attribute(CustomDisplayContextAttribute类)的代码在上下文中注入了自定义上下文属性 (CustomDisplayContextProperty类)。这个上下文属性在目标上下文的对象区域、服务器区域和客户端区域以及调用方上下文的信 使区域中注入了自定义消息接收器(CustomDisplayMessageSink类)。
• 消息接收器的行为可以通过传递给上下文attribute的参数修改。这里,这个参数是一个布尔值,它指示消息接收器是否必须在控制台上输出某些东西。
• 消 息接收器通过上下文属性注入这四个区域。CustomDisplayContextAttribute上下文attribute确保为Foo类的每个实例 创建上下文。我们首先创建Foo的实例,然后我们在这个实例上调用一个方法并穿越信使区域、服务器区域和对象区域的消息接收器。要穿越客户端区域的消息接 收器,我们创建了Foo的第二个实例,然后让第一个实例调用它。于是,这里有了三个上下文:执行Main()方法的上下文(ContextID = 0)、包含Foo的第一个实例的上下文(ContextID = 1)和包含Foo的第二个实例的上下文(ContextID = 2)。
• 上下文内部调用不会触发所有这些消息接收器的调用。这在Foo的第一个实例调用自身时可以看到。
• 在区域(这里是客户端区域)中注入了多个消息接收器。
• CLR在区域中注入消息接收器的时间。我们很清楚的看到这个时间依赖于区域的类型。
程序如下:
例22-34
执行程序后的输出如下所示。
22.15.6 调用上下文
可 以在运行在调用方上下文中的消息接收器与运行在目标上下文中的消息接收器之间传递信息。我们使用这个技术主要是为了把调用方上下文的信息传递给目标上下文 (例如调用方上下文支持某些属性)。我们把这项功能称为调用上下文。尽管它的名字中含有“上下文”这三个字,但是这项功能可以用在任何消息接收器中,包括 那些不在上下文中的。
为此,必须首先定义一个实现 System.Runtime.Remoting.Messaging.ILogicalThreadAffinative接口的类来描述要传递的信息。 在运行在调用方上下文(在信使区域或者客户端区域里)中的消息接收器的代码中,我们必须把这个类的实例附加到表示调用的消息上。在运行在目标上下文(在对 象区域或者服务器区域里)中的消息接收器的代码中,必须把这个类的实例从表示调用的消息中分离出来。这些操作是通过 IMethodMessage.LogicalCallContext属性完成的。
下面的代码演示如何运用该技术。
例22-35
我 们在前一节看到,在客户端区域和信使区域中注入消息接收器是发生在调用对象的构造函数之后。客户端区域和信使区域中的消息接收器无法把信息附加到表示构造 函数调用的消息上,而服务器区域的消息接收器却可能依然试图从表示构造函数调用的消息中分离出这个信息。在这种情况下,我们可以在上下文 attribute的GetPropertiesForNewContext()方法中附加这个信息。
例22-36
22.16 小结
22.16.1 激活对象的四种方式
我们已经看到,激活对象的方式有四种:WKO single-call模式、WKO singleton模式、CAO和对象发布。下面这张表总结了这些模式之间的主要差异。
22.16.2 截获消息
我们用了本章的一半专门来介绍如何拦截表示调用的消息以及为何这样做。图22-10简要总结了各种可能的拦截层面。
图22-10 拦截消息
分享到:
相关推荐
流程执行过程中,可以与ASP.NET上下文进行通信,接收或更新数据。 5. **工作流与ASP.NET的交互**:在实例中,主程序(ASP.NET页面或控制器)可能通过调用工作流服务来启动、暂停、恢复或终止流程。同时,工作流可以...
2. **语法讲解**:介绍Ruby语言的基本语法,特别是如何在ASP.NET上下文中使用Ruby特性,如动态类型、元编程等。 3. **Web控件和事件处理**:展示如何在Ruby代码中使用ASP.NET的服务器控件,以及如何处理用户交互...
它不仅演示了如何在ASP.NET上下文中集成WF,还展示了如何设计和实现状态机工作流。通过深入研究这个实例,开发者可以更好地掌握WF的概念,理解工作流生命周期管理,以及如何在实际项目中应用这些知识。 总之,"asp...
.NET上下文 自定义组件服务 第12章:安全 .NET安全架构 配置权限 编程式安全 Visual Studio 2005与安全 基于主体的安全 其他安全问题 附录A:基于接口的Web服务 附录B:统一Windows Forms和ASP.NET安全 附录C:反射...
标题中的“CLR无法从COM上下文0x645e18转换为COM上下文0x645f88”是一个典型的COM组件交互时出现的问题,涉及到.NET Framework的公共语言运行时(Common Language Runtime, CLR)和COM(Component Object Model)的...
本工程在objectarx2020下测试通过,如要在其他版本的sdk下使用,需要修改工程的引用文件 编译方法: 1、将解压后的文件夹放到objectarx2020 文件夹 内samples\dotNet 目录下,如G:\mywork\my-object-arx\samples\...
当在页面上标记文本时,该扩展在上下文菜单中添加新条目。... 怎么做: ... - 选择tarife.net上下文项目 标记的文本将被发送到www.tarife.net搜索,并将结果显示在一个新标签中。 支持语言:Deutsch,English
语言:Deutsch,English ... 当在页面上标记文本时,此扩展名将在上...怎么做:-在任何网站上标记文本(大部分为一个单词)-单击鼠标右键-选择tarife.net上下文项标记的文本将发送到www.tarife.net搜索并以新标签页给您。
在.NET框架中,使用Visual Studio C++进行编程时,为控件添加上下文菜单是常见的需求,这可以增强用户交互性并提供定制的功能选项。上下文菜单,也称为右键菜单,是在用户对控件执行右键点击时显示的一系列命令选项...
2. `drs`:这个文件名没有明确的.NET上下文,可能是开发者自定义的文件格式,可能包含了日期控件的数据或设置。 3. `_rels`:这个文件夹通常包含关于文档中各个部分关系的信息,按照Open Packaging Conventions标准...
在本人的.NET面向上下文、AOP架构模式(概述)一文中,我们大概了解了上下文如何辅助对象在运行时的管理。在很多时候我们急需在运行时能把对象控制在一定的逻辑范围内,在必要的时候能让他们体现出集中化的概念,如...
上下文特性(Context Attributes)和上下文属性(Context Properties)在.NET中用于控制对象的行为。它们通常用于将对象放置在特定的上下文中,并根据上下文属性的值来决定对象的行为。 1. **上下文特性的作用** ...
.NET Core 3.0 引入了可回收程序集加载上下文(Collectible AssemblyLoadContext),这是对.NET Core 动态加载和卸载程序集机制的重大改进。在.NET Framework 中,AppDomain 被用来加载程序集,但无法单独卸载一个...
46. **上下文对象**:ASP.NET上下文对象包含请求和响应信息,用于处理请求。 47. **转发与跳转**:转发(Server.Transfer)在服务器端完成,跳转(Response.Redirect)涉及客户端重定向。 48. **Socket同步通讯**...
标题和描述中重复的"2101_.net"字符串并没有提供足够的上下文来讨论.NET框架、编程概念或其他相关的IT主题。同样,标签和压缩包子文件的文件名称列表也只包含这一相同的字符串,无法推断出具体的知识点。 如果"2101...
因此,如果你的`StartWork`方法涉及到对ASP.NET上下文(如Session、Response等)的操作,可能会遇到问题,因为这些对象在非HTTP请求线程中不可用。如果需要访问ASP.NET上下文,可能需要考虑使用其他定时解决方案,如...