惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Help Net Security
Help Net Security
G
Google Developers Blog
雷峰网
雷峰网
WordPress大学
WordPress大学
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Engineering at Meta
Engineering at Meta
Security Latest
Security Latest
T
Threat Research - Cisco Blogs
AWS News Blog
AWS News Blog
F
Full Disclosure
C
Cybersecurity and Infrastructure Security Agency CISA
T
The Exploit Database - CXSecurity.com
J
Java Code Geeks
U
Unit 42
C
Cyber Attacks, Cyber Crime and Cyber Security
V
V2EX
C
Cisco Blogs
博客园 - 司徒正美
Project Zero
Project Zero
L
LINUX DO - 热门话题
阮一峰的网络日志
阮一峰的网络日志
Blog — PlanetScale
Blog — PlanetScale
Scott Helme
Scott Helme
A
About on SuperTechFans
Hugging Face - Blog
Hugging Face - Blog
S
Securelist
小众软件
小众软件
aimingoo的专栏
aimingoo的专栏
S
Schneier on Security
G
GRAHAM CLULEY
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyberwarzone
Cyberwarzone
MongoDB | Blog
MongoDB | Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 叶小钗
T
Threatpost
Recorded Future
Recorded Future
C
CXSECURITY Database RSS Feed - CXSecurity.com
宝玉的分享
宝玉的分享
N
News and Events Feed by Topic
人人都是产品经理
人人都是产品经理
The Register - Security
The Register - Security
S
Security Archives - TechRepublic
博客园 - Franky
N
News | PayPal Newsroom
Simon Willison's Weblog
Simon Willison's Weblog
S
SegmentFault 最新的问题
W
WeLiveSecurity
A
Arctic Wolf
B
Blog

博客园 - 邹标财

如何写规范需求分析说明书 从工程师到项目管理 程序员要避免的五种程序注释方式 浅谈JavaScript编程语言的编码规范 软件公司的岗位职责 项目管理软件Project实战应用 C# .Net 基础 33条经典面试题目及答案 一步一步学Remoting之六:事件(1) 一步一步学Remoting之六:事件(2) 一步一步学Remoting之五:异步操作 - 邹标财 - 博客园 一步一步学Remoting之四:承载方式(2) 一步一步学Remoting之四:承载方式(1) 一步一步学Remoting之二:激活模式 一步一步学Remoting之一:从简单开始 《Visual C# 最佳实践》第二章 控制语句 (二):类型转换 《Visual C# 最佳实践》第二章 控制语句 (一):语句结构 《Visual C# 最佳实践》第一章 程序设计 (四):运算符 《Visual C# 最佳实践》第一章 程序设计 (三):变量 《Visual C# 最佳实践》第一章 程序设计 (二):数据类型
一步一步学Remoting之三:复杂对象
邹标财 · 2010-06-10 · via 博客园 - 邹标财

 一步一步学Remoting之三:复杂对象这里说的复杂对象是比较复杂的类的实例,比如说我们在应用中经常使用的DataSet,我们自己的类等,通常我们会给远程的对象传递一些自己的类,或者要求对象返回处理的结果,这个时候通常也就是需要远程对象有状态,上次我们说了几种激活模式提到说只有客户端激活和Singleton是有状态的,而客户端激活和Singleton区别在于Singleton是共享对象的。因此我们可以选择符合自己条件的激活方式:
                        状态      拥有各自实例
Singleton              有            无
SingleCall              无            有
客户端激活              有            有
 
在这里,我们先演示自定义类的传入传出:
先说一个概念:MBV就是按值编码,对象存储在数据流中,用于在网络另外一端创建对象副本。MBR就是按引用编组,在客户机上创建代理,远程对象创建ObjRef实例,实例被串行化传递。

我们先来修改一下远程对象:

using System; namespace RemoteObject 

    
public class MyObject:MarshalByRefObject 
    { 
        
private MBV _mbv;
        
private MBR _mbr;
        
public int Add(int a,int b) 
        { 
            
return a+b; 
        } 
public MBV GetMBV()
        {
            
return new MBV(100);
        }
public MBR GetMBR()
        {
            
return new MBR(200);
        }
public void SetMBV(MBV mbv)
        {
            
this._mbv=mbv;
        }
public int UseMBV()
        {
            
return this._mbv.Data;
        }
public void SetMBR(MBR mbr)
        {
            
this._mbr=mbr;
        }
public int UseMBR()
        {
            
return this._mbr.Data;
        }
    } 

    [Serializable]

public class MBV
    {
        
private int _data;
        
public MBV(int data)
        {
            
this._data=data;
        }
        
public int Data
        {
            
get
            {
                
return this._data;
            }
            
set
            {
                
this._data=value;
            }
        }
    }
