2010年8月24日
摘要: 最近在做一个EDI项目,主要流程就是客户以HttpPost或Webservice的方式向我们公司下订单,订单内容是以XML格式表示,我这边需要做的操作是:一: 验证请求是否合法(双方密钥)二: 验证请求内容是否正确且符合一定的格式要求三: 对订单进行处理 验证用户的请求是否合法以及对订单的处理就不说了,我今天主要说的是一种优雅、美观、清爽、干净的验证方式 对于XML的内容,我这边的处理方式是...
阅读全文
posted @ 2010-08-24 00:07 Funeral 阅读(1750) 评论(27)
编辑
2009年4月20日
现在很多程序员在面试的时候都遇到过这个问题---<猫叫了,老鼠跑了,主人醒了...>,实现一个连动效果,我也遇到过,感觉这道面试题目挺经典的,挺考验面向对象设计(OOD)的能力,虽然是个很简单的例子,但要考虑到程序的扩展性。比如说有新的需求,要求后面再加上狗叫了,那些写的过死且繁琐的代码就要来次大地震了;再比如说又变需求了,猫叫了是因为被跳蚤咬的,那跳蚤就成为了导火线,就算是用事件和接口写出的扩展性很强的程序,也会有点蔫了......
这么一连串的反应是由一个行为所引起的,或者是猫叫,亦或者是一个按钮的点击引发,如何能让这一连串反映的扩展性更强,能更坚强的面对新的需求。这就需要一个更佳的思路,更佳的设计模式,今天无意想起了这个问题,也根据我的思路写了一套模式,下面就详细的说下我的想法:
无论是猫叫,还是老鼠跑,都是一个行为,我们把这个行为抽象出一个基类:

Code
1 namespace NewCatAndMouse
2 {
3 public abstract class BaseObject
4 {
5 private string name;
6
7 public string Name
8 {
9 get { return name; }
10 set { name = value; }
11 }
12
13 /// <summary>
14 /// 抽象出的行为
15 /// </summary>
16 public abstract void Action();
17 }
18 }
现在我们再建一个中间层,用来处理这些行为:

Code
1 namespace NewCatAndMouse
2 {
3 public class ActionHandle
4 {
5 private BaseObject manager;
6
7 public ActionHandle(BaseObject manager,string name)
8 {
9 this.manager = manager;
10 this.manager.Name = name;
11 }
12
13 /// <summary>
14 /// 执行
15 /// </summary>
16 public void Execute()
17 {
18 this.manager.Action();
19 }
20 }
21 }
现在我们一一实现猫、老鼠和主人(从基类继承):
1 namespace NewCatAndMouse
2 {
3 public class Cat:BaseObject
4 {
5 public override void Action()
6 {
7 Console.Write(this.Name+"(猫)大吼一声!"+"\n");
8 }
9 }
10 }
1 namespace NewCatAndMouse
2 {
3 public class Mouse:BaseObject
4 {
5 public override void Action()
6 {
7 Console.Write(this.Name+"(老鼠)仓惶逃跑!"+"\n");
8 }
9 }
10 }
1 namespace NewCatAndMouse
2 {
3 public class Master:BaseObject
4 {
5 public override void Action()
6 {
7 Console.Write(this.Name+"(主人)猛然惊醒!" + "\n");
8 }
9 }
10 }
三个实现类完成了。现在一一实例化,组合调用?不,那样客户端会显的臃肿而丑陋,有人说:代码是门技术,更是门艺术。所以我们的客户端代码应当越简洁越好。所以,我们把需要的东西写在配置文件里:

Code
1 <?xml version="1.0" encoding="utf-8" ?>
2 <configuration>
3 <connectionStrings>
4 <add name="AssemblyName" connectionString="NewCatAndMouse"/>
5 </connectionStrings>
6 <appSettings>
7 <add key="Cat" value="Tom"/>
8 <add key="Mouse" value="Jerry"/>
9 <add key="Master" value="Bob"/>
10 </appSettings>
11 </configuration>
然后我们再做一个类来处理配置文件:

Code
1 namespace NewCatAndMouse
2 {
3
4 public class SubjectAggregate
5 {
6 private static List<string> list = new List<string>();
7 /// <summary>
8 /// 将配置文件里的所有键读入集合,并返回
9 /// </summary>
10 public static List<string> GetAllObject()
11 {
12 foreach(string key in ConfigurationManager.AppSettings.AllKeys)
13 {
14 list.Add(key);
15 }
16
17 if (list.Count < 1)
18 {
19 return null;
20 }
21 else
22 {
23 return list;
24 }
25 }
26
27 }
28 }
刚才说为了客户端的干净整洁,不要把过多的实例化放在客户端,所以我们就用反射来实例化类:

