[转载]发布一款轻量级的JSON转换代码

mikel阅读(1064)

[转载]发布一款轻量级的JSON转换代码 – 仰光 – 博客园.

.NET FrameWork 2.0 并没有提供JSON 字符串对象化工具,因此尝试写了这个转换器, 目前已投入使用,分享一下. 实现方式是:正则 + 递归. 对需要转换的Json 字符串复杂度没有要求. 欢迎测试,并提供反馈,谢谢. 第一次运行,有点慢,估计是初使化正则占用了时间,这些正则是静态的,之后的转换会加快.

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

namespace JsonConver
{

///

<summary> /// 节点枚举
/// </summary>

&nbsp;

public enum NodeType
{
///

<summary> /// 标识数组
/// </summary>

&nbsp;

IsArray
,
///

<summary> /// 标识对象
/// </summary>

&nbsp;

IsObject
,
///

<summary> /// 标识元数据
/// </summary>

&nbsp;

IsOriginal

,
///

<summary> /// 未知格式
/// </summary>

&nbsp;

Undefined
}

//描述Json节点
public class JsonNode
{
public NodeType NodeType;
public List List;
public Dictionary DicObject;
public string Value;
}

///

<summary> /// json 字符串对象化
/// </summary>

&nbsp;

public class ConvertJsonObject
{
static string regTxt = "({0}[^{0}{1}]*(((?'Open'{0})[^{0}{1}]*)+((?'-Open'{1})[^{0}{1}]*)+)*(?(Open)(?!)){1})";

//匹配字符串(单双引号范围)
static string regKeyValue = "({0}.{1}?(?

//匹配元数据(不包含对象,数组)
static string regOriginalValue = string.Format("({0}|{1}|{2})", string.Format(regKeyValue, "'", "*"), string.Format(regKeyValue, "\"", "*"), "\\w+");

//匹配value (包含对象数组)
static string regValue = string.Format("({0}|{1}|{2})", regOriginalValue //字符
, string.Format(regTxt, "\\[", "\\]"), string.Format(regTxt, "\\{", "\\}"));

//匹配键值对
static string regKeyValuePair = string.Format("\\s*(?{0}|{1}|{2})\\s*:\\s*(?{3})\\s*"
, string.Format(regKeyValue, "'", "+"), string.Format(regKeyValue, "\"", "+"), "([^ :,]+)" //匹配key
, regValue); //匹配value

///

<summary> /// 判断是否是对象
/// </summary>

&nbsp;

static Regex RegJsonStrack1 = new Regex(string.Format("^\\{0}(({2})(,(?=({2})))?)+\\{1}$", "{", "}", regKeyValuePair), RegexOptions.Compiled);

///

<summary> /// 判断是否是序列
/// </summary>

&nbsp;

static Regex RegJsonStrack2 = new Regex(string.Format("^\\[(({0})(,(?=({0})))?)+\\]$", regValue), RegexOptions.Compiled);

///

<summary> /// 判断键值对
/// </summary>

&nbsp;

static Regex RegJsonStrack3 = new Regex(regKeyValuePair, RegexOptions.Compiled);

//匹配value
static Regex RegJsonStrack4 = new Regex(regValue, RegexOptions.Compiled);

//匹配元数据
static Regex RegJsonStrack6 = new Regex(string.Format("^{0}$", regOriginalValue), RegexOptions.Compiled);

//移除两端[] , {}
static Regex RegJsonRemoveBlank = new Regex("(^\\s*[\\[\\{'\"]\\s*)|(\\s*[\\]\\}'\"]\\s*$)", RegexOptions.Compiled);

string JsonTxt;
public ConvertJsonObject(string json)
{
//去掉换行符
json = Regex.Replace(json, "[\r\n]", "");

JsonTxt = json;
}

///

<summary> /// 判断节点内型
/// </summary>

&nbsp;

//////
public NodeType MeasureType(string json)
{
if (RegJsonStrack1.IsMatch(json))
{
return NodeType.IsObject;
}

if (RegJsonStrack2.IsMatch(json))
{
return NodeType.IsArray;
}

if (RegJsonStrack6.IsMatch(json))
{
return NodeType.IsOriginal;
}

return NodeType.Undefined;

}

///

<summary> /// json 字符串序列化为对象
/// </summary>

&nbsp;

//////
public JsonNode SerializationJsonNodeToObject()
{
return SerializationJsonNodeToObject(JsonTxt);
}

///

<summary> /// json 字符串序列化为对象
/// </summary>

&nbsp;

//////
public JsonNode SerializationJsonNodeToObject(string json)
{
json = json.Trim();
NodeType nodetype = MeasureType(json);
if (nodetype == NodeType.Undefined)
{
throw new Exception("未知格式Json: " + json);
}

JsonNode newNode = new JsonNode();
newNode.NodeType = nodetype;

if (nodetype == NodeType.IsArray)
{
json = RegJsonRemoveBlank.Replace(json, "");
MatchCollection matches = RegJsonStrack4.Matches(json);
newNode.List = new List();
foreach (Match match in matches)
{
if (match.Success)
{
newNode.List.Add(SerializationJsonNodeToObject(match.Value));
}
}
}
else if (nodetype == NodeType.IsObject)
{
json = RegJsonRemoveBlank.Replace(json, "");
MatchCollection matches = RegJsonStrack3.Matches(json);
newNode.DicObject = new Dictionary();
string key;
foreach (Match match in matches)
{
if (match.Success)
{
key = RegJsonRemoveBlank.Replace(match.Groups["key"].Value, "");
if (newNode.DicObject.ContainsKey(key))
{
throw new Exception("json 数据中包含重复键, json:" + json);
}
newNode.DicObject.Add(key, SerializationJsonNodeToObject(match.Groups["value"].Value));
}
}
}
else if (nodetype == NodeType.IsOriginal)
{
newNode.Value = RegJsonRemoveBlank.Replace(json, "").Replace("\\r\\n", "\r\n");
}

return newNode;
}
}
}

其中 JsonNode 是返回解析结果

NodeType 是枚举类型,表示当前节点是什么类型.

IsArray: JsonNode.List

IsObject:JsonNode.DicObject

IsOriginal:JsonNode.Value

Json 字符串换行请用双斜杠,如 “aa\\r\\nbb”,表示aa,bb 为相邻两行.

 

调用代码:

JsonConver.ConvertJsonObject jsonObj = new JsonConver.ConvertJsonObject("{'a':11,'b':[1,2,3],'c':{'a':1,'b':[1,2,3]}}");
            JsonConver.JsonNode node = jsonObj.SerializationJsonNodeToObject();
            if (node.NodeType == JsonConver.NodeType.IsObject)
            {
                if (node.DicObject["a"].NodeType == JsonConver.NodeType.IsOriginal)
                {
                    Console.Write("key:a , value:");
                    Console.Write(node.DicObject["a"].Value);
                    Console.WriteLine();
                }

                if (node.DicObject["b"].NodeType == JsonConver.NodeType.IsArray)
                {
                    Console.Write("key:b,value for first:");
                    Console.Write(node.DicObject["b"].List[0].Value);
                    Console.WriteLine();
                }

                if (node.DicObject["c"].NodeType == JsonConver.NodeType.IsObject)
                {
                    if (node.DicObject["c"].DicObject["a"].NodeType == JsonConver.NodeType.IsOriginal)
                    {
                        Console.Write("key:c  子对象值: , value:");
                        Console.Write(node.DicObject["c"].DicObject["a"].Value);
                        Console.WriteLine();
                    }
                }
            }

       

                Console.Read();

[转载]应用程序权限设计

mikel阅读(751)

[转载]应用程序权限设计 – 玉开 – 博客园.

我们在开发系统的时候,经常会遇到系统需要权限控制,而权限的控制程度不同有不同的设计方案。

 

1.       基于角色的权限设计

这种方案是最常见也是比较简单的方案,不过通常有这种设计已经够了,所以微软就设计出这种方案的通用做法,这种方案对于每一个操作不做控制,只是在程序中根据角色对是否具有操作的权限进行控制;这里我们就不做详述

2.       基于操作的权限设计

这种模式下每一个操作都在数据库中有记录,用户是否拥有该操作的权限也在数据库中有记录,结构如下:


