[Remoting] 八:元数据(收藏转帖http://www.rainsts.net/article.asp?id=415)
2008-03-26 14:15
369 查看
.NET Remoting 基础结构需要正确的元数据,以便将一个应用程序域中的对象连接到另一个域中的对象。通常我们将包含远程类型的程序集同时发布到服务器和客户端,但这并不是一个好主意。有太多的原因阻止我们这么做:
1. 我们并不想客户端开发人员知道远程对象的内部细节,诸如私有成员内容等。
2. 我们不希望每次升级都更新客户端文件。
Soapsuds
Remoting 为我们提供了一个工具 "Soapsuds"。不要被它的名字所迷惑,它同样适用于二进制序列化的远程对象,因为我们只是用它来创建一个远程代理而已。假设远程类型存放在 RemoteLibrary 中,类型全名是 RemoteLibrary.Data。
RemoteLibrary.csproj
namespace RemoteLibrary
{
public class Data : MarshalByRefObject
{
public void Test()
{
Console.WriteLine("Test AppDomain:{0}", AppDomain.CurrentDomain.FriendlyName);
}
}
}
在 "Visual Studio 2005 命令提示" 窗口中用 Soapsuds 创建客户端代理类型。
c:/> Soapsuds -types:RemoteLibrary.Data,RemoteLibrary -gc
你会看到生成的 RemoteLibrary.cs 文件,打开看一下。
using System;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Metadata;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Runtime.InteropServices;
namespace RemoteLibrary
{
[SoapType(...)]
[ComVisible(true)]
public class Data : System.Runtime.Remoting.Services.RemotingClientProxy
{
// Constructor
public Data()
{
}
public Object RemotingReference
{
get{return(_tp);}
}
[SoapMethod(...)]
public void Test()
{
((Data) _tp).Test();
}
}
}
将这个文件拷贝到客户端目录,并添加到项目中。开始编写客户端代码。
TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterActivatedClientType(typeof(RemoteLibrary.Data), "tcp://localhost:801/test");
RemoteLibrary.Data data = new RemoteLibrary.Data();
data.Test();
其实还可以使用 System.Runtime.Remoting.MetadataServices 名字空间中的相关类用代码来创建这些代理源码或者程序集。
using System.IO;
using System.Runtime.Remoting.MetadataServices;
ArrayList list = new ArrayList();
FileStream fs = new FileStream("test.xml", FileMode.OpenOrCreate);
// 将远程类型转换为 XML 架构。
MetaData.ConvertTypesToSchemaToStream(new Type[] { typeof(Data) }, SdlType.Wsdl, fs);
// 将 XML 架构流中转换为代理源码文件。
fs.Seek(0, SeekOrigin.Begin);
MetaData.ConvertSchemaStreamToCodeSourceStream(true, AppDomain.CurrentDomain.BaseDirectory, fs, list);
// 显示所生成的代理源码文件名。
foreach (string s in list) Console.WriteLine(s);
// 将生成的源码转换为程序集文件。
MetaData.ConvertCodeSourceStreamToAssemblyFile(list, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "test.dll"), null);
接口隔离
还有一个方式就是使用接口进行隔离,这样客户端就不会看到远程类型。我们继续用上面的例子做演示。
1. 创建接口类型项目。项目中包含接口和一个工厂类型,由工厂类型负责创建目标类型。(注意为避免循环引用,我们通过配置文件读取目标类型信息。)
RemoteInterface.projc
namespace RemoteInterface
{
public interface IData
{
void Test();
}
public class Factory : MarshalByRefObject
{
public IData NewData()
{
return (IData)Activator.CreateInstance(Type.GetType(ConfigurationManager.AppSettings["data"]));
}
}
}
配置文件
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="data" value="RemoteLibrary.Data,RemoteLibrary"/>
</appSettings>
</configuration>
2. 修改原类型使其实现 IData 接口,注意添加 RemoteInterface.dll 引用。
RemoteLibrary.csproj
namespace RemoteLibrary
{
public class Data : MarshalByRefObject, RemoteInterface.IData
{
public void Test()
{
Console.WriteLine("Test AppDomain:{0}", AppDomain.CurrentDomain.FriendlyName);
}
}
}
3. 在服务器端,除了 RemoteLibrary.Data,还要注册 RemoteInterace.Factory。
Server.csproj
TcpServerChannel channel = new TcpServerChannel(801);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.ApplicationName = "test";
RemotingConfiguration.RegisterActivatedServiceType(typeof(Factory));
RemotingConfiguration.RegisterActivatedServiceType(typeof(Data));
4. 将 RemoteInterface.dll 提供给客户端,添加引用后开始编码。
Client.csproj
RemotingConfiguration.RegisterActivatedClientType(typeof(Facade), "tcp://localhost:801/test");
RemotingConfiguration.RegisterActivatedClientType(typeof(IData), "tcp://localhost:801/test");
Factory factory = (Facade)Activator.CreateInstance(typeof(Factory), null);
IData data = factory.NewData();
data.Test();
这种方式稍显复杂,但从架构模式上来说要更好一些。它隔绝了目标类型和客户端的联系,服务器可以更灵活地变化和升级。
点击下载该演示代码
1. 我们并不想客户端开发人员知道远程对象的内部细节,诸如私有成员内容等。
2. 我们不希望每次升级都更新客户端文件。
Soapsuds
Remoting 为我们提供了一个工具 "Soapsuds"。不要被它的名字所迷惑,它同样适用于二进制序列化的远程对象,因为我们只是用它来创建一个远程代理而已。假设远程类型存放在 RemoteLibrary 中,类型全名是 RemoteLibrary.Data。
RemoteLibrary.csproj
namespace RemoteLibrary
{
public class Data : MarshalByRefObject
{
public void Test()
{
Console.WriteLine("Test AppDomain:{0}", AppDomain.CurrentDomain.FriendlyName);
}
}
}
在 "Visual Studio 2005 命令提示" 窗口中用 Soapsuds 创建客户端代理类型。
c:/> Soapsuds -types:RemoteLibrary.Data,RemoteLibrary -gc
你会看到生成的 RemoteLibrary.cs 文件,打开看一下。
using System;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Metadata;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Runtime.InteropServices;
namespace RemoteLibrary
{
[SoapType(...)]
[ComVisible(true)]
public class Data : System.Runtime.Remoting.Services.RemotingClientProxy
{
// Constructor
public Data()
{
}
public Object RemotingReference
{
get{return(_tp);}
}
[SoapMethod(...)]
public void Test()
{
((Data) _tp).Test();
}
}
}
将这个文件拷贝到客户端目录,并添加到项目中。开始编写客户端代码。
TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterActivatedClientType(typeof(RemoteLibrary.Data), "tcp://localhost:801/test");
RemoteLibrary.Data data = new RemoteLibrary.Data();
data.Test();
其实还可以使用 System.Runtime.Remoting.MetadataServices 名字空间中的相关类用代码来创建这些代理源码或者程序集。
using System.IO;
using System.Runtime.Remoting.MetadataServices;
ArrayList list = new ArrayList();
FileStream fs = new FileStream("test.xml", FileMode.OpenOrCreate);
// 将远程类型转换为 XML 架构。
MetaData.ConvertTypesToSchemaToStream(new Type[] { typeof(Data) }, SdlType.Wsdl, fs);
// 将 XML 架构流中转换为代理源码文件。
fs.Seek(0, SeekOrigin.Begin);
MetaData.ConvertSchemaStreamToCodeSourceStream(true, AppDomain.CurrentDomain.BaseDirectory, fs, list);
// 显示所生成的代理源码文件名。
foreach (string s in list) Console.WriteLine(s);
// 将生成的源码转换为程序集文件。
MetaData.ConvertCodeSourceStreamToAssemblyFile(list, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "test.dll"), null);
接口隔离
还有一个方式就是使用接口进行隔离,这样客户端就不会看到远程类型。我们继续用上面的例子做演示。
1. 创建接口类型项目。项目中包含接口和一个工厂类型,由工厂类型负责创建目标类型。(注意为避免循环引用,我们通过配置文件读取目标类型信息。)
RemoteInterface.projc
namespace RemoteInterface
{
public interface IData
{
void Test();
}
public class Factory : MarshalByRefObject
{
public IData NewData()
{
return (IData)Activator.CreateInstance(Type.GetType(ConfigurationManager.AppSettings["data"]));
}
}
}
配置文件
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="data" value="RemoteLibrary.Data,RemoteLibrary"/>
</appSettings>
</configuration>
2. 修改原类型使其实现 IData 接口,注意添加 RemoteInterface.dll 引用。
RemoteLibrary.csproj
namespace RemoteLibrary
{
public class Data : MarshalByRefObject, RemoteInterface.IData
{
public void Test()
{
Console.WriteLine("Test AppDomain:{0}", AppDomain.CurrentDomain.FriendlyName);
}
}
}
3. 在服务器端,除了 RemoteLibrary.Data,还要注册 RemoteInterace.Factory。
Server.csproj
TcpServerChannel channel = new TcpServerChannel(801);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.ApplicationName = "test";
RemotingConfiguration.RegisterActivatedServiceType(typeof(Factory));
RemotingConfiguration.RegisterActivatedServiceType(typeof(Data));
4. 将 RemoteInterface.dll 提供给客户端,添加引用后开始编码。
Client.csproj
RemotingConfiguration.RegisterActivatedClientType(typeof(Facade), "tcp://localhost:801/test");
RemotingConfiguration.RegisterActivatedClientType(typeof(IData), "tcp://localhost:801/test");
Factory factory = (Facade)Activator.CreateInstance(typeof(Factory), null);
IData data = factory.NewData();
data.Test();
这种方式稍显复杂,但从架构模式上来说要更好一些。它隔绝了目标类型和客户端的联系,服务器可以更灵活地变化和升级。
点击下载该演示代码
相关文章推荐
- [Remoting] 四:生存期租约(收藏转帖http://www.rainsts.net/article.asp?id=411)
- NET Remoting一,二(收藏转帖http://www.rainsts.net/article.asp?id=408)
- [Remoting] 十二:配置文件(收藏转帖http://www.rainsts.net/article.asp?id=420)
- [Remoting] 五:信道(收藏转帖http://www.rainsts.net/article.asp?id=412)
- [Remoting] 六:异步调用(收藏转帖http://www.rainsts.net/article.asp?id=413)
- [Remoting] 三:激活模式(收藏转帖http://www.rainsts.net/article.asp?id=410)
- [Remoting] 七:调用上下文(收藏转帖http://www.rainsts.net/article.asp?id=414)
- [Remoting] 九:动态发布(收藏转帖http://www.rainsts.net/article.asp?id=416)
- [Remoting] 十:追踪服务(收藏转帖http://www.rainsts.net/article.asp?id=417)
- Message Queuing(收藏转帖http://www.rainsts.net/article.asp?id=418)
- [Remoting] 十一:事件(收藏转帖http://www.rainsts.net/article.asp?id=419)
- 从雨痕老大的博客上转来的 http://www.rainsts.net/article.asp?id=1066 读书人偷书不算窃 :)
- [ASP.NET 优化] IIS6 Gziphttp://www.rainsts.net/article.asp?id=531
- 动态调用 WebService (收藏转贴http://www.rainsts.net/article.asp?id=304)
- Ajax开发之JSON应用http://onewww.net/blog/article.asp?id=47
- asp.net控件开发基础 来源:http://www.clingingboy.com/blog/article.asp?id=258
- ASP.NET 2.0 URL映射技巧http://onewww.net/blog/article.asp?id=83
- winsock学习笔记(一)(http://www.vccode.net/article_view.asp?id=737)
- winsock学习笔记(二)(http://www.vccode.net/article_view.asp?id=738)
- Asp.NET 2.0学习资源(reference from http://www.eyeya.com/article.asp?id=197)