利用Castle IOC实现远程调用的接口统一(上)

摘要:前段时间学习了解了一下Castle,也想着写点东西。只是不知道写些什么东西好,再加上本人的文采实在是不敢恭维,所以就一直没动手写。这两天本着学习的态度写了一个Castle的Facility。不管代码有没有用,希望对您学习Castle能有一定的帮助。

主要内容
            1、功能概述

            2、如何实现服务器端

            3、如何实现客户端

            4、功能组件实现

            5、代码下载

            6、其他说明

一.功能概述

         该Facility主要功能是收集添加到Windsor组件中的本允许远程调用的方法,然后利用反射,在内部实现一个接口,通过该接口来调用这些公开的方法。也就是说对于客户端,只需要这个接口来调用服务器上的其他接口。由于只有一个调用接口,我们就可以很容易的通过简单的配置来选择不同的调用机制,比如通过Remoting,通过命名管道(NamedPipe)。本文章主要介绍如何应用该Facility.

二.如何实现服务器端

          服务器端代码很简单,只需要一行代码。

               IWindsorContainer container = new WindsorContainer(new XmlInterpreter());
         指示需要通过App.config 或 web.config来读取配置文件。

         服务器端配置是通过App.config 或 web.config来包含Windsor的配置文件, 配置也很简单。配置信息如下:
     
<?xml version="1.0" encoding="utf-8" ?>
    
<configuration>
    
        
<configSections>
            
<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
        
</configSections>
    
        
<castle>
            
<include uri="file://Castle.NamedPipe.xml" />
            
<!--<include uri="file://Castle.Remoting.xml" />-->
            
<include uri="file://Castle.Components.xml" />
        
</castle>
    
    
</configuration>

            上面的配置是通过命名管道调用机制来提供接口,如果希望通过Remoting调用机制,只需要简单的修改一下该配置。当然也需要修改客户端的配置文件,下面会提到。 我们再看看Castle.NamedPipe.xml 文件的配置信息。
            
<configuration>
    
            
<facilities>
            
                
<facility id="actionRemoting" type="Suren.Module.ActionMarshal.Manager.Facility.RemotingActionFacility,Suren.Module.ActionMarshal.Manager"></facility>
                
            
</facilities>
            
<components>
        
                
<component id="service" 
                    service
="Suren.Module.ActionMarshal.Core.IMarshalService, Suren.Module.ActionMarshal.Core"
                    type
="Suren.Module.ActionMarshal.Manager.Service.NamedPipe.NamedPipeService, Suren.Module.ActionMarshal.Manager">
                    
<parameters>
                        
<name>MarshalRemotingTest</name>    
                    
</parameters>
                
</component>
            
</components>
        
        
</configuration>

            该配置文件配置了一个自定义的Facility。用来收集组件中的接口方法。还配置了一个实现命名管道服务组件。有关该自定义的Facility与服务组件的详细信息,可以看源代码。 如果大家有需要会写写下半部分,介绍一下该Facility 的代码。
               以下是Castle.Remoting.xml 文件的配置信息
<configuration>

        
<facilities>
        
            
<facility 
                id
="remote.facility" 
                type
="Castle.Facilities.Remoting.RemotingFacility, Castle.MicroKernel"
                isServer
="true"
                registryUri
="kernel.rem"
                remotingConfigurationFile
="RemotingTcpConfig.config">
            
</facility>    
            
            
<facility id="actionRemoting" type="Suren.Module.ActionMarshal.Manager.Facility.RemotingActionFacility,Suren.Module.ActionMarshal.Manager"></facility>
            
        
</facilities>
        
<components>
            
            
<component id="service" 
                service
="Suren.Module.ActionMarshal.Core.IMarshalService, Suren.Module.ActionMarshal.Core"
                type
="Suren.Module.ActionMarshal.Manager.Service.Remoting.RemotingService, Suren.Module.ActionMarshal.Manager"
                remoteserver
="component" />
        
</components>
    
    
</configuration>

三.如何实现客户端

          客户端的配置与服务器配置比较相似。也是通过App.config或Web.config来包含其它配置文件。配置如下:

<?xml version="1.0" encoding="utf-8" ?>
        
<configuration>
        
            
<configSections>
                
<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
            
</configSections>
        
            
<castle>
                 
<include uri="file://client_NamedPipe.xml" />
                
<!--<include uri="file://client_Remoting.xml" />-->
            
</castle>
        
        
</configuration>

         上面是的配置是通过命名管道来调用服务器接口,如果希望通过Remoting调用机制,只需要简单的修改一下该配置。当然也需要修改服务器端的配置文件。 我们再看看Castle.NamedPipe.xml 文件的配置信息。
<?xml version="1.0" encoding="utf-8" ?> 
        
<configuration>
          
          
<components>
          
                
<component id="service" 
                    service
="Suren.Module.ActionMarshal.Core.IMarshalService, Suren.Module.ActionMarshal.Core"
                    type
="Suren.Module.ActionMarshal.Client.NamedPipeClient, Suren.Module.ActionMarshal.Client">
                    
