[转载]介绍一下我自己开发的全新Remoting技术。(本地调用远程代码)

[转载]介绍一下我自己开发的全新Remoting技术。(本地调用远程代码) – 美丽人生 – 博客园.

前言

——————

本文介绍了一种全新的调用远程代码的技术。参考了微软 的remoting、webservice。

基础知识

——————

先抛开具体的代码,如果要实现远程代码调用,一个最简 单的模型是:

1. 使用一个HttpHandler,当有请求的时候,调用对应的代码,返回。例如:

代码

class RemoteHandler : IHttpHandler, IReadOnlySessionState
{
public bool IsReusable
{
get
{
return true;
}
}

public void ProcessRequest(HttpContext context)
{
//这里创建实例RemotingGreeting

RemotingGreeting greeting
= new RemotingGreeting();


byte[] response = greeting.Helloworld();

//这里返回调用结果到客户端

context.Response.Clear();

context.Response.ContentType = application/octet-stream;

BinaryWriter writer = new BinaryWriter(context.Response.OutputStream);

writer.Write(response);

writer.Flush();

writer.Close();

context.Response.End();
}
}

2. 客户端使用Http去访问这个Handler,就实现了最原始的远程调用

这段代码,就实现了远程调用 RemotingGreeting这个类,获取方法Helloworld();的返回值。

那么,这个过程如何实现通用呢?如何实现框架化?首先 先看看实际代码的调用效果:

代码实例

——————

首先声明一个被远程调用的对象,RemotingGreeting. 以及一个接口IRemotingGreeing

代码

class RemotingGreeting : IRemotingGreeting
{
public string Greeting(string message)
{
return Hi! + message;
}
}

[Remote(Pixysoft.Framework.Remoting.Demo, Pixysoft.Framework.Remoting.Demo.RemotingGreeting)]//这里实际指定了接口具体实现的类的Assembly和Type
public interface IRemotingGreeting
{
string Greeting(string message);
}

然后本地实现远程调用:

代码

using System;
using System.Collections.Generic;
using System.Text;

namespace Pixysoft.Framework.Remoting.Demo
{
class testcase
{
public void test()
{
//指定了调用的入口点 url
string url = http://localhost:1300/Apis/remoting.asmx;

//创建本地调用的透明代理
IRemoteChannel<IRemotingGreeting> channel = RemotingManager.CreateRemoteChannel<IRemotingGreeting>(url);

//登录远程服务器
channel.Login(xxxxxx, xxxxxxxxx);

//远程调用
string greeting = channel.RemoteProxy.Greeting(pixysoft);

//登出
channel.Logout();

//打印结果,就是“Hi!pixysoft”
Console.WriteLine(greeting);
}
}
}

正文

——————

远程调用框架的思路是:

1. 本地创建一个透明代理(RealProxy.GetTransparentProxy())

2. 用户本地的请求,被透明代理序列化为XML

3. XML传递到服务器的Handler,被解析后,加载对应的对象(Spring? 动态加载)

4. Handler运行对象,获取返回值,再序列化为XML,返回本地。

5. 本地透明代理解析XML,获取返回值。

第一步,创建透明代理。请各位先阅读 一篇相关的文章:

http://www.cnblogs.com/zc22/archive/2010/02/22/1671557.html

这里贴出核心代码的一个例子:

代码

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;

namespace Pixysoft.Framework.TestDrivens
{
public class Mock<TInterface> : RealProxy
{
public Mock()
:
base(typeof(TInterface))
{
}

public TInterface Value
{
get
{
return (TInterface)this.GetTransparentProxy();
}
}

public override IMessage Invoke(IMessage msg)
{
IMethodCallMessage methodCall
= msg as IMethodCallMessage;

//我返回 int = 1

return new ReturnMessage(1, null, 0, null, methodCall);
}
}

public interface IMock
{
int Devide(int a, int b);
}

public class testrealproxy //测试代码在这 里!!!
{
public void test()
{
IMock mock
= new Mock<IMock>().Value;

Console.WriteLine(mock.Devide(1, 2));

//输出 = 1
}
}
}

这篇文章讲解了如何实现一个接口的透明代理。本质在

public override IMessage Invoke(IMessage msg)

这里,对用户调用的方法进行序列化操作。

第二步,调用的序列化。

上文透明代理通过以下代码获取了用户调用的方法反射

IMethodCallMessage methodCall = msg as IMethodCallMessage;

MethodInfo method = methodCall.MethodBase as MethodInfo;

这里,要对调用方法MethodInfo进行序列化。 当然,就是自己去建立一个MethodInfo的xml描述,例如:

代码

<method assembly=”Pixysoft.Framework.Remoting” type=”Pixysoft.Framework.Remoting.Core.RemotingHelloworld” method=”HelloWorld” parametercount=”4″>
<parameter type=”DateTime” parameter=”para1″>2010-4-12 下午 08:52:21</parameter>
<parameter type=”String” parameter=”para2″>2</parameter>
<parameter type=”Int32″ parameter=”para3″>12</parameter>
<parameter type=”IRemotingValue” parameter=”para4″ />
<return type=”IRemotingValue” />
</method>

这个是我实际建立的MethodInfo的xml描 述。如何建立就不说了吧,很简单,用StringBuilder去拼就行了。

第三步,httpHandler解析 XML,加载对象运行结果。

客户端通过HttpPost到服务端,服务端获取了 XML之后,只要根据对应的参数加载Assembly,然后获取对象即可。具体涉及到了一些反射的操作:

Assembly assembly = Assembly.LoadFrom(assemblyname);

Type type = assembly.GetType(typename);

MethodInfo method = type.GetMethod(methodname);

获取了MethodInfo之后,只要把参数放入,获 取返回值即可。

代码

//实例化一个对象

ConstructorInfo constructorInfo
=
type.GetConstructor(BindingFlags.Public
| BindingFlags.NonPublic | BindingFlags.Instance,
null, new Type[] { }, null);

object remoteObject = constructorInfo.Invoke(new object[] { });

//调用这个对象的方法 这里省略了如何获取parameters过程

object returnvalue = method.Invoke(remoteObject, parameters);

第四步 Handler序列化返回值 为XML,返回本地。

只要把returnvalue序列化为xml即可。具 体就不叙述了。

第五步 本地透明代理解析XML,获取返回值。

本地透明代理把序列化的returnvalue再反序 列化为对象即可,然后返回

return new ReturnMessage(returnvalue, null, 0, null, methodCall);

难点讲解

——————

1. 整个调用过程最难的地方在于序列化操作。因为微软不支持接口的序列化、不支持内部类的序列化。这里需要自己实现。

2. 其次最难的在于值类型的操作。因为值类型进入了RealProxy之后,全部被装箱成为了对象(object)。这个时候直接把对象返回会抛异常,因此需 要根据具体的method.ReturnType, 逐一用值类型解析返回。

3. 再次,就是动态加载问题。Assembly.LoadFrom会有很多问题,比如版本问题、路径问题。因此要实现一个事件

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

实现了这个event之后,能够代码指定搜索 assembly的位置。具体代码我就不列举了。

后记

——————

写代码的过程,和拼装模型是一样的。只要我们手上的零 件越来越多,能实现的功能和效果就越来越多!

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