Code
1 namespace NewCatAndMouse
2 {
3 public class ReflectionObject
4 {
5
6 private static string assemblyName = System.Configuration.ConfigurationManager.ConnectionStrings["AssemblyName"].ConnectionString;
7
8 /// <summary>
9 /// 通过反射返回指定的类的实例
10 /// </summary>
11 /// <param name="key"></param>
12 /// <returns></returns>
13 public static BaseObject GetObject(string className)
14 {
15 return (BaseObject)Assembly.Load(assemblyName).CreateInstance(assemblyName+"."+className);
16 }
17 }
18 }
下面就是客户端代码了:

Code
1 namespace NewCatAndMouse
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
8 List<string> list = SubjectAggregate.GetAllObject();
9 if (list != null)
10 {
11 for (int i = 0; i < list.Count; i++)
12 {
13 ActionHandle handle = new ActionHandle(ReflectionObject.GetObject(list[i]),System.Configuration.ConfigurationManager.AppSettings[list[i]].ToString());
14 handle.Execute();
15 }
16 }
17 else
18 {
19 Console.Write("Not fount object!");
20 }
21 22 Console.Read();
23 }
24 }
25 }
这样就可以了,如果需要新的子类直接继承基类,再在配置文件添加一个子类属性就可以了。而且可以再配置文件里自由的组合而无需改动客户端的代码,符合了开放--封闭原则。
但由于用了反射,所以性能会有些差。而且如果实现类需要有新功能,就得在基类添加,如果功能太多基类就会变的臃肿不堪。所以,它也是有局限性的,最好是派生类不多而且行为较为统一。
可能有人会说:那么简单的代码也好意思发上来。我想说:功能总能实现,就看怎样实现。这只是一个思路,由于更多的人把自己总结的不错的设计思路分享出来,所以我们才能进步。
最近看设计模式有些上瘾,所以手痒也来凑凑热闹,但毕竟学程序的时间太短,经验太浅,所以可能有很多问题。希望大家帮我指正,希望能和大家一起努力,共同进步。
附:让板砖来的更激烈些吧!
posted @ 2009-04-20 17:25 Funeral 阅读(2409) 评论(50)
编辑
2009年3月20日
记得<倚天屠龙记>中有这样一段情节:张三丰向张无忌传授一套太极剑法,一路剑法使完,竟无一人喝彩,各人尽皆诧异:"这等慢吞吞、软绵绵的剑法,如何用来对敌过招"。还以为是张真人有意放慢了招数,好让张无忌瞧个明白。只听张三丰问道:“孩儿,你瞧明白了没有”,无忌答道:“看清楚了”。张三丰道:“都记得了没有?”,张无忌答道:“已忘记了一小半”。张三丰道:“好,那也难为你了。你自己去想想吧 。”张无忌低头默想。过了一会,张三丰问道:“现下怎样了?”张无忌道:“已忘了一大半了。"周颠等人皆急:“刚学的剑法都忘了一大半,这可如何迎敌”。便请张三丰重新传授一遍,张三丰微笑再使出一路相同的剑法,张无忌沉思一会,睁开眼:“我已忘的干干净净”。众人皆惊唯张三丰独喜,随即张无忌拿剑迎敌,大胜。
金庸这笔用意之深,使得透露出一个真理:忘记。张无忌学太极剑,不记招式,只是细看剑招中“神在剑先,绵绵不绝”之意。看完一路剑法,已忘记了一小半。低头默想之后,已忘记了一大半`。再看张三丰演练一遍,再经沉思玩味,终于忘得干干净净。当全部忘记之时,也是学成之时,缍以之力克强敌。由记得转化为有如本能一般,终能不受原来招式所限,随意出招自成章法。
让我想到现代背誉为中国IT商业领头羊、企业家的楷模的马云先生的一段语录:“三年以前我送一个同事去读MBA,我跟他说,如果毕业以后你忘了所学的东西,那你已经毕业了。如果你天天还想着所学的东西,那你就还没有毕业。学习MBA的知识,但要跳出MBA的局限。”
忘记其形,悟得其意,乃至返璞归真,神乎其技。
真正做到这种忘记何其难!需要你有着聪慧的头脑和超于常人的思维方式,跳出思维的局限和思想的束缚,从而达到另一个完全不同的境界。很多人十分用功,拼命强记,结果真的是“心有拘囿”,大受原来学说文字的拘束,真意反而完全错过,越是努力,所受缚束越深,令人深感可惜。
佛教禅宗有句佛偈:“看山是山,看水是水,是为第一境界;看山不是山,看水不是水,方为第二境界;看山还是山,看水还是水,才为最高境界”,跟无忌学剑有着异曲同工之妙。
张无忌是武侠小说中的人物,是虚拟出来的。普通人没有他那么变态的悟性,但无论是学武还是学文,其本质和境界都有着潜在的相似点,都要经历一个从简到繁,再从繁到简的过程。无论是哲学、文学还是科学,或是其他种种学科,我们刚入门、了解到一些皮毛的时候,或多或少的都会有一种“不过如此”、“原来这么简单”的浮躁心理,只是因为了解的太肤浅,是“看山是山,看水是水”的境界。当我们接触时间长了,遇到无数个问题和挫折的时候,开始逐渐了解到它的深意,就不再有刚开始的心态,而开始小心谨慎,好学善思,这时就是进入了“看山不是山,看水不是水”的境界,我们开始分析山为什么是山?水为什么是水?它们是由什么组成的?为何展现出这种不同的颜色和形态?第二境界是一个带着无数疑问,深入分析思考的过程。
当我们在第二境界停留的够久,对一种学科了解的足够深的时候,多年的量变积累引起了质变,完成了一个质的飞跃,我们就达到了“看山还是山,看水还是水”的最高境界。到了这个境界,我们就不会去考虑山为什么是山、水为什么是水了,因为已经能从一个更高层次的角度上来看待它们,甚至创造它们。
但,第三境界,却不是那么容易能达到的。我们大多数人,都停留在第二境界中苦苦的追寻,再寻觅的路途上迷失方向,或是经受不住挫折打击而停止前行。第二境界是一个迷宫,是一片布满了谜团和危险的原始森林,是一条蜿蜒崎岖、荆棘密布的道路,有着无数的分岔口,很多人穷尽一生也无法寻得正确的道路,在沐浴着真理的阳光的梦境中化为茫茫的白雾。也有人误以为成功的走了出来,拿到了真理的王冠,但公正的天平总会称量出赝品。
正如马云所说:“今天很残酷,明天更残酷,后天很美好。但大多数人死在了明天晚上”。今天,明天,后天,比作这三个境界也是恰如其分。
人类求知和探索的步伐从未停止过,翻开历史的书页,上面总会记载着人类中那凤毛麟角的几个。在秋水边逍遥游的庄子,在寂静夜空下沉思的苏格拉底.....等等(PS:为什么都是哲学家,难道就像修仙小说里说的那样,有无数个门派,但总只有那么一两个才是真正能得道成仙、修成正果的。或许也正是哲学的思想就是关于“天地人”的思考),无论怎么说,既然人活一世,就脱离不了这身皮囊,达到精神上的真正超脱和自由。哲学家也有饿肚子的时候,所以我并不是认为只有研究哲学才能达到最高境界。法国有句谚语:“人类一思考,上帝就发笑。”上帝给第二境界的人们布下了太多的陷阱与迷雾,所以他认为人类是永远走不出来的。所以当人们思考如何达到真正的最高境界时,上帝就象猎人看着猎物一样嘲笑它们的愚蠢,但终有一天,人类的思想超越了这个境界,那时估计上帝就笑不出来了。我并不赞同这句话,因为我认为它扼杀了人们的创造力,上帝只是一个代名词,代表着创造一切的伟大力量,但我坚信人类终会拥有这个力量(扯远了,扯远了......)
言归正传,我们大多数人都在第二阶段苦苦追寻,所以需要多研究一下前人的足迹,前人的经验和智慧,会对我们思想的道路提供很多正确的指引。让我们学会闭上双眼,去感受真理的方向,忘记那些路途上的障碍......只有真正学会了忘记,境界才能真正的升华。
有人给程序员也分了几种境界,分别是:
第一阶段
此阶段主要是能熟练地使用某种语言。这就相当于练武中的套路和架式这些表面的东西。
第二阶段
此阶段能精通基于某种平台的接口(例如我们现在常用的Win 32的API函数)以及所对应语言的自身的库函数。到达这个阶段后,也就相当于可以进行真实散打对练了,可以真正地在实践中做些应用。
第三阶段
此阶段能深入地了解某个平台系统的底层,已经具有了初级的内功的能力,也就是“手中有剑,心中无剑”。
第四阶段
此阶段能直接在平台上进行比较深层次的开发。基本上,能达到这个层次就可以说是进入了高层次。这时进入了高级内功的修炼。比如能进行VxD或操作系统的内核的修改。这时已经不再有语言的束缚,语言只是一种工具,即使要用自己不会的语言进行开发,也只是简单地熟悉一下,就手到擒来,完全不
像是第一阶段的时候学习语言的那种情况。一般来说,从第三阶段过渡到第四阶段是比较困难的。为什么会难呢?这就是因为很多人的思想转变不过来。
第五阶段
此阶段就已经不再局限于简单的技术上的问题了,而是能从全局上把握和设计一个比较大的系统体系结构,从内核到外层界面。可以说是“手中无剑,心中有剑”。到了这个阶段以后,能对市面上的任何软件进行剖析,并能按自己的要求进行设计,就算是MS Word这样的大型软件,只要有充足的时间,也一定会设计出来。
第六阶段
此阶段也是最高的境界,达到“无招胜有招”。这时候,任何问题就纯粹变成了一个思路的问题,不是用什么代码就能表示的。也就是“手中无剑,心中也无剑”。
哎,自我分析一下,我这个初出江湖的小菜鸟才刚达到第一境界,在程序这条道路上还有很长的路途要走,只能依仗着各位程序员前辈的指引和时刻提醒自己不要误入歧途了。啥时候能达到忘记代码、“手中无剑,心中也无剑”的境界呢,估计忘记代码很容易,但形成一种程序的思维就困难的多了(^-^)。
附:刚才没有排版,很乱很丑影响阅读,对不住各位大大了
posted @ 2009-03-20 12:13 Funeral 阅读(2735) 评论(40)
编辑
2009年3月16日
编程中经常会用到XML,.Net FrameWork提供了专门对XML进行处理的DLL,里面提供了很多对XML处理的方法,在这里简单介绍一下XPath的使用方法.
XPath 使用路径表达式来选取 XML 文档中的节点或者节点集.类似于用正则表达式对文本进行目的性匹配.
首先我们写一个普通的XML文档
<?xml version="1.0" encoding="utf-8" ?>
<school>
<class>
<number>1</number>
<teacher property="English">Mr Sun</teacher>
<student_count>50</student_count>
</class>
<class>
<number>2</number>
<teacher property="Chinese">Mrs Li</teacher>
<student_count>35</student_count>
</class>
<class>
<number>3</number>
<teacher property="Math">Mr Zhang</teacher>
<student_count>20</student_count>
</class>
</school>
XPath基本用法
| 表达式 |
描述 |
| nodename |
选取此节点的所有子节点 |
| / |
从根节点选取 |
| // |
从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
| . |
选取当前节点 |
| .. |
选取当前节点的父节点 |
| @ |
选取属性 |
实例
在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:
| 路径表达式 |
结果 |
| school |
选取 school元素的所有子节点 |
| /school |
选取根元素 school
注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
|
| school/class |
选取所有属于 school的子元素的 class元素。 |
| //class |
选取所有 book 子元素,而不管它们在文档中的位置。 |
| school//book |
选择所有属于 school元素的后代的 class元素,而不管它们位于 school之下的什么位置。 |
| //@property |
选取所有名为 property的属性。 |
我们做一个控制台应用程序,来用XPath操作这个XML:
namespace XPathTest
{
class Program
{
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();//创建一个XMLDocument对象
doc.Load("..\\TestXML.xml");//根据XML文件的路径加载XML文件
}
}
}
好了,现在我们需要得到number为1的班级里的所有信息:
XmlNodeList list=doc.SelectNodes("//class[number=1]"); //获得XML里子节点number为1的节点class
Console.Write(list[0]["number"].Name+":"+list[0]["number"].InnerText+"\n");
Console.Write(list[0]["teacher"].Name+":"+list[0]["teacher"].InnerText+"\n");
Console.Write(list[0]["student_count"].Name+":"+list[0]["student_count"].InnerText+"\n");
Console.Read();
显示的结果为:
number:1
teacher:Mr Sun
student_count:50
可能会有朋友说道:我也没看到哪里简单啊,我还不如用While(XmlReader.Read())呢.别急,XPath的优势还没体现出来
现在我们又变需求了,我们要找语文老师班上的学生人数,也就是property为Chinese的teacher的class的student_count(有点绕
):
XmlNodeList list = doc.SelectNodes("//class[teacher[@property='English']]");//匹配teacher节点里property为English的class
Console.Write(list[0]["student_count"].Name + ":" + list[0]["student_count"].InnerText);
Console.Read();
显示的结果:
student_count:35
我们又需要找班级人数不大与40的所有班级信息:
XmlNodeList list=doc.SelectNodes("//class[student_count<40]");//匹配student_count小于40的class
for(int i=0;i<list.Count;i++)
{
Console.Write("匹配的第"+i+"个节点信息");
Console.Write(list[i]["number"].Name+":"+list[i]["number"].InnerText+"\n");
Console.Write(list[i]["teacher"].Name+":"+list[i]["teacher"].InnerText+"\n");
Console.Write(list[i]["student_count"].Name+":"+list[i]["student_count"].InnerText+"\n");
Console.Read();
}
显示的结果:
匹配的第1个节点信息:
number:2
teacher:Mrs Li
student_count:35
匹配的第2个节点信息:
number:3
teacher:Mr Zhang
student_count:35
是不是很简单
,这就是XPath的优势:不需要一次次的遍历,只需用一句表达式就能得到想要的结果
还有一些XPath的基本语法:
实例
在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:(谓语是在方括号里的匹配条件)
| 路径表达式 |
结果 |
| /school/class[1] |
选取属于 school子元素的第一个 class元素。 |
| /school/class[last()] |
选取属于 school子元素的最后一个 class元素。 |
| /school/class[last()-1] |
选取属于 school子元素的倒数第二个 class元素。 |
| /school/class[position()<3] |
选取最前面的两个属于 school元素的子元素的 class元素。 |
| //teacher[@property] |
选取所有拥有名为 property的属性的 teacher元素。 |
| //teacher[@property='English'] |
选取所有 teacher元素,且这些元素拥有值为 English 的 property属性。 |
| /school/class[student_count>35.00] |
选取所有 school元素的 class元素,且其中的 student_count元素的值须大于 35.00。 |
| /school/class[student_count>35.00]/title |
选取所有 school元素中的 class元素的 teacher 元素,且其中的 student_count元素的值须大于 35.00。 |
选取未知节点
XPath 通配符可用来选取未知的 XML 元素。
| 通配符 |
描述 |
| * |
匹配任何元素节点 |
| @* |
匹配任何属性节点 |
| node() |
匹配任何类型的节点 |
实例
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
| 路径表达式 |
结果 |
| /school/* |
选取 school元素的所有子节点 |
| //* |
选取文档中的所有元素 |
| //property[@*] |
选取所有带有属性的 property元素。 |
选取若干路径
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。
实例
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
| 路径表达式 |
结果 |
| //class/teacher | //class/number |
选取所有 class 元素的 teacher 和 number 元素。 |
| //teacher | //number |
选取所有文档中 |
| /school/class/teacher | //number |
选取所有属于 school元素的 class元素的 teacher元素,以及文档中所有的 number元素。 |
XPath还有多个内置函数,分别是对字符串,值,日期等的处理和比较.这里就不一一说明了,XPath的魅力还不止如此
.本人是初学者,希望能和大家一起努力
posted @ 2009-03-16 13:08 Funeral 阅读(558) 评论(1)
编辑
2009年3月9日
关于TCP通道的Remoting的基本使用方法:
一:首先导入命名空间System.Runtime.Remoting,然后
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
建一个简单的测试接口和它的实现类
namespace RemotingTest
{
public interface ISubject
{
string Say(string name);
}
public class Subject:MarshalByRefObject,ISubject
{
public string Say(string name)
{
return "Hi,"+name;
}
}
}
//因为Remoting传递对象是以引用的方式,所以所传递的远程对象类必须继承 MarshalByRefObject
建一个WinForm窗体作为服务器端,拖一个Button,在Button的点击事件里写上:
class ServerFrm
{
private void Server_Click(object sender,EventArgs e)
{
//监听端口8001
TcpChannel channel = new TcpChannel(8001);
channel.ChannelName="TestChannel";
//注册这个TCP协议通道
ChannelServices.RegisterChannel(channel,false);
//在TCP协议通道里将Subject注册为已知类型,传递一段叫“SayHi”的Uri
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Subject),"SayHi",WellKnownObjectMode.SignleCall);
MessageBox.Show("服务器开始监听");
}
}
现在开始做客户端进行测试,先建一个接口ISubject
namespace RemotingTest
{
public interface ISubject
{
string Say(string name);
}
}
(注意,命名空间和接口名要和服务器端的完全相同)
同样建一个WinForm窗体,拖一个Button,在Button的点击事件里写上:
class ClientFrm
{
private void Client_Click(object sender,EventArgs e)
{
string name = "Bob";
//同样注册一个和服务器端通信的通道
ChannelServices.RegisterChannel(new TcpChannel());
//通过Activator.GetObject方法获得远程Remoting对象,这里的Url为本地8001端口的SayHi(Uri)
RemotingTest.ISubject sub = (RemotingTest.ISubject)Activator.GetObject(typeof(RemotingTest.ISubject),"tcp://localhost:8001/SayHi");
MessageBox.Show(sub.Say(name));
}
}
二:在Remoting中的远程对象中,如果还要调用或传递某个对象,例如实体类,或者结构,则该实体类或结构则必须实现可序列化Attribute[SerializableAttribute],比如:
[Serializable]
public class UserInfo
{
public UerInfo()
{
}
private string name;
private string sex;
private int age;
public string Name
{
get {return name;}
set {name = value;}
}
public string Sex
{
get {return sex;}
set {sex = value;}
}
public int Age
{
get {return age;}
set {age = value;}
}
}
将该远程对象以类库的方式编译成Dll,这个Dll将分别放在服务器端和客户端,以添加引用
三:注销通道
如果要关闭Remoting的服务,则需要注销通道,也可以关闭对通道的监听。在Remoting中当我们注册通道的时候,就自动开启了通道的监听。而如果关闭了对通道的监听,则该通道就无法接受客户端的请求,但通道仍然存在,如果你想再一次注册该通道,会抛出异常。
//获得当前已注册的通道
IChannel[] channels = ChannelServices.RegisteredChannels;
foreach(IChannel channel in channels)
{
//关闭名称为TestChannel的通道
if(channel.ChannelName == "TestChannel")
{
TcpChannel tcp = (TcpChannel)channel;
//关闭监听
tcp.StopListening(null);
//注销通道
ChannelServices.UnregisterChannel(tcp);
}
}
还有一种方法,相对上面这个较为复杂一点,但会大大简化服务器端和客户端的代码,因为要把需要的信息写在XML文件里。
按照上面的测试接口和类方法不变,用另一种方法实现Remoting的通信:
一:在服务器端建一个应用程序配置文件App.config,添加内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="tcp" port="8001">
</channel>
</channels>
<service>
<wellknown type="RemotingTest.Subject,Server" objectUri="Subject.rem" mode="SingleCall"/>
</service>
</application>
<customErrors mode="Off" />
</system.runtime.remoting>
</configuration>
其中channel节点指定了通信通道的类型和端口号,wellkonwn节点指定了type类型的格式:(命名空间.类,程序集名称)。
然后我们在服务器端的按钮点击事件里写上:
private void Server_Click(object sender,EventArgs e)
{
using(System.Runtime.Remoting.RemotingConfiguration.Configur(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,false))
{
MessageBox.Show("服务器开始监听");
}
}
就这样一句代码,无论在XML里增加多少个wellknown节点,都能一次性读取出来
我们在客户端也建一个App.config,添上这样几句:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Subject" value="tcp://localhost:8001/Subject.rem"/>
</appSettings>
</configuration>
然后在客户端的按钮点击事件里写上:
private void Client_Click(object sender,EventArg e)
{
RemotingTest.ISubject sub = (RemotingTest.ISubject)Activator.GetObject(typeof(RemotingTest.ISubject),System.Configuration.ConfigurationManager.AppSettings.Get("Subject"));
Message.show(sub.Say("Bob"));
}
OK,大功告成。
Http通道和Tcp通道的大体没什么区别,这里就不多做介绍了。本人也是Remoting的初学者,希望能和大家共同学习,共同进步!
posted @ 2009-03-09 17:45 Funeral 阅读(252) 评论(0)
编辑