OGSI.NET概述
1.基础架构
OGSI.NET的目标是尽可能地利用Microsoft核心的技术去实现OGSI。对于设计而言,是尽量令架构中的层尽可能“薄”,这样的目的是为了在Microsoft提供了技术的新版本的时候能够很方便地利用上。特别地,是指Web Services security的标准,但是这个标准到目前为止还没有一个公共的实现,微软对其有实现,而其他公司也有。因此,设计者希望微软能够提供一套SDK,即使有升级或变动,也是SDK内部的事,不需要开发人员对这些版本问题感到愁心,这也达到了以上令层尽可能薄的目的。而WSE(Web Services Enhancements)正属于此类SDK。
下面来说说OGSI.NET的基础架构。在设计中,OGSI.NET有一个实体容器容纳了全部的运行在同一台主机上的服务实例。这个容器进程是由一个应用程序域(AppDomains)的集合构成的,之所以提到应用程序域,是因为.NET的这个机制保证了进程内部的内存保护,即使一个AppDomain崩溃了,也完全不会影响到其他的AppDomains。除了每一个服务实例运行在它们的AppDomains中外,还有一个AppDomain负责容器的逻辑(比如调度、消息的处理等等功能)。在这个AppDomains中的对象可称为调度器(Dispatcher)。在现行版本的OGSI.NET中(OGSI.NET 2.0),每个服务都会被放在它自己独立的AppDomain中,为什么这样子做呢?举个例子,假如被同一个factory(OGSA,Open Grid Services Architecture,中定义的创建网格服务的接口)创建的服务都存在于同一个AppDomain中,这样的方式虽然在服务间进行通信显得很有效率,但是假如有一个错误的服务或是一个恶意的服务直接访问了AppDomain中其它服务的内存,付出的却是安全的代价。
当一个客户端向OGSI.NET发送请求的时候,它实际上是向IIS服务器发送信息。为了让网格服务支持随心所欲的名字,OGSI.NET使用了ISAPI过滤器在请求信息进入IIS请求链的前期就把它拦截了。过滤器重写了请求,所以IIS会把它调度给OGSI.NET的ASP.NET HttpHandler。这个HttpHandler调度这个请求给OGSI.NET的容器。容器进程拥有一个线程池,每一个IIS请求都会引起一个线程起执行调度器。调度器会决定哪个服务实例可以取得请求同时将线程的执行转移到合适的AppDomain的对象中。
在AppDomain里面,控制被转移到一个叫做Grid Service Wrapper(GSW)的对象中。一个GSW包括了一个服务的实例,包括它的方法的实现和它的服务数据。GSW维护着服务所支持的port type的一个列表(包括OGSI指定的由OGSI.NET提供的port type,以及自定义的port type。比如GridService port type和NotificationSouce port type等),另外还有序列化器和逆序列化器,这两个是为了满足服务支持多种消息协议(比如SOAP或.NET Remoting)的需要而存在的。GSW执行对每一个特定消息的处理,并逆序列化请求信息,从中得到要调用的方法的名字以及参数,通过请求中的参数还有特定的消息数据(比如SOAP标头数据)来调用方法。当调用返回数据时,GSW再将这些数据序列化成一个二进制array并传回给调度器,调度器再将这个array传给IIS并返回给客户。
二。系统元素
下面,再详细讨论一下OGSI.NET中的几个主要组件:调度器、服务包装器(网格服务和轻量级服务)、Factories以及消息处理器。
2.1 调度器(Dispatcher)
调度器是在客户端请求与服务实例之间的一个接口,它的主要功能是将请求消息路由到合适的服务实例中并将结果返回给客户端。调度器包含了从GSR(Grid Service Reference)到在容器中的AppDomain的映射表。原始的请求被调度到所请求的服务的AppDomain的GSW中,GSW会执行请求的工作并将一串字节流返回给调度器,调度器再返回给客户端
调度器的设计的简明性是经过深思熟虑的了,它能够帮助处理多个并发的请求访问容器,因为它能令请求各自独立,互不干扰。安全同样被加强了,因为调度器并未对进或出的消息进行加工处理,假如它对消息中的类型进行marshall/unmarshall的工作,那么表明它将潜在地运行用户的代码,而这个会令容器处于一种非常危险的境况中。事实上,在处理AppDomain中的所请求的服务实例的消息过程中,只有该实例受到影响。
2.2 GSW(Grid Service Wrapper)
GSW包住了网格服务实例的各种功能单元,每一个在容器中的AppDomain(调度器的AppDomain除外)都有一个GSW,每一个GSW也包装了一个网格服务实例。GSW对于网格服务的作者来说是一个很方便的处理单元,因为它提供了
可插入的,服务特定的消息序列化和逆序列化。
支持插件式的由服务提供的port type,还包括那些并非由服务作者写的port type,比如网格服务特有的port type。
用于管理SDE的API。
支持服务安全策略。
GSW也为调度器提供了一个访问任何一个网格服务实例的接口。GSW的ProcessRequest方法就是用来从一个网格服务实例本身取得它的WSDL文档,另外,还允许一个实例修改自己的WSDL,比如,更新它的通讯终端)。
网格服务的作者可以用.NET的特性(Attribute)去修饰他们的服务代码,而这些特性也在运行的时候提供给容器有关服务的信息。另外,容器的配置文件中也提供了更多的有关服务的信息。当GSW在一个AppDomain中被实例化的时候,它将含有对应的服务的程序集载入。配置文件会告诉GSW在容器中注册的哪种序列化/逆序列化的模型是适用于该服务的,服务的类上的特性声明了被服务所支持的port type。GSW指明了所有服务的port type的实例,包括由服务作者写的以及被OGSI规范定义并包含在OGSI.NET中的。服务的SDE(service data element)被GSW初始化,并通过OGSI规范所定义的接口暴露出来。最后,服务的policy由服务的policy特性初始化,每一个服务的请求都会被GSW检查它的policy。
2.3 轻量级服务包装
GSW由容器的功能所决定,这是为了更好地去处理请求和动态地创建或销毁服务实例。但是容器也可以提供给服务的作者以“服务”,这种服务器端的服务的功能会有一定的限制(比如某些只是维持着某些SDE,象ServiceGroupEntry)。这种服务经常被能够在与一些其它服务配合使用,但在有经常性的跨越AppDomain边界的通讯的时候,会令维持这些轻量级服务在它们各自的AppDomain中的保护机制变得超负荷。
OGSI.NET提供了第二种服务,叫做“轻量级服务”。它允许实体使用OGSI定义的但有一定限制的功能,而不需要整个容器在下面支持它,也不需要factory服务去创建它。在OGSI.NET中,这种轻量级的服务是被轻量级的服务包装(LWSW)所包住的。轻量级的服务和网格服务很相似,但是有以下约束:
不能创建其它的服务。
当父网格服务或者客户端终止时,其也会终止。或者父网格服务和客户端都可以销毁它。
不需要具备网格服务的可配置性(一个网格服务有服务参数和和全局参数。服务参数用于到服务实例,而全局参数是用于在容器中运行的每一个实例。LWSW没有服务参数,但其在服务器端创建的时候,会使用容器的全局参数)
2.4 Factories
Factories是一种创建其他服务实例的服务,这是在OGSI中定义了的网格接口。在OGSI.NET中,Factory服务意味这创建一个新的AppDomain,并在其中创建一个新的GSW。GSW会将对应的服务的程序集装载进内存,并实例化一个服务。一个Factory服务使用公开的实例名存储着一个对这个新的AppDomain中的GSW的引用(GSR),这个映射也会被传送到调度器。对象的引用可以看成是一个包装,并可跨应用程序域传送,新的服务实例的引用就是这样从Factory的域传送到调度器的域。
在容器启动的时候,容器的配置文件会指定由Factory创建的实例的类型。在OGSI.NET中,还有第二种不同的Factory,称为“Meta-Factory”。Meta-Factory接收一个程序集的集合,程序集定义了一个网格服务的类,类中有一个createService方法并有创建服务的参数。Meta-Factory创建一个新的Factory,Factory将程序集中定义的服务实例化,包括自动产生新的服务的WSDL文档。通过以上方式,Meta-Factory可以将在容器启动时未指定的以及尚未在容器中初始化的服务实例部署进容器中。
2.5 消息处理器
消息处理器对服务实例输入输出的消息执行消息格式的特定处理过程。OGSI.NET 2.0包含了两个消息处理器,分别用来处理SOAP与Remoting的消息格式。当一个服务实例被创建的时候,它的GSW也会为服务所支持的每种消息格式创建消息处理器。当请求信息以字节数组的形式到达调度器的时候,消息处理器会将它逆序列化,这个过程包括创建每一个所需要的参数对象及处理消息头。当请求完成后,或者一个异常被抛出的时候,处理器会序列化这些结果,形成一个字节流。然后交给调度器,并返回给客户端。通过这种方式,调度器处理传输协议,而消息处理器处理消息的协议。消息处理器允许服务作者书写服务的时候,不必关心消息的问题,Marshalling/UnMarshalling和异常都被消息处理器透明地进行了处理。
(注:OGSI.NET以Remoting的方式支持HTTP的二进制数据传输。Remoting消息处理器处理二进知的消息格式,而Microsoft Remoting系统则处理传输。)
三 调用服务
每一个网格服务的实例都提供了一些可以让客户端调用的函数。下面将讨论处理客户请求的过程。
当一个请求到达IIS WEB服务器的时候,会发生以下的步骤:
1.ISAPI过滤器:一个ISAPI过滤器冲写请求的目的URL,这样请求就可以被OGSI.NET的托管代码中的HttpHandler所处理。
(注:ISAPI过滤器通过重写请求URL将请求调度给ASP.NET基础架构,这点是必须的。因为IIS根据所请求的页面的扩展名调度请求<比如,所请求的asmx页面会交给ASP.NET来处理>)。为了处理随心所欲的服务名,便使用了ISAPI过滤器。因为请求会在处理的前期被拦截<即在IIS开始调度之前>,假如请求采用了容器所定义的前缀,那么请求将会被拦截,这样才可交给OGSI.NET的HttpHandler来处理。)
2.HttpHandler路由:HttpHandler将消息调度出IIS/ASP.NET系统,送往OGSI.NET容器,请求消息被送往容器中的调度器。
3.调度器寻找网格服务:调度器查找到在调度器的服务表中的请求URL,然后通过URL寻找合适的GSW。调度器得到GSW的句柄,并称它为ProcessRequest方法,这个方法以原始的消息作为参数。
4.处理消息头:GSW的消息处理器处理原始的消息的消息头,假如是个SOAP消息,那么它将会通过WSE的流水线进行处理。容器会使用消息头的信息来检查调用是否符合服务的安全策略。
5.取得方法的名称和参数:消息处理器逆序列化消息体,取得客户端所要调用的方法的名称,以及为所调用的参数进行译码的工作。
6.为方法名取得方法句柄:GSW从它port type数组中找到实现了所指定的方法的port type,然后使用反射取得所需要的方法的句柄。
7.调用方法:GSW调用所请求的方法并取得结果。
8.序列化结果:GSW使用消息处理器序列化返回结果或抛出的异常,形成一个字节数组。
9.将结果返回给客户端:将结果的数组送到调度器,调度器再将其送到HttpHandler,再送到IIS,IIS会结果再传回给客户端。
在OGSI框架中有几种类型的持久性:
·在启动的时候,被自动装载进容器的服务。因此,“持久”就意味着是关闭和启动。
·并不需要软状态的存活信息的服务(比如,拥有无限存活时间的服务)
·状态可以保存在永久的介质上(比如磁盘)的服务,这些状态也可以被装载回正在运行中的服务实例。
这些服务必须可用,以令到容器能够发挥作用。举些例子,索引/注册服务用来发现存在着的服务实例,处理识别服务用来决定怎样与它们进行通讯。OGSI.NET的容器配置文件中允许有这些当容器初始化时被创建和载入的服务的规范说明。
OGSI规范定义了服务超时的概念。一个服务假如在它的规定时间内假如没有接收到来自客户端或另一个服务的消息,那么它将会“死亡”,这种机制保证了容器不会变得凌乱。然而,也可以不使用Keep-Alive消息但能令到服务不超时,这就是为服务设置一个足够长的时间,只要容器一起在运行,那么它就一直不死亡。但是也有一个问题,即当容器被关闭或崩溃后,再重启,这样设置的服务并不会重启,这点和列在容器的配置文件中的服务是不相同的。很明显地,在容器配置文件中的服务有着两种持久性。
当服务超时的时候,移走服务的工作是由调度器来做的。调度器会周期性地运行一个“垃圾收集器”来移走老的实例。OGSI的规范中并没有说当服务超时的时候必须立即将它移走,只是客户端不能再指望它可用了。这意味着调度器的垃圾收集器并不需要与服务实例的时钟保持高度同步。
永久的服务状态可以通过SDE(Service Data Element)得到支持。GSW提供了由OGSI规范定义的功能来访问SDE。在OGSI.NET中服务特定的SDE必须通过服务的、或port type的类的属性,或者数据成员的属性来指定。在默认情况,在服务实例重启的时候,这个数据必须并不加以保持。但是,SDE还是可用通过它自身的属性告诉容器,当它的值改变的时候保存它的值,当它的值不可知的时候载入(可能是在服务正在启动的时候)。
OGSI.NET中,令SDE的值改变的代码称为SetHandler,取得SDE的值的代码称为GetHandler。网格服务的作者可以随心所欲地为每个SDE写GetHandler和SetHandler,以令其持久化(或者用其它函数)。
5. 安全性
创建一个基于.NET的容器会涉及到很多安全性的问题。一部分是与.NET相关,一部分是与宿主环境相关。首先,OGSI.NET通过在GSW的消息处理器运行的WSE流水线,提供了对服务实例的消息层的安全机制。
另外,还有一些安全问题涉及到调度器和容器。怎样保护系统组件不会因糟糕的实现或者恶意的服务而遭到破坏呢?应用程序域的机制提供了进程内的内存保护机制,而不需要为每一个服务创建重量级的进程。只允许每一个服务实例在其自己的AppDomain中存活,为其它在容器内的大量服务提供了保护。因为GSW实际上只调用在其AppDomain内的服务的方法,所以即使出现了问题令服务崩溃或者中止,也不会影响到调度器和容器中其它的服务。但是,假如允许服务调用非托管的代码的话,它们会绕过AppDomain的保护机制。
Factory创建网格服务实例的时候,会创建一个新的AppDomain,然后在AppDomain中创建一个GSW,GSW再将网格服务所需要的程序集装载进来。在一个新的AppDomain中装载服务的程序集,并初始化网格服务,可以令容器中的其余部分受到保护,不会因为创建服务的代码的潜在BUG而受到破坏。
我们同样希望能够在运行服务的时候,让某些特定的用户拥有一些特权。注意,这并不是意味着在某种用户身份下能够简单地创建一些计算的工作,而只是让改服务能够以某种用户的身份访问某些本地资源。有两个方案,第一是拥有一个具有分级机制的容器系统,在这个系统里面,一个单独的主控制容器调度其它具有各自不同的Windows用户身份的容器。每一个这样的用户容器可只可以创建基于特定的用户ID的服务,因此,容器中的每一个服务就可看成是容器的所有者。这种方案与使用GT3 Managed Job Service进行计算很相似。另一个方案是让每一个服务中活跃的线程以服务作者的Windows身份来运行。通过这种方式,多个拥有不同ID的线程可以在同一个容器中运行。
虽然在WEB安装与部署项目里的用户界面视图无法取得安装路径,也无法将安装路径放入InstallContext的Parameter里面,当然,也更不能通过遍历Parameter里面的变量来读取安装路径的值。但是,可以利用反射的机制。
Installer类的Install方法,实际上是在完成拷贝文件后才执行的。而所添加的自定义操作的类,在运行时,是会先被拷贝到安装目录的根目录下面(安装完后发现不见了,估计是被删掉了)。所以,完全可以通过反射的机制去读取该程序集的路径从而得到安装路径。代码很简单
string stLocation;
Assembly asm = Assembly.GetExcutingAssembly ();
stLocation = asm.Location;
另外,曾认为这种方法与读取AppDomain的APPBASE方法是一样的,但是,实际上有不同。
有三种方式去读取AppDomain的基目录路径
string dir1 = AppDomain.CurrentDomain.BaseDirectory;
string dir2 = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
string dir3 = (string) AppDomain.CurrentDomain.GetData("APPBASE");
在MSDN对基目录的解释是“程序集管理器开始探测应用程序集的目录”
本来,我觉得读出来的至少应该是安装程序的所在的目录,但是读取出来的属性实际上居然是“系统盘:\windows\system
我所知道的,在system32目录下的相关文件,有作为“垫片”的用来加载托管程序、进行即时编译并加载相应版本的CLR的mscoree.dll,也有两个版本的CLR,一个是mscorwks.dll,这个是工作站版本的CLR,一个是mscorsvr.dll,这个是服务器版本的CLR。但是觉得这些文件都和AppDomain的基目录风马牛不相及,实在是比较困惑。
设想Windows Installer假如在这个目录下放有某几个.NET版本的dll,而Installer类在这些dll里面有定义,在安装程序的时候,那么应该会首先使用到这些文件,这样的解释就比较合理了。但是,这还是个人的设想,希望能得到证实。欢迎大家讨论。
本文来自博客园,作者:Slashout,转载请注明原文链接:https://www.cnblogs.com/SlashOut/archive/2006/01/05/311646.html