但是如果直接使用上面的设计,会导致数据库中的
UserAction这张表数据量非常大,所以我们需要进一步设计提高效率,请看方案3

 

3.       基于角色和操作的权限设计


如上图所示,我们在添加了
Role,和RoleAction表,这样子就可以减少UserAction中的记录,并且使设计更灵活一点。

但 是这种方案在用户需求的考验之下也可能显得不够灵活够用,例如当用户要求临时给某位普通员工某操作权限时,我们就需要新增加一种新的用户角色,但是这种用 户角色是不必要的,因为它只是一种临时的角色,如果添加一种角色还需要在收回此普通员工权限时删除此角色,我们需要设计一种更合适的结构来满足用户对权限 设置的要求。

 

4.       2,3组合的权限设计,其结构如下:


我们可以看到在上图中添加了
UserAction表,使用此表来添加特殊用户的权限,改表中有一个字段HasPermission可以决定用户是否有某种操作的权限,改表中记录的权限的优先级要高于UserRole中记录的用户权限。这样在应用程序中我们就需要通过UserRoleUserAction两张表中的记录判断权限。

到这儿呢并不算完,有可能用户还会给出这样的需求:对于某一种action所操作的对象某一些记录会有权限,而对于其他的记录没有权限,比如说一个内容管理系统,对于某一些频道某个用户有修改的权限,而对于另外一些频道没有修改的权限,这时候我们需要设计更复杂的权限机制。

 

5.       对于同一种实体(资源)用户可以对一部分记录有权限,而对于另外一些记录没有权限的权限设计:


对于这样的需求我们就需要对每一种不同的资源创建一张权限表,在上图中对
ContentChannel两种资源分别创建了UserActionContentUserActionChannel表用来定义用户对某条记录是否有权限;这种设计是可以满足用户需求的但是不是很经济,UserActionChannelUserActionContent中的记录会很多,而在实际的应用中并非需要记录所有的记录的权限信息,有时候可能只是一种规则,比如说对于根Channel什么级别的人有权限;这时候呢我们就可以定义些规则来判断用户权限,下面就是这种设计。

 

6.       涉及资源,权限和规则的权限设计


在这种设计下角色的概念已经没有了,只需要
Rule在程序中的类中定义用户是否有操作某种对象的权限。

以上只是分析思路,如果有不对的地方,请大家指正。

[转载]原译C#编写FTP客户端软件

mikel阅读(1153)

[转载][原译]C#编写FTP客户端软件 – lazycoding – 博客园.

1 介绍

我知道。网上有很多现成的FTP软件。但是。我们也想要了解FTP的一些底层机构,因此。 这个开源的项目在你学习FTP知识的时候也许对你有些帮组。程序的界面看起来像FileZilla,FileZilla虽然流行但是有些bug,当我打开 我博客的时候总是有问题。我需要通过FTP连接我的服务器。发送文件,下载文件等等。因为。我决定写我自己的软件来处理所有的情况。FileZilla足 够好。但它不是我的。

 

2 背景

 

看看我们已经知道的。我们知道FTP是一个标准的基于TCP网络协议。用于从一个主机向另一个主机传输文件。它是一个C/S架构。

 

图2

 

FTP程序曾经是基于命令行的。我们仍沿可以通过cmd.exe连接FTP服务器。因为FTP的确可以通过命令来操作。举个例子。我们可以在命令行 使用“stor”命令来发送文件。为了完成这些请求。FTP服务器需要一直运行等待即将到来的客户端请求。我们可以从来自维基百科的解释更好的理解 FTP:

 

客户端计算机可以通过服务器的21端口和服务器通信。叫做控制连接。它在一次会话期间保持开放。第一次连接的时候。叫做数据连接,服务器可以对客户 端打开20端口(主动模式),建立一条数据通路,连接上客户端传输数据。或者客户端打开一个随机的端口(被动模式),去连接服务器,来传输数据。控制连接 使用一个类似Telnet的协议,被用作客户端和服务器会话管理(命令,标识,密码)。。比如。”RETR filename”  会从服务器端下载文件。

图三

一个完整的FTP文件传输需要建立两种类型的连接,一种为文件传输下命令,称为控制连接,另一种实现真正的文件传输,称为数据连接。

服务器 通过三位ASCII的数字状态码,可能包含可选的描述信息,在控制连接上做出回应。比如。“200”或者是“200 OK”,表示上一条命令成功了。数字代表编号,描述信息给出了一些说明(比如“OK”),或者可能是一些需要的参数(比如需要帐号来存储文件),那么我们 需要怎么做呢。很明显。发送命令,接收“OK”回应,发送数据。接收数据。完了。但是首先需要服务器已经准备好了。FTP服务器可以在主动和被动两种模式 下运行。主动模式是基于服务器的连接而被动模式是基友客户端的连接。继续看。

在主动连接中,客户端把自己的ip和端口发送给服务器。然后服务器尝试连接到客户端,但是可能会因为防火墙的原因而被拒绝。我们在windows上都会使用反病毒/自带防火墙。是吧。那么我们来看看被动模式

在被动连接中。服务器通过一个“PASV”命令把自己的ip和端口发送给客户端。然后客户端通过该IP尝试连接服务器。对于发送文件非常有用。当我 们发送文件的时候。优先使用“PASV”模式,如你们所说。大多数协议。像FTP/HTTP 使用ASCII编码,因为全球可用。因此我们会使用这种编码。你可以从下面得到FTP的命令列表

主动和被动都是对于服务器端来说的

3 使用代码

现在我们已经为编写软件做好准备了。我们写些有用的代码吧。:)首先。我们“打开文件对话框”,集成到我们的窗体里。

3.1 资源管理器组件

我们需要一个资源管理器组件在软件界面可以看到我们所有的文件。这样我们才可以选择哪些文件来发送到FTP服务器,新建一个Windows窗体控件库(下载包中提供了)

图四

最后看起来样子是上面这样。先添加一个TreeView,一些按钮,和一个搜索功能:

TreeView.Nodes.Clear();

TreeNode nodeD = new TreeNode();

nodeD.Tag = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);

nodeD.Text = "Desktop";

nodeD.ImageIndex = 10;

nodeD.SelectedImageIndex = 10;

TreeView.Nodes.Add(nodeD);

就像上面代码展示的那样。我们需要添加地一个主节点。我的文档。我的电脑等等。然后获得子目录。

