2007年11月09日

静态构造函数自动被调用,不能被显式调用。虽然提供了许多约束条件,但是静态构造函数执行的确切时间和顺序是不确定的:
一个类的静态构造函数在这个类的任何实例被创建前执行。
一个类的静态构造函数在类的任何静态成员被引用前执行。
一个类的静态构造函数在它的所有派生类的静态构造函数执行之后执行。
一个类的静态构造函数从不会被执行一次以上。

2007年03月28日

对象数组转换成ArrayList可以使用ArrayList.Adapter方法:
Person[] personArray =
 myPerson.GetPersons();
ArrayList personList =
 ArrayList.Adapter(personArray)

把一个ArrayList转换成对象数组可以使用ArrayList.ToArray方法
Person[] personArrayFromList = (Person[])personList.ToArray(typeof
(Person));

2007年03月23日

so…thatsuch…that的意思均为"如此……以致……",都用来引导结果状语从句。但二者用法不尽相同,现归纳如下:

  1.so…that结构中的so为副词,后面跟形容词或副词;such…that中的such为形容词,后面接名词(名词前可以有形容词或副词修饰)。例如:

  He became so angry that he couldn’t speak.他变得很生气,以致说不出话来。

  It was such a fine day that we went out for a walk.那是一个很晴朗的日子,我们出去散步。

  2.that前的名词有表示数量多少的many,much,few,little等修饰时,只能用so,不能用such。例如:

  There was so much noise outside that we couldn’t hear the teacher.外面嘈杂声很大,以致我们不能听到老师的话。

  He had so many falls that he was black and blue all over.他跌了这么多的跤,以致全身青一块、紫一块的。

  注意:若名词前的little解释为"()"意思时,则仍用such,而不能用so例如:

  It is such a little sheep that it can’t run fast.它是一只小绵羊,它不能够跑得快。

  3.that前是单数可数名词且该名词前面有形容词修饰时,sosuch可以互换,

  即:soadj.a/ann.sucha/anadj.n.。例如:

  She is so good a teacher that we all love her.She is such a good teacher that we all love her.她是一位好老师,我们都爱她。

  4.that前是不可数名词或复数可数名词时,则必须用such,不能用so来代替。例如:It was such fine weather that they all went swimming.那是个好天气,他们都去游泳了。

  They are such nice apples that we would like to eat them.它们是如此好的苹果,以致我们想吃它们。

  【巩固练习】根据句意,用sosuch填空。

  1.The boy is_____________ young that he can’t go to school.

  2.He told us_____________ a funny story that we all laughed.

  3.He has______________ few books to read that he has to borrow some books from the library.

  4.It is ___________a tall building that I can’t see its top.

  5.The girls had_____________ high a fever that she nearly died last week.

  6.They are ___________clever children that all the teachers love them.

  7.It is ___________ delicious orange juice that we all would love to drink it.

  8.It is _____________a little dog that Lucy likes it very much.

  9.There is ____________little water that it is not enough for ___________many people.

  Key1.so 2.such 3.so 4.such 5.so 6.such 7.such 8.such 9.so,so