<parameters>
                        
<pipeName>MarshalRemotingTest</pipeName>
                        
<server>192.168.0.68</server>
                    
</parameters>
                
</component>
          
</components>
        
        
</configuration>
            该配置文件配置了一个实现了命名管道客户端的组件,在配置文件中注入了两个参数,一个是命名管道名称,一个是命名管道服务器地址。命名管道名称必须与服务器上配置的一样。 以下是Client_Remoting.xml的配置信息:
<?xml version="1.0" encoding="utf-8" ?> 
    
<configuration>
    
      
<facilities>
      
        
<facility 
            id
="remote.facility" 
            type
="Castle.Facilities.Remoting.RemotingFacility, Castle.MicroKernel"
            remotingConfigurationFile
="RemotingTcpConfigClient.config"
            isClient
="true"
            remoteKernelUri
="tcp://localhost:2133/kernel.rem"
            baseUri
="tcp://localhost:2133" />
      
      
</facilities>
      
      
      
<components>
      
            
<component id="service" 
                service
="Suren.Module.ActionMarshal.Core.IMarshalService, Suren.Module.ActionMarshal.Core"
                type
="Suren.Module.ActionMarshal.Manager.Service.Remoting.RemotingService, Suren.Module.ActionMarshal.Manager"
                remoteclient
="component" />
      
</components>
    
    
</configuration>    
           
          客户端的调用代码如下:
IWindsorContainer container = new WindsorContainer(new XmlInterpreter());
    IMarshalService service 
= container["service"as IMarshalService;
    
object ret = service.Execute("Sum3",100,200,300);
    Console.WriteLine(ret);
            第三行代码作用是执行标识为Sum3的函数,该函数有三个参数,传递该函数的参数分别为100,200,300.执行完成后返回调用结果。

四.组件实现
 
         我们先看看一个简单的组件实现。
namespace Test.Components
    
{
        
using System;
        
using Suren.Module.ActionMarshal.Core;
        
        [Marshal]
        
public class CalcServiceImpl : MarshalByRefObject, ICalcService
        
{
            
public CalcServiceImpl()
            
{
            }

            
public int Sum(params int[] args)
            
{
                
int sum = 0;
    
                
foreach(int arg in args)
                
{
                    sum 
+= arg;
                }

                
return sum;
            }

            [Marshal(
"Sub")]
            
public int Sum(int arg)
            
{
                
int sum;
                sum 
= arg;
                
return sum;
            }

    
            [Marshal(
"Sum3",MarshalName="对三个整数的相加")]
            
public int Sum(int i1 ,int i2,int i3)
            
{
                
int sum ;
                sum 
= i1 + i2 + i3;
                
return sum;
            }

        }

        
    }
            该类上定义了MarshalAttribute属性。表示该类中的所有公共方法都允许远程调用。我们还可以在方法上也定义MarshalAttribute来修改默认的方法信息。
 
           用默认信息标识对外接口,即用方法名称(Sum)作为该对外接口的标识。
public int Sum(params int[] args)
        
{
            
int sum = 0;
    
            
foreach(int arg in args)
            
{
                sum 
+= arg;
            }

            
return sum;
        }

            用Sub作为该对外接口的标识
[Marshal("Sub")]
        
public int Sum(int arg)
        
{
            
int sum;
            sum 
= arg;
            
return sum;
        }

            用Sum3作为该对外接口的标识,并设置该接口的描述说明
[Marshal("Sum3",MarshalName="对三个整数的相加")]
        
public int Sum(int i1 ,int i2,int i3)
        
{
            
int sum ;
            sum 
= i1 + i2 + i3;
            
return sum;
        }

        

         如果我们没有在类上定义[Marshal],只在某些公共方法上定义Marshal属性。则只公开定义了Marshal属性的这些方法。
通常情况下我们把标识作为功能号。如[Marshal("10000")]  [Marshal("10001")] [Marshal("10002")] 
         调用的时候int ret = (int)service.Execute("10001",100,200,300);
         值得注意的是所有的标识号不能重复.

         在服务器上配置组件 Castle.Components.xml

<configuration>
        
<components>
    
            
<component id="calcservice" 
                service
="Test.Components.ICalcService,Test.Components" 
                type
="Test.Components.CalcServiceImpl,Test.Components">
            
</component>
            
<component id="serviceOne" 
                service
="Test.Components.IServiceOne,Test.Components" 
                type
="Test.Components.ServiceOneImpl,Test.Components">
            
</component>
        
</components>
        
    
</configuration>

在客户端上不需要作任何配置。也不需要引用这些组件
  
五.代码下载
 
       所有源代码  下载
 
 
六.其他说明

 命名管道实现代码 http://www.codeproject.com/csharp/dotnetnamedpipespart2.asp

 环境:windows 2003 \ Visual Studio 2003 \ framework1.1 编译运行成功
 
 本文原创,不允许转贴。

posted on 2006-09-26 11:49  俗人俗语  阅读(1894)  评论(3编辑  收藏  举报

导航