string[] dirList;
dirList = Directory.GetDirectories(parentNode.Tag.ToString());
Array.Sort(dirList);
if (dirList.Length == parentNode.Nodes.Count)
return;
for (int i = 0; i &lt; dirList.Length; i++) { node = new TreeNode(); node.Tag = dirList[i]; node.Text = dirList[i].Substring(dirList[i].LastIndexOf(@"\") + 1); node.ImageIndex = 1; parentNode.Nodes.Add(node); } 

可以从下载包里看到完整的代码。我们还应该处理鼠标单击事件。 现在我们有了一个资源管理器。还有FTP和VS所需要的所有信息。 首先,我们连接服务器。我们应该怎么做呢?

 FTPSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); AppendText(rchLog,"Status : Resolving IP Address\n",Color.Red); remoteAddress = Dns.GetHostEntry(Server).AddressList[0]; AppendText(rchLog, "Status : IP Address Found -&gt;" + remoteAddress.ToString() + "\n", Color.Red);
addrEndPoint = new IPEndPoint(remoteAddress, Port);
AppendText(rchLog,"Status : EndPoint Found -&gt;" + addrEndPoint.ToString() + "\n", Color.Red);
FTPSocket.Connect(addrEndPoint);

是的。我们需要一个socket连接到服务器 ,然后发送命令

AppendText(rchLog, "Command : " + msg + "\n", Color.Blue);
Byte[] CommandBytes = Encoding.ASCII.GetBytes((msg + "\r\n").ToCharArray());
FTPSocket.Send(CommandBytes, CommandBytes.Length, 0);
//read Response
ReadResponse();

我们发送命令到服务器。服务器以他自己的语言来响应。我们需要理解他。响应包括3位数字和一些解释。

private string SplitResponse()
{
try
{
while (true)
{
Bytes = FTPSocket.Receive(Buffer, Buffer.Length, 0); //Number Of Bytes (Count)
StatusMessage += Encoding.ASCII.GetString(Buffer, 0, Bytes); //Convert to String
if (Bytes &lt; Buffer.Length) //End Of Response break; } string[] msg = StatusMessage.Split('\n'); if (StatusMessage.Length &gt; 2)
StatusMessage = msg[msg.Length - 2]; //Remove Last \n
else
StatusMessage = msg[0];
if (!StatusMessage.Substring(3, 1).Equals(" "))
return SplitResponse();
for (int i = 0; i &lt; msg.Length - 1; i++)
AppendText(rchLog, "Response : " + msg[i] + "\n", Color.Green);
return StatusMessage;
}
catch(Exception ex)
{
AppendText(rchLog, "Status : ERROR. " +ex.Message+ "\n", Color.Red);
FTPSocket.Close();
return "";
}
}

完了。现在我们可以下载,上传,重命名。或者删除了。

4 FTP命令列表

命令 描述
ABOR 中断一个活动的文件传输
ACCT 系统帐号信息
ADAT 认证/安全数据
ALLO 分配空间来接收文件
APPE 添加文件到服务器
AUTH 认证/安全机制
CCC 清除命令通道
CDUP 转到父目录
CONF 机密性保护命令
CWD 改变服务器上的工作目录
DELE 删除服务器上的指定文件
ENC 机密保护通道
EPRT 指定一个服务器应该连接的扩展地址和端口
EPSV 进入扩展的被动模式
FEAT 得到服务器提供的功能列表
HELP 返回指定命令信息
LANG 返回语言信息
LIST 如果是文件名列出文件信息,如果是目录则列出文件列表
LPRT 指定一个服务器应该连接的长地址和端口
LPSV 进入长被动模式
MDTM 返回文件最近修改时间
MIC 完整的保护命令
MKD 创建目录
MLSD 列出指定目录的内容
MLST 在命令行上列出对象的精确信息
MODE 传输模式(S=流模式,B=块模式,C=压缩模式)
NLST 列出指定目录内容
NOOP 无动作,(虚包,来自常连接中)
OPTS 选择一个功能的选项
PASS 验证密码
PASV 进入被动模式
PBSZ 保护缓冲区大小
PORT 指定服务器应该连接的地址和端口
PROT 数据通道保护级别
PWD 显示当前工作目录
QUIT 从FTP服务器上退出登录
REIN 重新初始化登录状态连接
REST 由指定点重启文件传递
RETR 传递文件副本
RMD 在服务器上删除指定目录
RNFR 从旧名称重命名
RNTO 到新名称
SITE 向远程服务器发送指定命令
SIZE 返回文件大小
SMNT 挂载指定文件结构
STAT 返回当前状态
STOR 储存(复制)文件到服务器上
STOU 储存文件到服务器指定文件上
STRU 设置结构(F=文件,R=记录,P=页面)
SYST 返回服务器使用的操作系统
TYPE 传输模式(A=ASCII,E=EBCDIC,I=binary)
USER 验证用户
XCUP 跳到当前工作路径的父目录
XMKD 新建目录
XPWD 输出当前工作目录
XRMD 删除目录

 

5 返回码列表

  • 2xx –返回成功
  • 4xx or 5xx – 返回失败
  • 1xx or 3xx – 错误或不完整的回复

第二位定义了错误的类型

  • x0z – 语法 – 有语法错误.
  • x1z – 信息 – 请求提供信息
  • x2z – 连接 – 说明控制或数据连接有问题
  • x3z – 账户认证 – 登录或者是账户认证有问题.
  • x4z – 未定义
  • x5z – 文件系统 – 可能是服务器文件系统有问题。

 

Demo 下载

C#编写FTP客户端

6 许可

本文包括源代码和文件在CPOL下授权。

 

原文地址:File-Transfer-Protocol-FTP-Client

著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

[转载]SSL协议详解

mikel阅读(934)

[转载]SSL协议详解 – 麒麟 – 博客园.

背景介绍   

最近在看《密码学与网络安全》相关的书籍,这篇文章主要详细介绍一下著名的网络安全协议SSL。

     在开始SSl介绍之前,先给大家介绍几个密码学的概念和相关的知识。

    1、密码学的相关概念

密码学(cryptography):目的是通过将信息编码使其不可读,从而达到安全性。
明文(plain text):发送人、接受人和任何访问消息的人都能理解的消息。
密文(cipher text):明文消息经过某种编码后,得到密文消息。
加密(encryption):将明文消息变成密文消息。
解密(decryption):将密文消息变成明文消息。
算法:取一个输入文本,产生一个输出文本。
加密算法:发送方进行加密的算法。
解密算法:接收方进行解密的算法。
密钥(key):只有发送方和接收方理解的消息
对称密钥加密(Symmetric Key Cryptography):加密与解密使用相同密钥。
非对称密钥加密(Asymmetric Key Cryptography):加密与解密使用不同密钥。

    2、相关的加密算法介绍

DES算法即数据加密标准,也称为数据加密算法。加密过程如下:

在SSL中会用到分组DES、三重DES算法等加密算法对数据进行加密。当然可以选用其他非DES加密算法,视情况而定,后面会详细介绍。

3、密钥交换算法

      使用对称加密算法时,密钥交换是个大难题,所以Diffie和Hellman提出了著名的Diffie-Hellman密钥交换算法。

     Diffie-Hellman密钥交换算法原理:

复制代码
1)Alice与Bob确定两个大素数n和g,这两个数不用保密 (2)Alice选择另一个大随机数x,并计算A如下:A=gx mod n (3)Alice将A发给Bob (4)Bob  选择另一个大随机数y,并计算B如下:B=gy mod n (5)Bob将B发给Alice (6)计算秘密密钥K1如下:K1=Bx mod n (7)计算秘密密钥K2如下:K2=Ay mod n K1=K2,因此Alice和Bob可以用其进行加解密
复制代码

RSA加密算法是基于这样的数学事实:两个大素数相乘容易,而对得到的乘积求因子则很难。加密过程如下:

复制代码
(1)选择两个大素数P、Q (2)计算N=P*Q (3)选择一个公钥(加密密钥)E,使其不是(P-1)与(Q-1)的因子 (4)选择私钥(解密密钥)D,满足如下条件: (D*E) mod (P-1)(Q-1)=1 (5)加密时,明文PT计算密文CT如下: CT=PTE mod N (6)解密时,从密文CT计算明文PT如下: PT=CTDmodN 这也是SSL中会用一种密钥交换算法。
复制代码

3、散列算法: 

主要用于验证数据的完整性,即保证时消息在发送之后和接收之前没有被篡改对于SSL中使用到的散列算法有MD5、SHA-1。

4、数字证书:

 数字证书其实就是一个小的计算机文件,其作用类似于我们的身份证、护照,用于证明身份,在SSL中,使用数字证书来证明自己的身份,而不是伪造的。

5、简单的总结:

在SSL中会使用密钥交换算法交换密钥;使用密钥对数据进行加密;使用散列算法对数据的完整性进行验证,使用数字证书证明自己的身份。好了,下面开始介绍SSL协议。

SSL介绍:

安全套接字(Secure Socket LayerSSL)协议是Web浏览器与Web服务器之间安全交换信息的协议,提供两个基本的安全服务:鉴别与保密。

SSLNetscape1994年开发的,后来成为了世界上最著名的web安全机制,所有主要的浏览器都支持SSL协议

目前有三个版本:233.1,最常用的是第3版,是1995年发布的。

SSL协议的三个特性

 保密:在握手协议中定义了会话密钥后,所有的消息都被加密。

 鉴别:可选的客户端认证,和强制的服务器端认证。

 完整性:传送的消息包括消息完整性检查(使用MAC)。

SSL的位置

SSL介于应用层和TCP层之间。应用层数据不再直接传递给传输层,而是传递给SSL层,SSL层对从应用层收到的数据进行加密,并增加自己的SSL头。

 

SSL的工作原理

握手协议(Handshake protocol

记录协议(Record protocol

警报协议(Alert protocol

1、握手协议

握 手协议是客户机和服务器用SSL连接通信时使用的第一个子协议,握手协议包括客户机与服务器之间的一系列消息。SSL中最复杂的协议就是握手协议。该协议 允许服务器和客户机相互验证,协商加密和MAC算法以及保密密钥,用来保护在SSL记录中发送的数据。握手协议是在应用程序的数据传输之前使用的。

每个握手协议包含以下3个字段
(1)Type:表示10种消息类型之一
(2)Length:表示消息长度字节数
(3)Content:与消息相关的参数

握手协议的4个阶段

1.1建立安全能力

    SSL握手的第一阶段启动逻辑连接,建立这个连接的安全能力。首先客户机向服务器发出client hello消息并等待服务器响应,随后服务器向客户机返回server hello消息,对client hello消息中的信息进行确认。
Client hello消息包括Version,Random,Session id,Cipher suite,Compression method等信息。

ClientHello 客户发送CilentHello信息,包含如下内容:

(1)客户端可以支持的SSL最高版本号

(2)一个用于生成主秘密的32字节的随机数。(等会介绍主秘密是什么)

(3)一个确定会话的会话ID。

(4)一个客户端可以支持的密码套件列表。

    密码套件格式:每个套件都以“SSL”开头,紧跟着的是密钥交换算法。用“With”这个词把密钥交换算法、加密算法、散列算法分开,例 如:SSL_DHE_RSA_WITH_DES_CBC_SHA,表示把DHE_RSA(带有RSA数字签名的暂时Diffie-HellMan)定义为 密钥交换算法;把DES_CBC定义为加密算法;把SHA定义为散列算法。

(5)一个客户端可以支持的压缩算法列表。

 ServerHello 服务器用ServerHello信息应答客户,包括下列内容

(1)一个SSL版本号。取客户端支持的最高版本号和服务端支持的最高版本号中的较低者。

(2)一个用于生成主秘密的32字节的随机数。(客户端一个、服务端一个)

(3)会话ID

(4)从客户端的密码套件列表中选择的一个密码套件

(5)从客户端的压缩方法的列表中选择的压缩方法

这个阶段之后,客户端服务端知道了下列内容:

(1)SSL版本

(2)密钥交换、信息验证和加密算法

(3)压缩方法

(4)有关密钥生成的两个随机数。

1.2 服务器鉴别与密钥交换

 服务器启动SSL握手第2阶段,是本阶段所有消息的唯一发送方,客户机是所有消息的唯一接收方。该阶段分为4步:
(a)证书:服务器将数字证书和到根CA整个链发给客户端,使客户端能用服务器证书中的服务器公钥认证服务器。
(b)服务器密钥交换(可选):这里视密钥交换算法而定
(c)证书请求:服务端可能会要求客户自身进行验证。
(d)服务器握手完成:第二阶段的结束,第三阶段开始的信号

这里重点介绍一下服务端的验证和密钥交换。这个阶段的前面的(a)证书 和(b)服务器密钥交换是基于密钥交换方法的。而在SSL中密钥交换算法有6种:无效(没有密钥交换)、RSA、匿名Diffie-Hellman、暂时 Diffie-Hellman、固定Diffie-Hellman、Fortezza。

在阶段1过程客户端与服务端协商的过程中已经确定使哪种密钥交换算法。

如果协商过程中确定使用RSA交换密钥,那么过程如下图:

这个方法中,服务器在它的第一个信息中,发送了RSA加密/解密公钥证书。不过,因为预备 主秘密是由客户端在下一个阶段生成并发送的,所以第二个信息是空的。注意,公钥证书会进行从服务器到客户端的验证。当服务器收到预备主秘密时,它使用私钥 进行解密。服务端拥有私钥是一个证据,可以证明服务器是一个它在第一个信息发送的公钥证书中要求的实体。

其他的几种密钥交换算法这里就不介绍了。可以参考Behrouz A.Forouzan著的《密码学与网络安全》。

 1.3 客户机鉴别与密钥交换:

 

客户机启动SSL握手第3阶段,是本阶段所有消息的唯一发送方,服务器是所有消息的唯一接收方。该阶段分为3步:
(a)证书(可选):为了对服务器证明自身,客户要发送一个证书信息,这是可选的,在IIS中可以配置强制客户端证书认证。
(b)客户机密钥交换(Pre-master-secret):这里客户端将预备主密钥发送给服务端,注意这里会使用服务端的公钥进行加密。
(c)证书验证(可选),对预备秘密和随机数进行签名,证明拥有(a)证书的公钥。
下面也重点介绍一下RSA方式的客户端验证和密钥交换。

这种情况,除非服务器在阶段II明确请求,否则没有证书信息。客户端密钥交换方法包括阶段II收到的由RSA公钥加密的预备主密钥。
阶段III之后,客户要有服务器进行验证,客户和服务器都知道预备主密钥。

1.4 完成

客户机启动SSL握手第4阶段,使服务器结束。该阶段分为4步,前2个消息来自客户机,后2个消息来自服务器。

1.5密钥生成的过程

这样握手协议完成,下面看下什么是预备主密钥,主密钥是怎么生成的。为了保证信息的完整性 和机密性,SSL需要有六个加密秘密:四个密钥和两个IV。为了信息的可信性,客户端需要一个密钥(HMAC),为了加密要有一个密钥,为了分组加密要一 个IV,服务也是如此。SSL需要的密钥是单向的,不同于那些在其他方向的密钥。如果在一个方向上有攻击,这种攻击在其他方向是没影响的。生成过程如下:

 

 

2、记录协议 

记录协议在客户机和服务器握手成功后使用,即客户机和服务器鉴别对方和确定安全信息交换使用的算法后,进入SSL记录协议,记录协议向SSL连接提供两个服务:
(1)保密性:使用握手协议定义的秘密密钥实现
(2)完整性:握手协议定义了MAC,用于保证消息完整性
记录协议的过程:

 3、警报协议

客户机和服务器发现错误时,向对方发送一个警报消息。如果是致命错误,则算法立即关闭SSL连接,双方还会先删除相关的会话号,秘密和密钥。每个警报消息共2个字节,第1个字节表示错误类型,如果是警报,则值为1,如果是致命错误,则值为2;第2个字节制定实际错误类型。
总结
SSL中,使用握手协议协商加密和MAC算法以及保密密钥 ,使用握手协议对交换的数据进行加密和签名,使用警报协议定义数据传输过程中,出现问题如何去解决。
整个过程比较复杂,如果大家有不理解和我叙述不周的地方,欢迎大家指正出来!

作者:朱祁林
出处:http://zhuqil.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 

[转载]img标签的方方面面

mikel阅读(1003)

[转载]标签的方方面面 – hencehong – 博客园.

img>标签是页面上最为重要的元素之一。很难想象一个页面上没有图片的样子,这样的页面效果将会大打折扣。


任何一个前端工程师想必对<img>标签都非常熟悉了,毕竟经常和它打交道嘛。但你真的对它完全了解吗?如果你能准确无误地回答出以下几个关于<img>的问题,那么恭喜你,本文你可以不再往下看了,或者说你可以用省视的目光来核对本文。

  • 问题1:如果在一个页面上插入<img>标签,有哪些属性是必需的?
  • 问题2:<img>标签在HTML和XHTML中有什么区别?
  • 问题3:在一个页面上插入<img>标签,为什么说最好要使用height和width属性?
  • 问题4:<img>标签的onload/onerror/onabort事件,在什么情况下会被触发?
  • 问题5:我们一般知道,当一个图片请求返回404时,会触发onerror事件,那当图片请求返回302时,会触发onerror事件吗?304呢?403呢?500呢?请求超时呢?甚至说当返回200,但内容并非是图片时,也会触发onerror么?
  • 问题6:图片触发onerror事件时,能使用JavaScript获取到图片请求的响应代码么?
  • 问题7:我们一般知道,<img>标签可以用来发起跨域请求,你能手写出一段正确使用<img>发起跨域请求的JavaScript代码么?
  • 问题8:用户是可以设置浏览器不显示图片的,尤其是在移动设备上,用户为了节省流量,往往会进行那么,如何获知用户是否禁止浏览图片呢?

 


问题已经提出,你能回答出哪几个呢?事实上,在没有查看标准和亲自做试验之前,笔者对其中一些问题的答案也是模棱两可,不敢确保自己的答案100%准确。

下面,我们逐一分析和解答上述的8个问题:

问题1:如果在一个页面上插入<img>标签,有哪些属性是必需的?

答案是src和alt。

实例:(本实例摘自W3school: http://www.w3school.com.cn

<img src=” http://www.w3school.com.cn/i/eg_tulip.jpg”  alt=”上海鲜花港 – 郁金香” />

 

src属性规定了显示图像的URL,浏览器会对该URL发起Http Get请求。

alt属性则规定了图像的替代文本,在图像无法显示或者用户禁用图像显示时,代替图像显示在浏览器中的内容。如下图:

与src属性相比较,alt属性更容易被设计人员和开发人员所忽视,事实上,在笔者撰写本文时,即使在国内一些大型门户网站首页上(例如新浪、搜 狐),我们也可以找到许多没有alt属性的<img>标签。但笔者强烈推荐在文档的每个图像中都使用这个属性,这样即使图像无法显示,用户还 是可以看到的一些相关信息,从而大大提高了页面的用户友好性。

问题2:<img>标签在HTML和XHTML中有什么区别?

(答案摘自W3school: http://www.w3school.com.cn

在 HTML 中,<img> 标签没有结束标签。例如:

<img src=” http://www.w3school.com.cn/i/eg_tulip.jpg”  alt=”上海鲜花港 – 郁金香” >

 

在 XHTML 中,<img> 标签必须被正确地关闭。

<img src=” http://www.w3school.com.cn/i/eg_tulip.jpg”  alt=”上海鲜花港 – 郁金香” />

 

在 HTML 4.01 中,不推荐使用 image 元素的 “align”、”border”、”hspace” 以及 “vspace” 属性。在 XHTML 1.0 Strict DTD 中,不支持 image 元素的 “align”、”border”、”hspace” 以及 “vspace” 属性。

 问题3:在一个页面上插入<img>标签,为什么说最好要使用height和width属性?

您在浏览网页的时候,可能会遇到这种情况:随着页面中的图像加载并成功显示,页面上的内容会随之发生不规律的移动,影响您的阅读。这种情况就是因为页面上的图像没有定义height和width属性而导致的。

如果没有定义图片的height和width属性,那么浏览器为了能够显示每一个加载的图像,它需要先下载图像,然后解析出图像的高度和宽度,并在显示窗口留出相应的屏幕空间,这样就会导致浏览器不断地重新计算/调整页面的布局,这可能会延迟文档的显示,并导致页面重绘。

因此,笔者建议使用<img>的 height 和 width 属性来指定图像的尺寸。这样的话,浏览器在下载图像之前就为其预留出了空间,从而可以加速文档的显示,还可以避免文档内容的移动而引起页面重绘。

但是,需要注意的是:不要通过 height 和 width 属性来缩放图像。如果通过 height 和 width 属性来缩小图像,那么用户就必须下载大容量的图像(即使图像在页面上看上去很小)。正确的做法是,在网页上使用图像之前,应该通过软件把图像处理为合适的 尺寸。当然,这个准则在实际应用中也有例外,例如笔者就认为,小比例的图像缩放应该是允许的,此外,如果页面上需要加载同一张图像的不同尺寸的显示,因为浏览器对同一个图像只会请求一次,因此此时就建议使用height 和 width 属性来缩放图像。

问题4:<img>标签的onload/onerror/onabort事件,在什么情况下会被触发?

onload: 事件会在图像加载完成后立即发生。

onerror: 事件会在文档或图像加载过程中发生错误时被触发。

onabort: 事件会在图像加载被中断时发生。例如用户单击了浏览器的Stop按钮,或者在图像下载的过程中。

 

上面的三句话虽然看起来很简单,但实际上有许多细节需要进一步的研究,尤其是onload和onerror事件。这些细节的问题,将在问题5中提出。

问题5:我们一般知道,当一个图片请求返回404时,会触发onerror事件,那当图片请求返回302时,会触发onerror事件吗?304呢?403呢?500呢?请求超时呢?甚至说当返回200,但内容并非是图片时,也会触发onerror么?

这些问题需要动手做个试验。试验的结果如下表所示:

图片请求

触发的事件类型

IE

FireFox

Chrome

返回404

onerror

返回302,并且跳转地址为一个正常的图片

onload

所触发的事件类型与原始的请求无关,而是与跳转地址相关。

返回304,并且缓存生效

onload

但也要注意,如果缓存不存在,仅仅是单纯地返回304,依然会触发onerror

返回403

onerror

返回500

onerror

请求超时

onerror

返回504

返回200,但返回的内容并非图片

onerror

 

问题6:图片触发onerror事件时,能使用javascript获取到图片请求的响应代码么?

很遗憾,目前浏览器厂商尚未提供相关的接口。

问题7:我们一般知道,<img>标签可以用来发起跨域请求,你能手写出一段正确使用<img>发起跨域请求的javascript函数么?

这个问题看起来很简单,或许你很快的就写出了以下代码:

function setImageSrc() {
var i = new Image();
i.src = "http://.../1.gif";
i.onload = function() {
// do sth.
};

i.onerror = function() {
// do sth.
}

i.onabort = function() {
// do sth.
}
}

代码中新建了一个image对象,并绑定了onload, onerror, onabort三个事件处理函数。

但实际上,上述代码存在几个问题,你能看出几个呢?

1)       属性src赋值操作应该在事件绑定之后:否则,有可能出现图片已经加载完毕、但事件绑定尚未完成的情况。例如,在上述代码片段中,如果在第三行和第四行之间增加一句alert(1),就能重现这种情况。

2)       在IE6中,上述事件绑定代码会形成一个循环引用——Image对象的onload属性引用了一个匿名函数对象,而匿名函数通过其作用域链引用会 Image对象,这种循环引用会在IE6中导致内存泄露。因此,在onload的匿名函数中,应该解除循环引用,正确的代码类似于:

1 i.onload = function() {
2 // do sth.
3
4 i.onload = null;
5 i = null;
6 }

3)       在IE6中,如果图片是多帧的gif,会触发多次的onload事件。因此,为避免这种情况,也需要在onload事件处理函数中解除事件函数:

1 i.onload = function() { 2     // do sth.
3 
4     i.onload = null; 5     i = null; 6 }

问题8:用户是可以设置浏览器不显示图片的,尤其是在移动设备上,用户为了节省流量,往往会禁止图片显示。那么,如何获知用户是否禁止浏览图片呢?

注:该问题的解决方案来源于 http://stackoverflow.com/questions/8379156/how-to-detect-if-images-are-disabled-in-browser,笔者对其中的原理和代码bug做了相应的解读和修复。

在Firefox和Chrome中,可以使用Image对象的complete属性来解决此问题:设置Image对象的src属性,以请求一个不存在的图片,当浏览器禁止显示图片时,Image对象的complete属性为true,否则为false。

在Opera中,也可以使用Image对象的complete属性,但它与Firefox和Chrome的不同,设置Image的src后,在 onload之前,它一直显示为false。但我们可以将图片的src设置为一个特殊的值:img.src = “data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==”;  这样,当Opera禁止显示图片时,Image的complete属性为false,否则为true。

而在IE中,Image的complete属性会一直为false。因此,但我们注意到,当IE禁止显示图片时,是不会触发Image对象的 onload/onerror/onabort事件的。针对该特性,我们使用setTimeout函数,当在一定的时间内没有检测onload /onerror/onabort事件的发生,则认为浏览器禁止显示图片。

具体的代码如下:

<script type="text/javascript">
         detectImageEnabledMode({
             onDetectImageIsDisabled:function(){
                 alert('disabled');
             },
             onDetectImageIsEnabled:function(){
                 alert('enabled');
             }
         });
 
         // 用来检测浏览器是否禁止显示图片
      // 参数options: onDetectImageIsDisabled,检测到禁止显示图片后的回调函数;onDetectImageIsEnabled, 检测到显示图片后的回调函数
      function detectImageEnabledMode(options){
             /* define disabled/enabled actions */
             var actionCounter = 0;
             var enabledAction = options.onDetectImageIsEnabled || function() {};
             var enaledActionRun = function(){
                 if(actionCounter) 
                     return;
                 actionCounter++;
                 enabledAction();
             }
 
             var disabledAction = options.onDetectImageIsDisabled || function(){};
             var disabledActionRun = function(){
                 if(actionCounter) return;
                 actionCounter++;
                 disabledAction();
             }        
             
             /* create image */
             var img = new Image();
             var currentTime = (+new Date);
             if(navigator.appName.indexOf('Microsoft Internet Explorer') != -1){// ie
                 img.onload = i.onerror = i.onabort = enaledActionRun;
 
                 // 试图访问一个不存在的图片
                 img.src = currentTime+'.'+currentTime+'?time='+currentTime;
                 // 如果500毫秒后,尚未触发图片的onload/onerror/onabort事件,则认为浏览器禁止了图片显示
                 setTimeout(function(){
                     disabledActionRun();
                 }, 500);
             }else if (navigator.appName.indexOf('Opera') != -1) {// opera
                 img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="+'?time='+currentTime;
 
                 // 禁止图片显示时,img.complete==false
                 if(img.complete){ 
                     enaledActionRun();
                 }else{
                     disabledActionRun();
                 }
             }else{// firefox chrome safari
                 // 试图访问一个不存在的图片
                 img.src = currentTime+'.'+currentTime+'?time='+currentTime;
 
                 // 禁止图片显示时,img.complete==true
                 if(img.complete){
                     disabledActionRun();
                 }else{
                     enaledActionRun();
                 }
             }
         }
     </script>

至此,相信你已经对Image有了更进一步的了解了。事实上,还有与Image相关的许多技巧在本文没有提及,例如Image的lazyload。大家在实际编程中可以慢慢接触和了解。在以后的文章中,我也会根据实际情况持续地写一些与Image相关的文章。

[转载]微软随.NET 4.5发布新REST API框架

mikel阅读(1062)

[转载]微软随.NET 4.5发布新REST API框架.

在最近发布的Visual Studio 2012及.NET 4.5中, 微软正式推出新的网络服务框架ASP.NET Web API。作为ASP.NET MVC 4的一部分,ASP.NET Web API这套开源框架的设计目的是简化RESTful服务的开发和使用。

在“Where does ASP.NET Web API Fit?”这篇博文中, West Wind Technologies的 Rick Strahl 解析了ASP.NET Web API的目标与优势。

ASP.NET Web API 与之前的内建HTTP服务解决方案的不同之处在于,它一开始就是围绕HTTP协议及其消息语义构建起来的。与WCF REST或ASP.NET AJAX加ASMX相比,它不是对现有框架的增强,而是一个全新的平台。新的ASP.NET Web API的优势在于它汇集了之前各平台的各种最佳特性,结合为一个全面而不臃肿的HTTP平台。这套Web API基于ASP.NET,又借用了很多ASP.NET MVC的概念,应该很容易被ASP.NET的开发者适应和熟悉。

Strahl 指出ASP.NET Web API有一些核心功能,能让它成为ASP.NET MVC框架现用户的自然选择,同时也切合HTTP端点开发者的需要。

  • 完善支持URL路由,透过用户熟悉的MVC风格路由语义,生成干净的URL
  • 根据Accept标头对请求和响应的序列化形式进行内容协商(Content Negotiation)
  • 支持大量输出格式,包括JSON、XML、ATOM等
  • 默认对REST语义有完善支持,同时又不强制限定必须使用REST语义
  • 易于扩展的Formatter机制,支持添加新的输入/输出类型
  • 可通过HttpResponseMessage类、HttpRequestMessage类和强类型枚举来描述大量的HTTP操作,提供对更高级的HTTP特性的深度支持
  • 基于惯例的设计引导用户按HTTP Services的正确方式行事
  • Formatters和Filters延续了MVC的扩展模型,具备出色的扩展能力
  • 用于非Web程序时,可以脱离IIS运行(Self-hostable)
  • 具备可测试性,测试机制的设计类似于MVC

微软现有的Web服务框架叫做Windows Communication Foundation( WCF),它利用TCP、HTTP、MSMQ等传输协议构建“契约先行”的服务。WCF最初为基于SOAP的服务而设计,首先支持的是WS-*功能,但后 来添加了少量迎合REST的功能。按照Ido Flatow在一篇Code Project文章中的描述,ASP.NET Web API一开始也归在WCF框架旗下,但最终被移交到ASP.NET团队。

随着时间流逝,WCF Web API为了让WCF适配到”原生”HTTP世界,遇到了很多困难。因为WCF主要是为基于SOAP的XML消息设计的,为了让Web API成为WCF一部分,需要动的手术实在有点大(至少Web API的开发者们给了我这样的印象)。另一方面,ASP.NET MVC的基础设施既能优雅地处理HTTP请求和响应,又能轻松创建各种控制器,好像是创建这种新类型服务的合适途径。

WCF在最新的.NET 4.5中依然健在,Flatow给出了一些在WCF和ASP.NET Web API之间做出选择的标准。

  • 如果想让服务支持特殊场景,如单向消息传递、消息队列、双向通信等等,最好选择WCF。
  • 如果想让服务优先使用快速传输通道,如TCP、Named Pipes,甚至UDP(在WCF 4.5中),然后在所有其他传输都不可用的时候支持HTTP,那么最好选择WCF,并且把SOAP和WebHttp两种绑定都用上。
  • 如果服务是建立在HTTP之上的面向资源的服务,需要发挥HTTP的全部功能,如 定义浏览器的缓存控制,用ETags做版本与并发,传送图像、文档、HTML页面等多种类型的内容,在响应中用URI模板去包含Task URIs,那么新的Web API是最好的选择。
  • 如果服务是多目标环境的,既可作为面向资源的服务走HTTP通道,又可作为RPC风格的SOAP服务走TCP通道——先跟我谈谈吧,我会给你一些指点。

ASP.NET Web API已经包含在Visual Studio 2012中,Visual Studio 2010用户可单独下载。需要上手指导的开发者可以在该团队的Codeplex网站上找到很多示例项目

查看英文原文:Microsoft Release New REST API Framework as Part of .NET 4.5

[转载].NET中的Lambda表达式与匿名方法

mikel阅读(1044)

[转载].NET中的Lambda表达式与匿名方法 – yangecnu – 博客园.

    在C#2中,由于有了方法组,匿名方法,类型的协变和抗变,使得运用delegate变得很容易,在注册事件时代码变得简单易读,但是在C# 2中,代码仍然有点臃肿,大块的匿名方法会降低代码的可读性,一般我们不会在一条语句中写多个匿名方法。

LINQ产生的一个目的是能够方便的对数据进行管道操作而不失语义。LINQ能够表达对数据进行的各种逻辑操作,LINQ执行时,这些操作实际上都是通过 委托来实现的。使用LINQ to Object操作数据时,一条语句中包含多个委托是很常见的,C# 3中的Lambda表达式正式这幕后的功臣,它不仅使得我们能够在一条代码中写多个委托,而且不会丧失代码的可读性。相信用过LINQ的人应该都有这样的 体会。

在很多方面Lambda表达式可以看成是C#2中匿名方法的演变。他们俩的功能是一样的,都使得代码更加清晰和紧凑。另外,Lambda表达式和匿名方法 在闭包的特性上是一致的,但是Lambda表达式还有一些小的特性,能够使得代码在大多数情况下更加紧凑。和匿名方法一样,Lambda表达式有着自己的 转换规则—表达式的类型并不是一个委托的类型,但是它可以显示或者隐式的转换为一个委托的实例。

下面来看看Lambda表达式是如何来表示委托的。我们先从一个简单的例子开始。首先我们写一个以String类型为参数,返回Int32类型的值的委托实例。然后演示委托如何一步一步转换为Lambda表达式。

 

一、Func<……>泛型委托类型

首先我们要选委托类型,在.NET 3.5中,提供了一系列泛型委托类型。在.NET3.5中有5个名为Func的泛型委托类型。每一个类型里面包含0至4个类型参数。5个Func泛型类型签名如下:

TResult Func<TResult>()
TResult Func<T,TResult>(T arg)
TResult Func<T1,T2,TResult>(T1 arg1, T2 arg2)
TResult Func<T1,T2,T3,TResult>(T1 arg1, T2 arg2, T3 arg3)
TResult Func<T1,T2,T3,T4,TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4)

尖括号中的,都是类型参数,例如,Func<String,Double,Int32> 表示该委托接受两个参数,第一个是String,第二个是Double,返回Int32类型,所有适合该类型的方法都可以使用该委托。 Func<String,Double,Int32>等价如下面的委托:

public delegate Int32 SomeDelegate(String arg1, Double arg2)

.NET 3.5中还有一个名为Action<……>的泛型委托类,他的用法和Func的差不多,只是他的返回值为void。如果您觉得5个参数不够用 的话,在.NET 4.0中,Action<……>和Func<……>的参数扩展到了16个,如 Func<T1,……,T16,TResult>,这么多的参数主要是为了支持DLR。

在我们这个例子中,我们需要一个类型,他接受String作为参数,返回Int32类型的值,所以我们可以使用Func<String,Int32>。

二、转化为Lambda表达式的第一步

根据上面的委托类型,我们可以使用匿名方法创建一个委托实例。如下,该实例返回String参数的长度。

Func<String, Int32> returnLength;
returnLength = delegate(String text) { return text.Length; };
Console.WriteLine(returnLength("Hello"));

上面的例子中,将输出5. 上面的以delegate开头的是匿名表达式。现在我们开始对这部分进行转换。最常见的Lambda表达式的形式如下:

(参数类型1 参数名1 [ , 参数类型2 参数名2 ……]) => { 方法内部表达式 }

=>是在C# 3中引入的,他告诉编译器,我们将使用Lambda表达式,大多数的使用Lambda表达式代表委托的方法都有一个返回值。但在C# 1中,委托通常用于事件,所以很少有返回值。在LINQ中,委托用做数据管道的一部分,使得数据能够进行各种映射,过滤等操作。

下面我们使用Lambda表达式来表示该委托的实例,代码如下:

Func<String, Int32> returnLength;
returnLength = (String text)=> { return text.Length; };
Console.WriteLine(returnLength("Hello"));

上面的例子返回的结果和之前的一样,在大括号中,我们可以写任意表达式,只要返回值为String类型。

三、使用单个表达式作为函数体

前面的例子中,我们使用一对大括号将返回值表达式括起来了。这样做很灵活,你可以在括号内写多条语句,进行各种操作,就像在匿名方法中的那样。但是大多数 情况下,通常可以将这个函数体表示为单个表达式,这个表达式的值就是Lambda表达式的值。在这种情况下,我们可以省去左右的大括号和逗号,表达式样子 下面的样子。

(参数类型1 参数名1 [ , 参数类型2 参数名2 ……]) =>方法表达式

这样,上面例子中的右边部分可以改写为:

returnLength = (String text) => text.Length;

现在看起来简洁多了。那参数类型怎么办呢,由于编译器已经知道他是Func<String,Int32>的一个实例,该实例接受一个String类型的参数,所以我们可以直接将参数卸载括号内,从而省略参数类型。

四、隐式类型参数列表

在大多数情况下,编译器能够推断出参数的类型,而不需要我们现实的去声明,因此,Lambda表达是可以改写为:

(参数名1 [ ,参数名2 ……]) =>方法表达式

隐式类型参数列表,就是一系列用逗号分隔的参数名称。这些参数类型,要么全部都显示声明类型,要么全部不声明类型让编译器推断,不能一部分显示声明,一部 分隐式声明。如果有参数类型为out或者in的话,就必须显示声明参数类型。这样我们的Lambda表达式可以改写为:

returnLength = (text) => text.Length;

现在看起来简洁多了。最后唯一一点有点不爽的是,参数有个括号。

五、去掉单参数两侧的括号

当Lambda表达式只有一个参数的额时候,C# 3运行我们省略掉两边的括号,整个Lambda表达式变为下面的形式:

参数名 =>方法表达式

根据这一规则,之前例子中的Lambda表达个可以改为:

returnLength = text => text.Length;

你可能会想,哪有这么多特例啊,参数恰好只有一个,函数主题恰好能用一个表达式表达完。这里是为了展示Lambda表达式如何简化代码提高可读性,很多时候,当大量的这样的情况出现时,使用Lambda表达式能够极大提高代码可读性。现在整个方法可以写成下面这样:

Func<String, Int32> returnLength;
returnLength = text => text.Length;
Console.WriteLine(returnLength("Hello"));

现在看起来简洁多了,可能第一次觉得这样写怪怪的,就像第一次用匿名方法和LINQ那样,用久了就习惯了。当使用Lambda表达式时,你能够体会到在创 建一个委托实例时时多磨的简洁。上面例子中,我们可以把变量text换乘其他名字比如x,在LINQ中经常这样,但是长一点的变量可以更加容易阅读。下图 总结了以上的步骤:

匿名方法和委托w

 

六、总结

本文以一个特例演示了匿名方法如何一步一步转换为Lambda表达式。从转化中您可以体会到Lambda表达式的简洁,希望这些对您了解Lambda表达式有点帮助。

[转载]Visual Studio及TFS进行单元测试、负载测试、代码覆盖率、每日构建配置

mikel阅读(1070)

[转载]Visual Studio及TFS进行单元测试、负载测试、代码覆盖率、每日构建配置 – 陆敏技 – 博客园.

这是以前在VS2010上让同事做的相关工作的备案,现在VS2012都出来了,2010都快过期,帖出来共享一下。

一、单元测试

微软官方给出的指导和示例在这里。一步一步按照说明下来就可以完成。(不截图说明了)。此外博客园有一篇文章说得比较清楚,在这里

二、创建并运行包含单元测试的负载测试

微软官方给出的指导和示例在这里。一步一步按照说明下来就可以完成。(不截图说明了)更多测试项目和任务在这个页面也有。

三、运行测试并查看代码覆盖率

微软官方给出的指导和示例在这里。一步一步按照说明下来就可以完成。(不截图说明了)。这里需要说明的是,在我们查看代码覆盖率的时候出现这种情况:

找不到任何覆盖率数据

解决办法:

1.     打开 Local.testsettings,弹出“测试设置”窗口

2.     在“测试设置”的左边,选择“数据和诊断”

3.     在该窗口的右下角,选中“代码覆盖率”后面的复选框。见图1.

4.     接着单击“配置”按钮(非常隐蔽,在未选择“代码覆盖率”之前是禁用状态)

5.     在“代码覆盖率 详细信息”弹出窗口,然后选择要检测的项目.确定 应用 关闭。见图2.

再次运行测试,然后查看代码覆盖率。见图3.

图1.

图2.

图3.

四、Team Foundation Server 配置工具配置 Team Foundation 生成服务

1.      微软官方给出的指导在这里。一步一步按照说明下来就可以完成。配置完成后在TFS管理控制台后为:

2.      创建基本生成定义

这里的步骤可以完成生成配置。需要说明的是,在我们选择触发器时选择第5个就可以了。更加灵活、适合项目的需求。见下图

五:有关如何使用 Team Web Access 管理工作

可以在微软官方这里找到说明。我们可以在TFS管理控制台→应用层摘要→Web访问URL查看地址

六:配置电子邮件通知和指定 SMTP 服务器

在正式开始之前,我们先把IIS6中的“电子邮件服务”配置好:

1.     开始菜单“运行”输入“appwiz.cpl”,点击“添加/删除Windows组件”,在弹出的“Windows 组件向导”窗口,在组件列表中选择“电子邮件服务”见图:

 

2.     在IIS6中配置SMTP Server
要想让TFS的邮件提醒功能将邮件转发到第三方邮箱(如@cdce.cn、@live.cn、@163.com等),需要进行邮件转发设置,打开IIS6,如下图:

3.     在SMTP Virtual Server属性中:
(1)    在常规选项卡中设置IP地址:

(2)    在访问选项卡中设置中继限制:

在中继限制弹出框中选择“仅以下列表除外”

接着就是确定→确定。
 4.     需要为SMTP Server分配一个E-mail地址。打开IIS7,设置Email地址以及转到本地SMTP服务器,如下图:

5.     配置TFS 2010

注意,IIS中的Email地址和本地SMTP服务器设置必须要与TFS管理控制台中的电子邮件通知设置一致!!!
6.     客户端设置
在Visual Studio 2010的菜单栏找到邮件邮件提醒设置:团队→项目警报(只有已连接到TFS服务器后才有此选项),输入需要提醒的事件以及接收提醒的邮箱,如下图:


(项目警报也可以在Team Web Access和团队资源管理器设置。其两者是同步更改的,即:在团队自由管理器设置更改后会同步到Team Web Access。)

到此,邮件提醒功能设置完毕,现在看看效果如何。Check in 一个文件后,收到一封邮件:

在邮件中我们可以点击变更过的文件,然后在网页中显示变更过的内容,查看前一个和当前版本的内容。如图:

微软在这里介绍了如何配置。我们可以在TFS管理控制台应用层→电子邮件通知设置来配置。见下图

然后,我们在Team Web Access具体配置。见图1、图2.
图1.

图2.

至此,邮件发送功能配置全部完毕。
七:关于生成
如果解决方案中没有单元测试和代码覆盖率配置的话,在生成中就不会自动报告单元测试和代码覆盖率结果,如图:

。否则为这样:


只有在解决方案中建立单元测试和配置好代码覆盖率,在生成中才会有相应报告。

 

[转载]几年精心维护的.NET代码生成器ASP.NET Factory 开放所有源代码下载

mikel阅读(868)

转载几年精心维护的.NET代码生成器ASP.NET Factory 开放所有源代码下载 – James Li – 博客园.

刚开始应用.NET开发数据库访问代码,实体层的手工编码是一个相对麻烦而又重复的工作。增加数据库字段,需要添加实体层类型属性,其次还要修改数 据库读写代码。在项目初试阶段,这种变动太频繁了,于是根据一些项目的特性,设计了如下的代码生成器,以减少没有技术含量的基础代码生成工作。

clip_image002

下面以(localhost)上面的Northwind为例子,来看看如何应用它。

在服务器停靠窗体中,添加新的数据库,选择Employees表,生成它的Model类型的代码,也就是实体层。

using System;
namespace BusinessEntity
{
///

<summary> /// 实体类EmployeesEntity
/// </summary>

&nbsp;

public class EmployeesEntity
{
public EmployeesEntity() { }
private int _employeeid;
private string _lastname;
private string _firstname;
private string _title;
private string _titleofcourtesy;
private DateTime _birthdate;
private DateTime _hiredate;
private string _address;
private string _city;
private string _region;
private string _postalcode;
private string _country;
private string _homephone;
private string _extension;
private byte[] _photo;
private string _notes;
private int _reportsto;
private string _photopath;

public int EmployeeID
......
}

部分代码如下图所示的,对每个字段添加下划线,再首字母大写生成对应的属性。网上常称这是个贫血的类型定义,没有适当的方法行为。

再选择DAL数据访问代码,选择基于Param类型的,或是基于SQL方式的代码,生成的代码例子如下

using System;
using System.Data;
using System.Text;
using System.Collections.Generic;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.Data.Sql;
using System.Data.Common;
namespace Service
{
///

<summary> /// 数据访问类EmployeesDAL。
/// </summary>

&nbsp;

public class EmployeesDAL
{
public EmployeesDAL()
{}

///

<summary> /// 是否存在该记录
/// </summary>

&nbsp;

public bool Exists(int EmployeeID,string LastName)
{
StringBuilder strSql=new StringBuilder();
strSql.Append("SELECT COUNT(1) FROM Employees");
strSql.Append(" WHERE EmployeeID="+EmployeeID+" and LastName="+LastName+" ");
Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetSqlStringCommand(strSql.ToString());
int cmdresult;
object obj = db.ExecuteScalar(dbCommand);
if ((Object.Equals(obj, null)) || (Object.Equals(obj, System.DBNull.Value)))
{
cmdresult = 0;
}
else
{
cmdresult = int.Parse(obj.ToString());
}
if (cmdresult == 0)
{
return false;
}
else
{
return true;
}
}
------
}

最后,生成业务接口,以封装上面的数据访问代码。

using System;
using System.Data;
using System.Collections.Generic;
using BusinessEntity;
namespace Service
{
///

<summary> /// 业务逻辑类EmployeesService
/// </summary>

&nbsp;

public class EmployeesService
{
private readonly EmployeesDAL dal=new EmployeesDAL();
public EmployeesService()
{}
#region 成员方法
///

<summary> /// 是否存在该记录
/// </summary>

&nbsp;

public bool Exists(int EmployeeID,string LastName)
{
return dal.Exists(EmployeeID,LastName);
}
......
}

 
在2009年,我写过一篇文章,指出代码生成器配合一种小项目结构,以快速应用开发。请参考文章《一种小项目开发结构》,来了解这种结构。我截取一个图,简单的概括一下它的基本结构

clip_image002_thumb4

设计三个层,实体层 BusinessEntity,数据访问层DataProvider,服务接口层Service,最后是界面层Web应用程序。

ASP.NET Factory代码生成器能胜任上面的工作,为你减轻大量敲写重复代码的工作量。
在2010年的时候,接触到ORM,并且应用到项目中去。ORM项目有自己的代码生成器,再加上自己对模板生成有了新的理解和认识,这个代码生成器就停止维护,一直未进行过修订,所以如果所下载的源码中有Bug,请自行调试解决。

这种代码生成器有一定的优势,弊端也有,我列举几条,供您作出增强方面的参考

1  如果需要改动生成的代码格式,需要修改代码,重新编译,这会带来新的bug。

2  当时只考虑了SQL Server,没有对Access,Oracle,MySQL等流行的数据库进行编码,也没有留下扩展的接口。

3 命名规则固定到代码中,没有应用配置选项。被生成的实体名,数据访问DAL方法名,命名空间,都写死到代码中,如果需要修改,请自行查找出处。

4 没有批量代码生成的功能。如果需要对同一个数据库的所有表生成所有的实体访问代码,则无法做到。

5 没有同时生成VB和C#两种代码。合理的情况下,应该提供同时生成VB和C#两种格式的代码,像CodeDom那样。微软自己的窗体设计器,就是应用CodeDom,可生成VB或C#的两种格式的代码,而只需要一写编写,维护一套代码。

 

所有源代码下载地址 http://epn.codeplex.com

[转载]浅谈大型网站的算法和架构(一)

mikel阅读(979)

[转载]浅谈大型网站的算法和架构(一) – 川山甲 – 博客园.

 
  上个月老大给我们讲解了”浅谈大型网站的算法和架构”,获益匪浅。由于篇幅太多(光数据结构大概就有20多种),我也没有办法一下全部吸收,故我边理解,边分章节与大家分享。
  这周我查阅资料,来理解各个数据结构和算法。
  推荐几本个人感觉不错的书籍:——我把电子书放到http://download.csdn.net/user/rtxbc这里了,需要下载,到这里进行下载。
    《指针的艺术.蔡明志》——我只看了C语言这一篇。C语言个人感觉比较难的也就是指针了。
    《数据结构 使用C语言[朱战立]》——严蔚敏的也不错,可就是里面的很多语法都是抽象语法,无法运行。我个人如果没有办法在终端运行,很难印象深刻。
    《算法导论》
为了学习下载的电子书(截个图):
  算法结构

  C语言

介绍
  1984年,Pascal语义的发明者和结构化程序设计创始者,沃斯提出“算法 + 数据结构 = 程序“,从而获得当年的图灵奖。
  现今技术日新月异,互联网技术在不断的发展中,从而也翻开了历史的新篇章,这时有人提出了“算法 + 架构 = 互联网程序“。
  生活在这个时代的程序员来说,这又意味着什么呢?
  从这篇文章开始,我将与各位浅谈大型网站的算法和架构,今天先了解一下基础知识,然后我们进行逐步过渡。
查找算法(单机)
1.有个无序数组。

2.找7到20之间的数,你的思路是什么?

无怪乎以下两点:

1》冒泡排序

2》二分查找快

3.C代码实现

执行结果

数组中插入数据

数组问题:插入太慢,得挪数据。

请看下面的代码,

                                    执行结果

 

试试链表

                                    代码结构

 

链表插入数据

链表的特点是插入快,查找慢。

代码实现:

实现方式

 

请看执行过程

 

于是有了二叉树(Binary Tree)
  我们不难发现上面的两个结构(数组和链表)各有弊端。
  1》数组在更新的时候比较消耗资源,需要挨个挪动后面的元素。
  2》而链表在查询的时候需要从头挨个对比之后选择出要查询的内容。

  综上我们需要一个查询更快,更新更快的结构,于是我们有了二叉树。由于篇幅太长,下一篇继续介绍。

 

推荐
喜欢编程