2007年03月20日
Asp.net(C#)常用函数表
2007-03-11 18:35
1、DateTime 数字型
System.DateTime currentTime=new System.DateTime();
1.1 取当前年月日时分秒
currentTime=System.DateTime.Now;
1.2 取当前年
int 年=currentTime.Year;
1.3 取当前月
int 月=currentTime.Month;
1.4 取当前日
int 日=currentTime.Day;
1.5 取当前时
int 时=currentTime.Hour;
1.6 取当前分
int 分=currentTime.Minute;
1.7 取当前秒
int 秒=currentTime.Second;
1.8 取当前毫秒
int 毫秒=currentTime.Millisecond;
(变量可用中文)2、Int32.Parse(变量) Int32.Parse("常量")
字符型转换 转为32位数字型
1.9 取中文日期显示——年月日时分
string strY=currentTime.ToString("f"); //不显示秒
1.10 取中文日期显示_年月
string strYM=currentTime.ToString("y");
1.11 取中文日期显示_月日
string strMD=currentTime.ToString("m");
1.12 取当前年月日,格式为:2003-9-23
string strYMD=currentTime.ToString("d");
1.13 取当前时分,格式为:14:24
string strT=currentTime.ToString("t");

3、 变量.ToString()
字符型转换 转为字符串
12345.ToString("n"); //生成 12,345.00
12345.ToString("C"); //生成 ¥12,345.00
12345.ToString("e"); //生成 1.234500e+004
12345.ToString("f4"); //生成 12345.0000
12345.ToString("x"); //生成 3039 (16进制)
12345.ToString("p"); //生成 1,234,500.00%

4、变量.Length 数字型
取字串长度:
如: string str="中国";
int Len = str.Length ; //Len是自定义变量, str是求测的字串的变量名

5、System.Text.Encoding.Default.GetBytes(变量)
字码转换 转为比特码
如:byte[] bytStr = System.Text.Encoding.Default.GetBytes(str);
然后可得到比特长度:
len = bytStr.Length;

6、System.Text.StringBuilder("")
字符串相加,(+号是不是也一样?)
如:System.Text.StringBuilder sb = new System.Text.StringBuilder("");
sb.Append("中华");
sb.Append("人民");
sb.Append("共和国");

7、变量.Substring(参数1,参数2);
有点类似vb里的Left,right,Mid函数。
截取字串的一部分,参数1为左起始位数,参数2为截取几位。
如:string s1 = str.Substring(0,2);
参数2可以缺省,表示从参数1开始取到字符串末尾。如:
String a = "abc";
a.substring(1)
就是"bc"。

8、String user_IP=Request.ServerVariables["REMOTE_ADDR"].ToString();
取远程用户IP地址

9、穿过代理服务器取远程用户真实IP地址:
if(Request.ServerVariables["HTTP_VIA"]!=null){
string user_IP=Request.ServerVariables["HTTP_X_FORWARDED_FOR"].ToString();
}else{
string user_IP=Request.ServerVariables["REMOTE_ADDR"].ToString();
}

10、 Session["变量"];
存取Session值;
如,赋值: Session["username"]="小布什";

取值: Object objName=Session["username"];
String strName=objName.ToString();
清空: Session.RemoveAll();

11、String str=Request.QueryString["变量"];
用超链接传送变量。
如在任一页中建超链接:<a href=Edit.aspx?fbid=23>点击</a>
在Edit.aspx页中取值:String str=Request.QueryString["fdid"];

12、DOC对象.CreateElement("新建节点名");
创建XML文档新节点

13、父节点.AppendChild(子节点);
将新建的子节点加到XML文档父节点下

14、 父节点.RemoveChild(节点);
删除节点

15、Response
Response.Write("字串");
Response.Write(变量);
向页面输出。

Response.Redirect("URL地址");
跳转到URL指定的页面

16、char.IsWhiteSpce(字串变量,位数)——逻辑型
查指定位置是否空字符;
如:
string str="中国 人民";
Response.Write(char.IsWhiteSpace(str,2)); //结果为:True, 第一个字符是0位,2是第三个字符。

17、char.IsPunctuation(‘字符’) –逻辑型
查字符是否是标点符号
如:Response.Write(char.IsPunctuation(‘A’)); //返回:False

18、(int)’字符’
把字符转为数字,查代码点,注意是单引号。
如:
Response.Write((int)’中’); //结果为中字的代码:20013

19、(char)代码
把数字转为字符,查代码代表的字符。
如:
Response.Write((char)22269); //返回"国"字。

20、 Trim()
清除字串前后空格

21 、字串变量.Replace("子字串","替换为")
字串替换
如:
string str="中国";
str=str.Replace("国","央"); //将国字换为央字
Response.Write(str); //输出结果为"中央"

再如:(这个非常实用)

string str="这是<script>脚本";
str=str.Replace("<","<font><</font>"); //将左尖括号替换为 <font> 与 < 与 </font> (或换为<,但估计经XML存诸后,再提出仍会还原)
Response.Write(str); //显示为:"这是<script>脚本"

如果不替换,<script>将不显示,如果是一段脚本,将运行;而替换后,脚本将不运行。
这段代码的价值在于:你可以让一个文本中的所有HTML标签失效,全部显示出来,保护你的具有交互性的站点。
具体实现:将你的表单提交按钮脚本加上下面代码:
string strSubmit=label1.Text; //label1是你让用户提交数据的控件ID。
strSubmit=strSubmit.Replace("<","<font><</font>");
然后保存或输出strSubmit。
用此方法还可以简单实现UBB代码。

22、Math.Max(i,j)
取i与j中的最大值
如 int x=Math.Max(5,10); // x将取值 10

23、字串对比一般都用: if(str1==str2){ } , 但还有别的方法:

(1)、
string str1; str2
//语法: str1.EndsWith(str2); __检测字串str1是否以字串str2结尾,返回布尔值.如:
if(str1.EndsWith(str2)){ Response.Write("字串str1是以"+str2+"结束的"); }

(2)、
//语法:str1.Equals(str2); __检测字串str1是否与字串str2相等,返回布尔值,用法同上.

(3)、
//语法 Equals(str1,str2); __检测字串str1是否与字串str2相等,返回布尔值,用法同上.

24、IndexOf() 、LastIndexOf()
查找字串中指定字符或字串首次(最后一次)出现的位置,返回索引值,如:
str1.IndexOf("字"); //查找"字"在str1中的索引值(位置)
str1.IndexOf("字串");//查找"字串"的第一个字符在str1中的索引值(位置)
str1.IndexOf("字串",3,2);//从str1第4个字符起,查找2个字符,查找"字串"的第一个字符在str1中的索引值(位置)

25、Insert()
在字串中指定索引位插入指定字符。如:
str1.Insert(1,"字");在str1的第二个字符处插入"字",如果str1="中国",插入后为"中字国";

26、PadLeft()、PadRight()
在字串左(或右)加空格或指定char字符,使字串达到指定长度,如:
<%
string str1="中国人";
str1=str1.PadLeft(10,’1′); //无第二参数为加空格
Response.Write(str1); //结果为"1111111中国人" , 字串长为10
%>

27、Remove()
从指定位置开始删除指定数的字符
字串对比一般都用: if(str1==str2){ } , 但还有别的方法:

1、
string str1; str2
//语法: str1.EndsWith(str2); __检测字串str1是否以字串str2结尾,返回布尔值.如:
if(str1.EndsWith(str2)){ Response.Write("字串str1是以"+str2+"结束的"); }

2、
//语法:str1.Equals(str2); __检测字串str1是否与字串str2相等,返回布尔值,用法同上.

3、
//语法 Equals(str1,str2); __检测字串str1是否与字串str2相等,返回布尔值,用法同上.

IndexOf()
查找字串中指定字符或字串首次出现的位置,返首索引值,如:
str1.IndexOf("字"); //查找"字"在str1中的索引值(位置)
str1.IndexOf("字串");//查找"字串"的第一个字符在str1中的索引值(位置)
str1.IndexOf("字串",3,2);//从str1第4个字符起,查找2个字符,查找"字串"的第一个字符在str1中的索引值(位置)

==============Asp.net(C#)常用函数表 ======================
Abs(number)   取得数值的绝对值。
Asc(String)   取得字符串表达式的第一个字符ASCII   码。
Atn(number)   取得一个角度的反正切值。
CallByName (object, procname, usecalltype,[args()])   执行一个对象的方法、设定或传回对象的属性。
CBool(expression)   转换表达式为Boolean   型态。
CByte(expression)   转换表达式为Byte   型态。
CChar(expression)   转换表达式为字符型态。
CDate(expression)   转换表达式为Date   型态。
CDbl(expression)   转换表达式为Double   型态。
CDec(expression)   转换表达式为Decimal   型态。
CInt(expression)   转换表达式为Integer   型态。
CLng(expression)   转换表达式为Long   型态。

CObj(expression)   转换表达式为Object   型态。
CShort(expression)   转换表达式为Short   型态。
CSng(expression)   转换表达式为Single   型态。
CStr(expression)   转换表达式为String   型态。
Choose (index, choice-1[, choice-2, ... [, choice-n]])   以索引值来选择并传回所设定的参数。
Chr(charcode)   以ASCII   码来取得字符内容。
Close(filenumberlist)   结束使用Open   开启的档案。
Cos(number)   取得一个角度的余弦值。
Ctype(expression, typename)   转换表达式的型态。
DateAdd(dateinterval, number, datetime)   对日期或时间作加减。
DateDiff(dateinterval, date1, date2)   计算两个日期或时间间的差值。
DatePart (dateinterval, date)   依接收的日期或时间参数传回年、月、日或时间。
DateSerial(year, month, day)   将接收的参数合并为一个只有日期的Date   型态的数据。
DateValue(datetime)   取得符合国别设定样式的日期值,并包含时间。

Day(datetime)   依接收的日期参数传回日。
Eof(filenumber)   当抵达一个被开启的档案结尾时会传回True 。
Exp(number)   依接收的参数传回e   的次方值。
FileDateTime(pathname)   传回档案建立时的日期、时间。
FileLen(pathname)   传回档案的长度,单位是Byte 。
Filter(sourcearray, match[, include[, compare]])   搜寻字符串数组中的指定字符串,凡是数组元素中含有指定字符串,会将它们结合成新的字符串数组并传回。若是要传回不含指定字符串的数组元素,则include   参数设为False 。compare   参数则是设定搜寻时是否区分大小写,此时只要给TextCompare   常数或1   即可。
Fix(number)   去掉参数的小数部分并传回。
Format(expression[, style[, firstdayofweek[, firstweekofyear]]])   将日期、时间和数值资料转为每个国家都可以接受的格式。
FormatCurrency(expression[,numdigitsafterdecimal [,includeleadingdigit]])   将数值输出为金额型态。
numdigitsafterdecimal   参数为小数字数,includeleadingdigit   参数为当整数为0   时是否补至整数字数。

FormatDateTime(date[,namedformat])   传回格式化的日期或时间数据。
FormatNumber(expression[,numdigitsafterdecimal [,includeleadingdigit]])   传回格式化
的数值数据。Numdigitsafterdecimal   参数为小数字数,includeleadingdigit   参数为当整数为0   时是否补至整数字数。
FormatPercent(expression[,numdigitsafterdecimal [,includeleadingdigit]])   传回转换为百分比格式的数值数据。numdigitsafterdecimal   参数为小数字数,includeleadingdigit   参数为当整数为0   时是否补至整数字数。
GetAttr(2005620163726.htm)   传回档案或目录的属性值。
Hex(number)   将数值参数转换为16   进制值。
Hour(time)   传回时间的小时字段,型态是Integer 。
Iif(expression, truepart, falsepart)   当表达式的传回值为True   时执行truepart   字段的程序,反之则执行falsepart   字段。
InStr([start, ]string1, string2)   搜寻string2   参数设定的字符出现在字符串的第几个字符,start   为由第几个字符开始寻找,string1   为欲搜寻的字符串,string2   为欲搜寻的字符。
Int(number)   传回小于或等于接收参数的最大整数值。
IsArray(varname)   判断一个变量是否为数组型态,若为数组则传回True ,反之则为False 。

IsDate(expression)   判断表达式内容是否为DateTime   型态,若是则传回True ,反之则为False 。
IsDbNull(expression)   判断表达式内容是否为Null ,若是则传回True ,反之则为False 。
IsNumeric(expression)   判断表达式内容是否为数值型态,若是则传回True ,反之则为False 。
Join(sourcearray[, delimiter])   将字符串数组合并唯一个字符串,delimiter   参数是设定在各个元素间加入新的字符串。
Lcase(string)   将字符串转换为小写字体。
Left(string, length)   由字符串左边开始取得length   参数设定长度的字符。
Len(string)   取得字符串的长度。
Log(number)   取得数值的自然对数。
Ltrim(string)   去掉字符串的左边空白部分。
Mid(string, start[, length])   取出字符串中strat   参数设定的字符后length   长度的字符串,若length   参数没有设定,则取回start   以后全部的字符。
Minute(time)   取得时间内容的分部分,型态为Integer 。
MkDir(path)   建立一个新的目录。
Month(date)   取得日期的月部分,型态为Integer 。

MonthName(month)   依接收的月份数值取得该月份的完整写法。
Now()   取得目前的日期和时间。
Oct(number)   将数值参数转换为8   进制值。
Replace(expression, find, replace)   将字符串中find   参数指定的字符串转换为replace   参数指定的字符串。
Right(string,length)   由字符串右边开始取得length   参数设定长度的字符。
RmDir(path)   移除一个空的目录。
Rnd()   取得介于0   到1   之间的小数,如果每次都要取得不同的值,使用前需加上Randomize   叙述。
Rtrim(string)   去掉字符串的右边空白部分。
Second(time)   取得时间内容的秒部分,型态为Integer 。
Sign(number)   取得数值内容是正数或负数,正数传回1 ,负数传回-1 ,0   传回0 。
Sin(number)   取得一个角度的正弦值。
Space(number)   取得number   参数设定的空白字符串。

Split(expression[, delimiter])   以delimiter   参数设定的条件字符串来将字符串分割为字符串数组。
Sqrt(number)   取得一数值得平方根。
Str(number)   将数字转为字符串后传回。
StrReverse(expression)   取得字符串内容反转后的结果。
Tan(number)   取得某个角度的正切值。
TimeOfDay()   取得目前不包含日期的时间。
Timer()   取得由0:00   到目前时间的秒数,型态为Double 。
TimeSerial(hour, minute, second)   将接收的参数合并为一个只有时间Date   型态的数据。
TimaValue(time)   取得符合国别设定样式的时间值。
Today()   取得今天不包含时间的日期。
Trim(string)   去掉字符串开头和结尾的空白。
TypeName(varname)   取得变量或对象的型态。
Ubound(arrayname[, dimension])   取得数组的最终索引值,dimension   参数是指定取得第几维度的最终索引值。

Ucase(string)   将字符串转换为大写。
Val(string)   将代表数字的字符串转换为数值型态,若字符串中含有非数字的内容则会将其去除后,合并为一数字。
Weekday(date)   取的参数中的日期是一个星期的第几天,星期天为1 、星期一为2 、星期二为3   依此类推。
WeekDayName(number)   依接收的参数取得星期的名称,可接收的参数为1   到7 ,星期天为1 、星期一为2 、星期二为3   依此类推。

2007年02月06日

.test{
width:200px;
height:50px;
border:1px solid red;
padding:10px;
overflow:hidden;            /*不显示超过对象宽度的内容*/
text-overflow:ellipsis;    /*当对象内文本溢出时显示省略标记(…)*/
white-space:nowrap;    /*限制在一行内显示所有文本*/
}

另:禁止拷贝、复制、选择
<body leftmargin=0 topmargin=0  oncontextmenu=’return false’ ondragstart=’return false’ onselectstart =’return false’ onselect=’document.selection.empty()’ oncopy=’document.selection.empty()’ onbeforecopy=’return false’ onmouseup=’document.selection.empty()’>

2006年03月28日

开源分享:相当但丰富于DataTable/View数据王国的“BaiDu”超级搜索过滤控件(源码直接贴出来,欢迎转载)

***名称***
淘金筛控件(WebMIS.GoldFilter)源码分享

***用法***
Step1 将淘金筛控件拖至WinForm/WebForm,假如命名为GoldFilter1;
将网格控件拖至WinForm/WebForm,假如命名为DataGrid1;

Step2 在Form_Load/Page_Load事件中过程中,设置DataGrid1的数据源之后,只需指定如下一句一切OK:
GoldFilter1.DataSource = DataGrid1.DataSource

Step3 程序运行时,GoldFilter1自动在WinForm/WebForm中为字段列下拉框加载数据源的各列或指定的列。
为操作类型下拉框加载各种操作,包括各种比较操作如=、<>、>、>=、<、<=、列举多个相等过滤、
两者之间范围比较等及其它的丰富的操作如包含、左包含、右包含模糊匹配。针对常用且实用的
长度判断、空值与非空值过滤特别智能匹配比较等。

***功能特点***
简单快捷、易用实用

***功能描述***
对DataTable/View各列做各种智能匹配、比较操作、模糊匹配查询过滤。
相当但丰富于DataTable/View数据王国的“BaiDu”

***适用范围***
各个网站网页或软件的网格数据过滤,通用于Oracel、SQLServer、ADO.NET的查询过滤。



***操作***
1、智能匹配
字段列下拉框选择一项,操作类型下拉框不用选,直接在过滤输入中输入过滤的数字或文本或日期即可查找过滤。
如果你输入了通配符如%、*号,自动做模糊匹配查找过滤。

2、比较操作
字段列下拉框选择一项,操作类型下拉框选择比较操作,直接在过滤输入中输入过滤的数字或文本或日期即可查找

过滤。
比较操作有如下几种:
相等、不等、大于、大于或等于、小于、小于或等于、两者之间、列举多个(相等)


3、模糊匹配
字段列下拉框选择一项,操作类型下拉框选择包含操作,直接在过滤输入中输入包含的数字或文本或日期即可查找

过滤。
包含操作有如下几种:
包含,过滤所有在过滤输入中的文本中出现的数据
左边象,过滤所有以在过滤输入中的文本开头的数据
右边象,过滤所有以在过滤输入中的文本结尾的数据

ValueTextItem.cs、ValueTextItemCollection.cs两个文件写的类是用来表示加载DataTable/View或网格列。

using System;

namespace WebMIS.GoldFilter
{
/// <summary>
/// 描述键值对,为清晰可见不用KeyValue而用ValueText,均以字符串形式配对,表示值及它的显示文本。
/// </summary>
public class ValueTextItem
{
private string _Value;
private string _Text;

/// <summary>
/// 创建类的新实例
/// </summary>
public ValueTextItem(){}

/// <param name="text">文本值,也就是键名与键值相同</param>
public ValueTextItem(string text):this(text,text)
{

}

/// <param name="val">值,即键名</param>
/// <param name="text">值对应的文本,一般用于显示</param>
public ValueTextItem(string val,string text)
{
_Value = val;
_Text = text;
}

/// <summary>
/// 值,即键名
/// </summary>
public string Value
{
get
{
return _Value;
}
set
{
_Value = value;
}
}

/// <summary>
/// 值对应的文本,一般用于显示
/// </summary>
public string Text
{
get
{
return _Text;
}
set
{
_Text = value;
}
}

/// <summary>
/// 以“值 – 文本”格式返回文本。
/// </summary>
/// <returns></returns>
public override string ToString()
{
return this.Value + " – " + this.Text;
}

}//End Struct

}//End Namespace



using System;
using System.Collections;

namespace WebMIS.GoldFilter
{
/// <summary>
/// 键值对集合
/// </summary>
public class ValueTextItemCollection:CollectionBase
{
public ValueTextItemCollection()
{
//
// TODO: 在此处添加构造函数逻辑
//
}

/// <summary>
/// 将指定的键值对添加到集合的结尾处
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int Add(ValueTextItem item)
{
return this.InnerList.Add(item);
}

/// <summary>
/// 将指定的键值对添加到集合的结尾处
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int Add(string val,string text)
{
return this.InnerList.Add(new ValueTextItem(val,text));
}

/// <summary>
/// 获取指定位置的键值对
/// </summary>
public ValueTextItem this[int index]
{
get
{
return this.InnerList[index] as ValueTextItem;
}
set
{
this.InnerList[index] = value;
}
}

/// <summary>
/// 从实例中移除特点的第一个匹配的键值对
/// </summary>
/// <param name="item"></param>
public void Remove(ValueTextItem item)
{
this.InnerList.Remove(item);
}


/*绑定到WinForm和WebForm列表控件

/// <summary>
/// 绑定到列表控件,如ComboBox、ListBox
/// </summary>
/// <param name="listControl">继承于ListControl的列表控件如ComboBox、ListBox</param>
public void BindingTo(System.Windows.Forms.ListControl listControl)
{
listControl.DataSource = this;
listControl.ValueMember = "Value";//ValueTextItem对像的属性名称
listControl.DisplayMember = "Text";
}

/// <summary>
/// 绑定到列表控件,如 CheckBoxList、DropDownList、ListBox 和 RadioButtonList
/// </summary>
/// <param name="listControl">继承于ListControl的列表控件如 CheckBoxList、DropDownList、ListBox 和 RadioButtonList</param>
public void BindingTo(System.Web.UI.WebControls.ListControl listControl)
{
listControl.DataSource = this;
listControl.DataValueField = "Value";
listControl.DataTextField = "Text";
}

*/


}//End Class

}//End Namespace

namespace WebMIS.GoldFilter
{
/// <summary>
/// 过滤操作类型,用于不同场合(Oracle、SqlServer、ADO.NET的RowFilter等)时对应的表达示可能不一样,这里统一定义常用包括比较操作、包含以及其它的操作类型。
/// 但注意如果类型为日期时间型的,如果仅有日期部分则可以完成日期的精确比较;如果带时间,如2005-9-15 00:00:01要完成与2005-9-15的比较,可用Bettween 2005-9-15 And 2005-9-16。
/// </summary>
public enum FilterOperationTypeFlags
{
#region 定义…

/*
/// 例Oracel中日期用to_date函数如Select to_date(‘字符字段’,'YYYY-MM-DD’) From dual,Select to_char(‘日期字段’,'YYYY-MM-DD’) From dual,而日期永远没有等于,用大于等于那一天并小于等于下一天即可。
/// SqlServer中用Convert()函数如Select CONVERT(nchar(10), 字段, 120),
/// DataView.RowFilter中用两个#界定日期如"Birthdate < #1/31/82#"(MSDN上是这么说的,其实用’还是可以,可我试了,对Oracel用等号没用,后来解决了,见相GetFilter中程序说明)。
/// 在DataView.RowFilter中数字型字段也可以用Like如rowfilter ="Convert(age, ‘System.String’) Like ‘1%’"
/// */

/// <summary>
/// 默认,即 fieldname = ‘value’,因为Oracle9i、SQLServer2K的数值与字符型及一些字段的SQL和RowFilter支持这种写法。
/// 如果包含了通配符,可以用模糊查询,但是必须转换为字符如rowfilter ="Convert(age, ‘System.String’) Like ‘1*’"。
/// </summary>
Default,

/// <summary>
/// 空值,即 fieldname is null,RowFilter="Isnull(fieldname,’Null Column’) = ‘Null Column’"。
/// </summary>
Null,

/// <summary>
/// 非空值,即 not(fieldname is null),RowFilter="Not(Isnull(fieldname,’Null Column’) = ‘Null Column’)"。
/// </summary>
NotNull,

//******************通用比较******************
#region 定义比较类型包括=、<> 、>、>=、<、<=、Between…And…,In…,同时适用于字符、数字、日期类型。…

/// <summary>
/// 相等,即 fieldname = ‘value’。
/// 注意如果类型为日期时间型的,如果仅有日期部分则可以完成日期的精确比较;如果带时间,如2005-9-15 00:00:01要完成与2005-9-15的比较,可用Bettween 2005-9-15 And 2005-9-16。
/// </summary>
Equal,

/// <summary>
/// 不相等,即 fieldname <> ‘value’。
/// </summary>
UnEqual,

/// <summary>
/// 大于,即 fieldname > ‘value’。
/// </summary>
Great,

/// <summary>
/// 大于等于,即 fieldname >= ‘value’。
/// </summary>
GreatEqual,

/// <summary>
/// 小于,即 fieldname < ‘value’。
/// </summary>
Little,

/// <summary>
/// 小于等于,即 fieldname <= ‘value’。
/// </summary>
LittleEqual,

/// <summary>
/// 介于两值之间,包括两值在内,即 fieldname between ‘value1′ and ‘value2′,RowFilter="’value1′ <= fieldname And fieldname <= ‘value2′"
/// 注意如果类型为日期时间型的,如果仅有日期部分则可以完成日期的精确比较;如果带时间,如2005-9-15 00:00:01要完成与2005-9-15的比较,可用Bettween 2005-9-15 And 2005-9-16。
/// </summary>
BetweenAnd,

/// <summary>
/// 文本在…内,即 fieldname in (‘value1′,’value2′,…,’valuen’)。
/// </summary>
In,

#endregion

//******************文本包含******************

#region 定义文本包含关系,对应Like关键字,数值、日期型如果转换成文本也可做包含。

/// <summary>
/// 文本包含,即 fieldname Like ‘%value%’。数值、日期型如果转换成文本也可做包含。。
/// </summary>
TextLike,

/// <summary>
/// 文本左边像,就是以文本开头,左起包含文本,即 fieldname Like ‘value%’。数值、日期型如果转换成文本也可做包含。
/// </summary>
TextLeftLike,

/// <summary>
/// 文本右边像,就是以文本结尾,尾边包含文本,即 fieldname Like ‘%value’。数值、日期型如果转换成文本也可做包含。
/// </summary>
TextLikeRight,

#endregion

/// <summary>
/// 文本长度,即 Oracel\SqlServer\RowFilter分别为Lenght(fieldname) = value、Len(fieldname) = value。
/// </summary>
TextLength,

#endregion
}


/// <summary>
/// 过滤匹配值类型,例如单个比较的相等、Like,两者之间的BetweenAnd和多个的In操作。
/// </summary>
public enum FilterMatchingTypeFlags
{
#region 定义…

/// <summary>
/// 单一值。
/// </summary>
Single,

/// <summary>
/// 用逗号分隔的两个值,用于做介于两值之间的操作。
/// </summary>
BetweenAnd,

/// <summary>
/// 用逗号分隔的多个值,用于做在…内的操作,对应SQL的关键字IN。
/// </summary>
Multi

#endregion
}

/// <summary>
/// 数据过滤,作者:长江支流(周方勇)。下载:www.webmis.com.cn Email:flygoldfish@sina.com QQ:150439795
/// </summary>
public class DataFilter
{
public static string GetFilter(string fieldName,FilterOperationTypeFlags filterOperationType,string filterValue)
{
string strFilter = "";
string strfilterValue = ReplaceSQL(filterValue);

//关于RowFilter的MSDN解释摘录重点几个(其它请参见 DataColumn 类的 Expression 属性):
/*
若要形成 RowFilter 值,请指定列的名称,后跟一个运算符和一个要筛选的值。该值必须用引号括起来。
例如"LastName = ‘Smith’"。
若要只返回那些具有空值的列,请使用以下表达式:
"Isnull(Col1,’Null Column’) = ‘Null Column’"
字符串值应放在单引号内。日期值应放在磅符号 (#) 内(经过试验,无效)。对于数值,允许使用小数和科学记数法。

字符串的开头和结尾处可以使用通配符,%与*等意, 在字符串的中间不允许使用通配符。例如,不允许 ‘te*xt’。

数据类型总是可以通过检查列的 DataType 属性来确定。还可以使用 Convert 函数来转换数据类型,语法为Convert(expression, dataType)
如"Convert(total, ‘System.Int32′)"

其它函数支持,如LEN、ISNULL、IIF、TRIM、SUBSTRING
*/

switch(filterOperationType)
{
#region 实现…

case FilterOperationTypeFlags.Default:
//可输入通配符
strFilter = GetStringMatchingFilter(fieldName,strfilterValue);
break;
case FilterOperationTypeFlags.Null:
//strFilter = fieldName + " Is NULL";
strFilter = "Isnull(" + fieldName + ",’Null Column’) = ‘Null Column’";//这个对空值有效,反而对Int型的无效了
break;
case FilterOperationTypeFlags.NotNull:
//strFilter = "Not(" + fieldName + " Is NULL)";
strFilter = "Not(Isnull(" + fieldName + ",’Null Column’) = ‘Null Column’)";
break;
case FilterOperationTypeFlags.TextLength:
//strFilter = "Length(" + fieldName + ") = " + strfilterValue;//Oracel
//strFilter = "Length(" + fieldName + ") = " + strfilterValue;//SqlServer
strFilter = "Len(" + fieldName + ") = " + strfilterValue;//RowFilter
break;


#region 比较运算,同时适用于字符、数字、日期类型…

case FilterOperationTypeFlags.Equal:
strFilter = fieldName + "=’" + strfilterValue + "’";
break;
case FilterOperationTypeFlags.UnEqual:
strFilter = fieldName + "<>’" + strfilterValue + "’";
break;
case FilterOperationTypeFlags.Great:
strFilter = fieldName + ">’" + strfilterValue + "’";
break;
case FilterOperationTypeFlags.GreatEqual:
strFilter = fieldName + ">=’" + strfilterValue + "’";
break;
case FilterOperationTypeFlags.Little:
strFilter = fieldName + "<’" + strfilterValue + "’";
break;
case FilterOperationTypeFlags.LittleEqual:
strFilter = fieldName + "<=’" + strfilterValue + "’";
break;
case FilterOperationTypeFlags.BetweenAnd:
//用逗号分隔的两个值
strFilter = GetStringMatchingFilter(fieldName,strfilterValue,FilterMatchingTypeFlags.BetweenAnd);
break;
case FilterOperationTypeFlags.In:
//用逗号分隔的多个值
strFilter = GetStringMatchingFilter(fieldName,strfilterValue,FilterMatchingTypeFlags.Multi);
break;

#endregion

#region 定义文本包含关系,对应Like关键字,数值、日期型如果转换成文本也可做包含。

case FilterOperationTypeFlags.TextLike:
strFilter = fieldName + " Like ‘%" + strfilterValue + "%’";
break;
case FilterOperationTypeFlags.TextLeftLike:
strFilter = fieldName + " Like ‘" + strfilterValue + "%’";
break;
case FilterOperationTypeFlags.TextLikeRight:
strFilter = fieldName + " Like ‘%" + strfilterValue + "’";
break;

#endregion

default:
//一般支持加单引号界定
strFilter = fieldName + "=’" + strfilterValue + "’";
break;

#endregion
}

return strFilter;
}

/// <summary>
/// 获取数据表或数据视图指定列的过滤字符串,这里根据视图所在的表的指定列自动判断了数值、文本、日期型,如果还有其它的,再完善。
/// 如果列是字符类型,则可以用匹配或模糊(根据是否有通配符)查询;如果是数值型,则完全相等匹配;如果是日期型,查指定日,如带时间,查指定时间及之后的值。
/// </summary>
/// <param name="dataView">数据视图</param>
/// <param name="colName">列名,系统自动根据表中指定的列判断数据类型。</param>
/// <param name="filterValue">过滤值,还可以输入通配符</param>
/// <returns>返回指定列的过滤条件。</returns>
public static string GetFilter(DataView dataView,string colName,string filterValue)
{
return GetFilter(dataView.Table,colName,filterValue);
}

/// <summary>
/// 获取数据表或数据视图指定列的过滤字符串,这里根据表的指定列自动判断了数值、文本、日期型,如果还有其它的,再完善。
/// </summary>
/// <param name="dataTable">数据表</param>
/// <param name="colName">列名</param>
/// <param name="filterValue">过滤值,如果是字符串,还可以输入通配符</param>
/// <returns>返回指定列的过滤条件。</returns>
public static string GetFilter(DataTable dataTable,string colName,string filterValue)
{
#region 实现…

string strFilter = "";
string strfilterValue = ReplaceSQL(filterValue);

System.Type dataType = dataTable.Columns[colName].DataType;
System.TypeCode typeCode = System.Type.GetTypeCode(dataType);

//所以类型可以加引号,但是为了效率,相应的判断一下。

//规则参见RowFilter和DataColumn.Expression属性
//"Isnull(Col1,’Null Column’) = ‘Null Column’"
//字符串值应放在单引号内。日期值应放在磅符号 (#) 内。对于数值,允许使用小数和科学记数法

//字符串
if(typeCode == System.TypeCode.String)
{
//字符串,用户可以直接输入通配符,通用的是%与_,而Access为*与?
strFilter = GetStringMatchingFilter(colName,strfilterValue);
}
//数值型
else if (typeCode == System.TypeCode.Byte ||
typeCode == System.TypeCode.Char ||
typeCode == System.TypeCode.Decimal ||
typeCode == System.TypeCode.Double ||
typeCode == System.TypeCode.Int16 ||
typeCode == System.TypeCode.Int32 ||
typeCode == System.TypeCode.Int64 ||
typeCode == System.TypeCode.SByte ||
typeCode == System.TypeCode.Single ||
typeCode == System.TypeCode.UInt16 ||
typeCode == System.TypeCode.UInt32 ||
typeCode == System.TypeCode.UInt64)
{
//数值,完全相等,虽然可以加单引号,但是为了提高效率数字相比快。
strFilter = colName + "=" + strfilterValue;
}
else if(typeCode == System.TypeCode.DateTime)
{
//日期,完全相等
/*以下几种不行
strFilter = colName + "=’" + strfilterValue + "’";
strFilter = colName + "=#" + strfilterValue + "#";
strFilter = "Convert(" + colName + ",’System.String’)=’" + strfilterValue + "’";
strFilter = "Convert(" + colName + ",’System.String’)=#" + strfilterValue + "#";
strFilter = colName + "=Convert(" + strfilterValue + ",’System.DateTime’)";
*/
//strFilter = "Convert(" + colName + ",’System.DateTime’)" + "=Convert(" + strfilterValue + ",’System.DateTime’)";

/// 例Oracel中日期用to_date函数把字符或字符字段转换成日期(不能转换日期字段本身)如Select to_date(‘字符字段’,'YYYY-MM-DD’) From dual,
/// 而日期字段本身要格式则用 to_char 如 Select to_char(‘日期字段’,'YYYY-MM-DD’) From dual,而日期永远没有等于,用大于等于那一天并小于等于下一天即可。
/// SqlServer中用Convert()函数如Select CONVERT(nchar(10), 字段, 120),


try
{
System.DateTime dtStart = System.DateTime.Parse(strfilterValue);
System.DateTime dtEnd = dtStart.AddDays(1);

//MSDN说用#界定,经过运行试验,传统的’还是可以界定。
//主要为了对付Oracel,其它的可以直接用=,Oracel的日期在内核中是用数字表示的,所以他带了时间,根本仅日期比较永远不可能相等。
//strFilter = colName + ">=#" + dtStart.ToString() + "# And " + colName + "<#" + dtEnd.ToString() + "#";//<#改为<=#在Oracel中也只是查dtStart这一天,没有查出下一天,不知其它DB如何,待试。。。
strFilter = colName + ">=’" + dtStart.ToString() + "’ And " + colName + "<’" + dtEnd.ToString() + "’";
}
catch{}
}
else
{
//其它,完全相等
strFilter = colName + "=’" + strfilterValue + "’";
}

return strFilter;

#endregion
}

/// <summary>
/// 将原SQL替换为新的SQL,主要是对一些特殊字符进行处理如一个单引号替换成两个单引号。
/// </summary>
/// <param name="strSQL"></param>
/// <returns></returns>
private static string ReplaceSQL(string sql)
{
string strSql = sql;
strSql = strSql.Replace("’", "”");

return strSql;
}

/// <summary>
/// 智能组合LIKE、=、In或BetweenAnd操作,通用于标准SQL和ADO.NET的RowFilter。
/// 根据是否有通配符决定是完全匹配还是模糊查找,如果用于RowFilter,字符型之外的其它类型可用转换函数Convert执行类字符串的操作如"Convert(age, ‘System.String’) Like ‘1%’"。
/// 字符串的开头和结尾处可以使用通配符,%与*等意, 在字符串的中间不允许使用通配符。
/// </summary>
/// <param name="colName">列名</param>
/// <param name="filterValue">过滤值,单值情况下还可以输入通配符(通用的是%与_,而Access为*与?),其它用逗号分隔。</param>
/// <returns></returns>
public static string GetStringMatchingFilter(string colName,string filterValue)
{
return GetStringMatchingFilter(colName,filterValue,FilterMatchingTypeFlags.Single);

}

/// <param name="filterMathcingTypeFlags">过滤值类型,单一值可以用匹配或模糊查询,多个值用In查询,而两者之间的操作用BetweenAnd,非单一值用逗号分隔。</param>
/// <returns></returns>
public static string GetStringMatchingFilter(string colName,string filterValue,FilterMatchingTypeFlags filterMathcingTypeFlags)
{
//智能组合LIKE、=、In或BetweenAnd操作。
#region 实现…

string strFilter = "";

switch(filterMathcingTypeFlags)
{
case FilterMatchingTypeFlags.Single:
//字符串,用户可以直接输入通配符,通用的是%与_,而Access为*与?
if (filterValue.IndexOf(‘%’) > -1 || filterValue.IndexOf(‘_’) > -1 || filterValue.IndexOf(‘*’) > -1 || filterValue.IndexOf(‘?’) > -1)
{
//包含通配符则模糊查询
strFilter = colName + " LIKE ‘" + filterValue + "’";
}
else
{
//直接相等,以提高效率
strFilter = colName + "=’" + filterValue + "’";
}
break;
case FilterMatchingTypeFlags.BetweenAnd:
if(filterValue == null || filterValue == "")
{
strFilter = colName + "=”";
}
else
{
//接受分隔符,或;或-或~
string[] arr = filterValue.Split(‘,’);

if (arr.Length == 1)
{
if (filterValue.IndexOf(‘;’) > -1)
{
arr = filterValue.Split(‘;’);
}
else if (filterValue.IndexOf(‘-’) > -1)
{
arr = filterValue.Split(‘-’);
}
else if (filterValue.IndexOf(‘~’) > -1)
{
arr = filterValue.Split(‘~’);
}
}

if (arr.Length > 1)
{
//在ADO.NET中,经过试验RowFilter不支持Between…And…
//strFilter = colName + " Between ‘" + arr[0] + "’ And ‘" + arr[1] + "’";

strFilter = colName + ">= ‘" + arr[0] + "’ And " + colName + "<=’" + arr[1] + "’";
}
else
{
strFilter = colName + "=”";
}
}
break;
case FilterMatchingTypeFlags.Multi:
if(filterValue == null || filterValue == "")
{
strFilter = colName + "=”";
}
else
{
strFilter = colName + " In (";

//接受分隔符,或;或-或~
string[] arr = filterValue.Split(‘,’);

if (arr.Length == 1)
{
if (filterValue.IndexOf(‘;’) > -1)
{
arr = filterValue.Split(‘;’);
}
}

for(int i = 0 ; i < arr.Length ; i++)
{
strFilter += "’" + arr[i] + "’,";
}

//去掉最后一个多余的逗号
strFilter = strFilter.Remove(strFilter.Length -1,1);

strFilter += ")";
}
break;
}

return strFilter;

#endregion 实现…
}

}//End Class
}//End Namespace

2006年03月11日

select top (maxid-minid+1) * from (select top maxid * from (SELECT top

maxid * FROM table order by id asc) as temp_a order by id desc) as temp_b

2006年03月09日

///将文件inname加密并输出到outname
///tijnK,tijnV需要为16字节byte数组
private void EncryptoStream(string inname,string outname,byte[] tijnK,byte[] tijnV)
{

          Stream fsin = new FileStream (inname,FileMode.Open,FileAccess.Read,FileShare.Read);
          Stream fsout = new FileStream(outname,FileMode.Create,FileAccess.Write,FileShare.None);

          byte[] bin = new byte[100];
          long frlen = 0;
          long tolen = fsin.Lenght;
          int len;

          SymmetricAlgorithm sa = SymmetricAlgorithm.Create();
          ///需要解密时sa.CreateEncryptor换为sa.CreateDecryptor
          CryptoStream cs = new CryptoStream(fsout,sa.CreateEncryptor(tijnK,tijnV),CreateStreamMode.Write);

          while (frlen < tolen)
          {
                   len = fsin.Read(bin,0,100);
                   cs.Write(bin,0,len);
                   frlen += len;
          }

         cs.Close();
         fsin.Close();
         fsout.Close();

}

2006年02月28日

一、关于Web Service

什么是Web Service
对这个问题,我们至少有两种答案。从表面上看,Web service 就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。这就是说,你能够用编程的方法通过Web来调用这个应用程序。我们把调用这个Web service 的应用程序叫做客户。例如,你想创建一个Web service ,它的作用是返回当前的天气情况。那么你可已建立一个ASP页面,它接受邮政编码作为查询字符串,然后返回一个由逗号隔开的字符串,包含了当前的气温和天气。要调用这个ASP页面,客户端需要发送下面的这个HTTP GET请求:
http://host.company.com/weather.asp?zipcode=20171

返回的数据就应该是这样:
21,晴

这个ASP页面就应该可以算作是Web service 了。因为它基于HTTP GET请求,暴露出了一个可以通过Web调用的API。当然,Web service 还有更多的东西。
下面是对Web service 更精确的解释: Web services是建立可互操作的分布式应用程序的新平台。作为一个Windows程序员,你可能已经用COM或DCOM建立过基于组件的分布式应用程序。COM是一个非常好的组件技术,但是我们也很容易举出COM并不能满足要求的情况。
Web service平台是一套标准,它定义了应用程序如何在Web上实现互操作性。你可以用任何你喜欢的语言,在任何你喜欢的平台上写Web service ,只要我们可以通过Web service标准对这些服务进行查询和访问。

新平台
Web service平台需要一套协议来实现分布式应用程序的创建。任何平台都有它的数据表示方法和类型系统。要实现互操作性,Web service平台必须提供一套标准的类型系统,用于沟通不同平台、编程语言和组件模型中的不同类型系统。在传统的分布式系统中,基于界面(interface)的平台提供了一些方法来描述界面、方法和参数(译注:如COM和COBAR中的IDL语言)。同样的,Web service平台也必须提供一种标准来描述Web service,让客户可以得到足够的信息来调用这个Web service。最后,我们还必须有一种方法来对这个Web service进行远程调用。这种方法实际是一种远程过程调用协议(RPC)。为了达到互操作性,这种RPC协议还必须与平台和编程语言无关。下面几个小节就简要介绍了组成Web service平台的这三个技术。

XML和XSD
可扩展的标记语言(XML)是Web service平台中表示数据的基本格式。除了易于建立和易于分析外,XML主要的优点在于它既是平台无关的,又是厂商无关的。无关性是比技术优越性更重要的:软件厂商是不会选择一个由竞争对手所发明的技术的。
XML解决了数据表示的问题,但它没有定义一套标准的数据类型,更没有说怎么去扩展这套数据类型。例如,整形数到底代表什么?16位,32位,还是64位?这些细节对实现互操作性都是很重要的。W3C制定的XML Schema(XSD)就是专门解决这个问题的一套标准。它定义了一套标准的数据类型,并给出了一种语言来扩展这套数据类型。Web service平台就是用XSD来作为其数据类型系统的。当你用某种语言(如VB.NET或C#)来构造一个Web service时,为了符合Web service标准,所有你使用的数据类型都必须被转换为XSD类型。你用的工具可能已经自动帮你完成了这个转换,但你很可能会根据你的需要修改一下转换过程。在第二章中,我们将深入XSD,学习怎样转换自定义的数据类型(例如类)到XSD的类型。

SOAP
Web service建好以后,你或者其他人就会去调用它。简单对象访问协议(SOAP)提供了标准的RPC方法来调用Web service。实际上,SOAP在这里有点用词不当:它意味着下面的Web service是以对象的方式表示的,但事实并不一定如此:你完全可以把你的Web service写成一系列的C函数,并仍然使用SOAP进行调用。SOAP规范定义了SOAP消息的格式,以及怎样通过HTTP协议来使用SOAP。SOAP也是基于XML和XSD的,XML是SOAP的数据编码方式。第三章我们会讨论SOAP,并结识SOAP消息的各种元素。

WSDL
你会怎样向别人介绍你的Web service有什么功能,以及每个函数调用时的参数呢?你可能会自己写一套文档,你甚至可能会口头上告诉需要使用你的Web service的人。这些非正式的方法至少都有一个严重的问题:当程序员坐到电脑前,想要使用你的Web service的时候,他们的工具(如Visual Studio)无法给他们提供任何帮助,因为这些工具根本就不了解你的Web service。解决方法是:用机器能阅读的方式提供一个正式的描述文档。Web service描述语言(WSDL)就是这样一个基于XML的语言,用于描述Web service及其函数、参数和返回值。因为是基于XML的,所以WSDL既是机器可阅读的,又是人可阅读的,这将是一个很大的好处。一些最新的开发工具既能根据你的Web service生成WSDL文档,又能导入WSDL文档,生成调用相应Web service的代码。

现在我将列举三种情况,在这三种情况下,你将会发现使用Web service会带来极大的好处。此后,我还会举出不应该使用Web service的一些情况。

跨越防火墙的通信
如果你的应用程序有成千上万的用户,而且他们都分布在世界各地,那么客户端和服务器之间的通信将是一个棘手的问题。那是因为客户端和服务器之间通常都会有防火墙或者代理服务器。在这种情况下,你想使用DCOM就不是那么简单了,而且,通常你也不愿意把你的客户端程序发布到如此庞大数量的每一个用户手中。于是,你最终选择了用浏览器作为客户端,写下一堆ASP页面,把应用程序的中间层暴露给最终用户。结果呢?运气好的话,只是开发难度大了一些,运气不好的话,就会得到一个根本无法维护的应用程序。
想象一下你应该怎么在你的应用程序里面加入一个新的页面:你必须先建立好用户界面(Web页面),以及在这个页面后面,包含相应商业逻辑的中间层组件。这还不够,你还要再建立至少一个ASP页面,用来接受用户输入的信息,调用中间层组件,把结果格式化为HTML形式,最后还要把"结果页"送回浏览器。要是客户端代码不再如此依赖于HTML表单,客户端的编程不就简单多了吗?还有,建立ASP页面的那一步可以省略掉吗?
当然。如果你的中间层组件是Web service的话,你完全可以从用户界面直接调用中间层组件,从而省掉建立ASP页面的那一步。要调用Web service,你可以直接使用Microsoft SOAP Toolkit或.NET这样的SOAP客户端,也可以使用你自己开发的SOAP客户端,然后把它和你的应用程序连接起来。这样做,不仅可以缩短开发周期,还可以减少代码的复杂度,并增强整个应用程序的可维护性。同时,你的应用程序也不再需要在每次调用中间层组件时,都跳转到相应的"结果页"了。
以我的经验来看,在一个用户界面和中间层有较多交互的应用程序中,使用Web service这种结构,可以轻松的节省花在用户界面编程上的20%的开发时间。这样做还有另一个好处,就是你将得到一个由Web service组成的中间层,这一层是完全可以在应用程序集成或其他场合下被重用的。最后,通过Web service把你的应用程序的逻辑和数据暴露出来,还可以让其它平台上的客户重用你的应用程序。

应用程序集成
企业级的应用程序开发者都知道,企业里经常都要把用不同语言写成的在不同平台上运行的各种程序集成起来,而这种集成将花费很大的开发的力量。你的应用程序经常都需要从运行在古老的IBM主机上的程序中获取数据;或者再把数据发送到主机或UNIX应用程序中去。即使是在同一个平台上,不同的软件厂商生产的各种软件也常常需要集成起来。通过Web service,应用程序可以用标准的方法把功能和数据暴露出来,供其它的应用程序使用。
例如,你有一个订单登录程序,用于登录从客户来的新订单,包括客户信息、发货地址、数量、价格和付款方式等信息。同时,你还有一个订单执行程序,用于实际货物发送的管理。这两个程序是来自不同软件厂商的。一份新订单进来之后,订单登录程序需要通知订单执行程序发送货物。通过在订单执行程序上面增加一层Web service,订单执行程序可以把"AddOrder"函数暴露出来。这样,每当有新订单到来时,订单登录程序就可以调用这个函数来发送货物了。如下图。


通过Web service集成应用程序,点击小图放大


B2B的集成
用Web service集成应用程序,可以使你公司内部的商务处理更加自动化。但当交易跨越了你的供应商和客户,突破了公司的界线时又会怎么样呢?跨公司的商务交易集成通常叫做B2B集成。
Web service是B2B集成成功的关键。通过Web service,你的公司可以把关键的商务应用暴露给指定的供应商和客户。例如,把你的电子下单系统和电子发票系统暴露出来,你的客户就可以以电子的方式向你发送购货订单,而你的供应商则可以以电子的方式把原料采购的发票发送给你。当然,这并不是一个新的概念:电子文档交换(EDI)早就是这样了。Web service和EDI之间的主要区别在于,Web service的实现要比EDI简单得多,而且Web service是运行在Internet上的,在世界任何地方都可轻易实现,这样其运行成本就相对较低。不过,Web service并不像EDI那样,是文档交换或B2B集成的一套完整的解决方案。Web service只是B2B集成的一个关键部分,还需要许多其它的部分才能完成这个集成。
用Web service来实现B2B集成的最大好处在于可以轻易实现互操作性。只要把你的商务逻辑暴露出来,成为Web service,你就可以让任何指定的合作伙伴轻松的调用你的商务逻辑,而不管他们的系统在什么平台上运行,使用的是什么开发语言。这样就大大减少了花在B2B集成的上的时间和成本。这样的低成本让许多原本无法承受EDI的投资成本的中小企业也能实现B2B集成。

软件重用
软件重用是一个很大的主题,它有很多的形式和程度。最基本的形式是源代码模块或者类一级的重用。另一种形式是二进制形式的组件重用。当前,像表格控件或用户界面控件这样的可重用软件组件在市场上都占有很大的份额。但这类软件的重用都有一个很严重的限制:重用仅限于代码,而数据不能被重用。原因在于你可以很轻易的发布组件甚至源代码,但要发布数据就没那么容易了,除非那些数据都是不会经常变化的静态数据。
而Web service允许你在重用代码的同时,重用代码后面的数据。使用Web service,你不再像以前那样,要先从第三方购买、安装软件组件,再从你的应用程序中调用这些组件。你只需要直接调用远端的Web service就可以了。举个例子,你想在你的应用程序中确认用户输入的邮件地址,那么,你只需把这个地址直接发送给相应的Web service,这个Web service 就会帮你查阅街道地址、城市、省区和邮政编码等信息,确认这个地址的确在相应的邮政编码区域。Web service 的提供商可以按时间或使用次数来对这项服务进行收费。这样的服务要通过组件重用来实现是不现实的,因为那样的话你必须下载并安装好包含街道地址、城市、省区和邮政编码等信息的数据库,而且这个数据库还是不能实时更新的。
另一种软件重用的情况是把好几个应用程序的功能集成起来。例如,你想要建立一个局域网上的门户站点应用,让用户既可以查询他们的联邦快递包裹,察看股市行情,又可以管理他们的日程安排,还可以在线购买电影票。现在Web上有很多应用程序供应商,都在其应用中实现了上面的这些功能。一旦他们把这些功能都通过Web service 暴露出来,你就可以非常轻易地把所有这些功能都集成到你的门户站点中,为用户提供一个统一的、友好的界面。如下图。


点击小图放大


用Web service来集成各种应用中的功能,为用户提供一个统一的界面
许多应用程序都会利用Web service,把当前基于组件的应用程序结构扩展为组件和Web service 的混合结构。你也可以在应用程序中使用第三方的Web service 提供的功能。你还可以把你自己的应用程序的功能通过Web service 提供给别人。所有这些情况下,你都可以重用代码和代码后面的数据。总之,Web service 将是软件重用的一种非常有力的形式。

什么时候不应该使用Web Service
一个对Web service的完整介绍还应该包括什么时候不该用Web service。经过前面的介绍,我们知道了Web service 在通过Web进行互操作或远程调用的时候是最有用的。不过,还有许多情况,Web service根本不能给你带来任何好处。

单机应用程序
目前,我们还有很多桌面应用程序是供商用和个人使用的。其中一些只需要与运行在本机上的其他程序通信。在这种情况下,我们最好就不要再用Web service ,只要用本地的API就可以了。COM非常适合于在这种情况下工作,因为它既小又快。运行在一台服务器上的服务器软件也是这样:最好直接用COM或其他本地的API来进行应用程序间的调用。当然Web service 也能用在这些情况下,但那样不仅消耗太大,而且不会给你带来任何好处。

局域网上的同构应用程序
在许多应用中,你所有的程序都是用VB或VC开发的,都在Windows平台下使用COM,都运行在同一个局域网上。例如,你有两个服务器应用程序需要相互通信,或者你有一个Win32或WinForm的客户程序要连接到局域网上的另一个服务器程序。在这些程序里使用DCOM会比SOAP/HTTP有效的多。类似的,如果你的一个.NET程序要连接到LAN上的另一个.NET程序,那么你应该使用.NET remoting。有趣的是,在.NET remoting中,你也可以指定使用SOAP/HTTP来进行Web service 调用。不过最好还是直接通过TCP进行RPC调用,那样会有效得多。总之,只要你从应用程序结构的角度看来,有别的方法比Web service 更有效,更可行,那就不要再用Web service。

总结
Web service是创建可互操作的分布式应用程序的新平台。Web service 的主要目标是跨平台的可互操作性。为了达到这一目标,Web service 是完全基于XML、XSD等独立于平台、独立于软件供应商的标准的。
Web service在应用程序跨平台和跨网络进行通信的时候是非常有用的。Web service适用于应用程序集成、B2B集成、代码和数据重用,以及通过Web进行客户端和服务器的通信的场合。
当然,Web service也不是万能的,你不能到处滥用Web service。在有些情况下,Web service 会降低应用程序的性能,而不会带来任何好处。例如,一台机器或一个局域网里面运行的同构应用程序就不应该用Web service 进行通信。

2005年11月08日