public class MBR:MarshalByRefObject
    {
        
private int _data;
        
public MBR(int data)
        {
            
this._data=data;
        }
        
public int Data
        {
            
get
            {
                
return this._data;
            }
            
set
            {
                
this._data=value;
            }
        }
    }


Get方法用来从服务器返回对象,Set方法用于传递对象到服务器,Use方法用来测试远程对象的状态是否得到了保存。

我们先来测试一下客户端激活模式:(服务器端的设置就不说了)

    RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.CreateInstance(typeof(RemoteObject.MyObject),null,new object[]{new System.Runtime.Remoting.Activation.UrlAttribute(System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"])});
            RemoteObject.MBV mbv
=app.GetMBV();
            Console.WriteLine(mbv.Data);
            RemoteObject.MBR mbr
=app.GetMBR();
            Console.WriteLine(mbr.Data);
            mbv
=new RemoteObject.MBV(100);
            app.SetMBV(mbv);
            Console.WriteLine(app.UseMBV());
            
//mbr=new RemoteObject.MBR(200);
            
//app.SetMBR(mbr);
            
//Console.WriteLine(app.UseMBR());
            Console.ReadLine();


依次显示:100,200,100
前面2个100,200说明我们得到了服务器端返回的对象(分别是MBV和MBR方式的),后面一个100说明我们客户端建立了一个MBV的对象传递给了服务器,因为客户端激活模式是有状态的所以我们能使用这个对象从而输出100,最后我们注释了几行,当打开注释运行后出现异常“由于安全限制,无法访问类型 System.Runtime.Remoting.ObjRef。”这个在【通道】一节中会讲到原因。

好了,我们再来测试一下Singleton(别忘记修改客户端配置文件中的URI哦)

RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]);
            
//RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.CreateInstance(typeof(RemoteObject.MyObject),null,new object[]{new System.Runtime.Remoting.Activation.UrlAttribute(System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"])});


后面的语句省略,运行后同样出现100,200,100-》Singleton也是能保存状态的。
SingleCall呢?修改一下服务端的Config再来一次,在“Console.WriteLine(app.UseMBV());”出现了“未将对象引用设置到对象的实例。”因为服务端没有能够保存远程对象的状态,当然出错。

再看一下.net内置的一些复杂对象,比如DataSet,可能传入传出DataSet和DataTable在应用中比较普遍,一些不可序列话的类我们不能直接传递,比如DataRow等,要传递的时候可以考虑放入DataTable容器中。

远程对象修改如下:

using System; 
using System.Data;namespace RemoteObject 

    
public class MyObject:MarshalByRefObject 
    { 
        
public DataSet Method(DataSet ds)
        {
            DataTable dt
=ds.Tables[0];
            
foreach(DataRow dr in dt.Rows)
            {
                dr[
"test"]=dr["test"]+"_ok";
            }
            
return ds;
        }
    }


客户端修改如下:

    RemoteObject.MyObject app = (RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]);
            DataSet ds
=new DataSet();
            DataTable dt
=new DataTable();
            dt.Columns.Add(
new DataColumn("test",typeof(System.String)));
            DataRow dr
=dt.NewRow();
            dr[
"test"]="data";
            dt.Rows.Add(dr);
            ds.Tables.Add(dt);
            ds
=app.Method(ds);
            Console.WriteLine(ds.Tables[
0].Rows[0]["test"].ToString());
            Console.ReadLine();


运行后发现输出data_ok了。在这里不管用哪种模式来激活都会得到data_ok,因为我们并没有要求远程对象来保存状态。

总结:

所有必须跨越应用程序域的本地对象都必须按数值来传递,并且应该用 [serializable] 自定义属性作标记,否则它们必须实现 ISerializable 接口。对象作为参数传递时,框架将该对象序列化并传输到目标应用程序域,对象将在该目标应用程序域中被重新构造。无法序列化的本地对象将不能传递到其他应用程序域中,因而也不能远程处理。通过从 MarshalByRefObject 导出对象,可以使任一对象变为远程对象。当某个客户端激活一个远程对象时,它将接收到该远程对象的代理。对该代理的所有操作都被适当地重新定向,使远程处理基础结构能够正确截取和转发调用。尽管这种重新定向对性能有一些影响,但 JIT 编译器和执行引擎 (EE) 已经优化,可以在代理和远程对象驻留在同一个应用程序域中时,防止不必要的性能损失。如果代理和远程对象不在同一个应用程序域中,则堆栈中的所有方法调用参数会被转换为消息并被传输到远程应用程序域,这些消息将在该远程应用程序域中被转换为原来的堆栈帧,同时该方法调用也会被调用。从方法调用中返回结果时也使用同一过程。