<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_乱世经典</title><subtitle type="text">当一个人先从自己的内心开始奋斗，他就是个有价值的人</subtitle><id>http://feed.cnblogs.com/blog/u/47263/rss</id><updated>2012-05-22T05:02:01Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/47263/rss"/><entry><id>http://www.cnblogs.com/chenkai/archive/2012/05/15/2501592.html</id><title type="text">Windows phone应用开发[16]-数据加密</title><summary type="text">关于Windows Phone 中加密算法使用.最近一段时间很多做Windows Phone应用同学在微博上提了不少问题.其实在客户端实际需求中大多都会涉及到数据基于加密算法的解析和加密.本篇幅针对Windows Phone数据加密算法的问题.给出一些解决方案. 首先有必要来说说为何会存在Windows Phone数据加密的问题.做过Silverlight的同学应该知道.在Silverlight 4版本 .NET类库中基于System.Security.Cryptography命名空间下.保留了Aes加密算法.关于数据DES和TripleDES[3DES]加密算法已经不存在了.同样在Wind.</summary><published>2012-05-15T06:49:00Z</published><updated>2012-05-15T06:49:00Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><link rel="alternate" href="http://www.cnblogs.com/chenkai/archive/2012/05/15/2501592.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/archive/2012/05/15/2501592.html"/><content type="html">&lt;p&gt;&lt;font face="Consolas"&gt;关于Windows Phone 中加密算法使用.最近一段时间很多做Windows Phone应用同学在&lt;/font&gt;&lt;a href="http://weibo.com/1918185435/yiv59cKDs" target="_blank"&gt;&lt;font face="Consolas"&gt;微博上&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;提了不少问题.其实在客户端实际需求中大多都会涉及到数据基于加密算法的解析和加密.本篇幅针对Windows Phone数据加密算法的问题.给出一些解决方案.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;首先有必要来说说为何会存在Windows Phone数据加密的问题.做过Silverlight的同学应该知道.在Silverlight 4版本 .NET类库中基于&lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/9eat8fht(v=vs.95)" target="_blank"&gt;&lt;font face="Consolas"&gt;System.Security.Cryptography&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;命名空间下.保留了&lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.aes(v=vs.95)" target="_blank"&gt;&lt;font face="Consolas"&gt;Aes&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;加密算法.关于数据DES和TripleDES[3DES]加密算法已经不存在了.同样在Windows Phone SDK 7.1.1最新版本中.也能够看出除了SHA1和HMAC_SHA1对称算法外.如果我们尝试做MD5或对称的HMAC_MD5加密操作发现官方的SDK并没有提供类似支持的类. 如是问题就这么出现了.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;如果需要在服务器端和和客户端传递类似MD5、HMAC_MD5或是解析服务器端传递的DES、TripleDES[3DES]数据是发现现在Windows Phone针对数据加密和解析并没有对应的支持.其实这些问题.原来都在我们团队实际Coding过程都碰到过.也算是找到一些比较成熟的解决方案.如下.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;本篇幅针对MD5,HMAC_MD5,DES,TripleDES[3DES]算法给出Windows Phone移植版本.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;首先来说说MD5.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;MD5[Message Digest Algorithm MD5]用于确保信息传输完整一致，在计算机广泛使用的杂凑算法之一[又译摘要算法、哈希算法].比较常见使用于保证数据完整性.MD5或者说HASH值是一种不可逆的算法.在.NET 4中也提供类似在&lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5.aspx"&gt;&lt;font face="Consolas"&gt;System.Security.Cryptography.MD5&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;命名空间下&lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5cryptoserviceprovider.aspx" target="_blank"&gt;&lt;font face="Consolas"&gt;MD5CryptoServiceProvider&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; 类的对应实现.针对Silverlight和WP对应版本不支持MD5的情况,微软官方在archive.msdn上给出对应的MD5 Silverlight移植版本.[同样使用于Windows Phone]：&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;Silverlight MD5 Implementation:&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;[&lt;/font&gt;&lt;a href="http://archive.msdn.microsoft.com/SilverlightMD5"&gt;&lt;font face="Consolas"&gt;http://archive.msdn.microsoft.com/SilverlightMD5&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;]&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;具体实现Code也可以参考&lt;a href="https://github.com/chenkai/DataEncryptWindowsPhoneDemo/blob/master/DataEncryptBuildDemo/DataEncryptCommon/MD5_DataEncrypt.cs" target="_blank"&gt;GitHub上&lt;/a&gt;地址.这里不再赘述.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-05-15_144720" border="0" alt="2012-05-15_144720" src="http://images.cnblogs.com/cnblogs_com/chenkai/201205/20120515145204126.png" width="253" height="484" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;HMAC_MD5.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;使用 &lt;/font&gt;&lt;font face="Consolas"&gt;MD5&lt;/font&gt;&lt;font face="Consolas"&gt; 哈希函数计算基于哈希值的消息验证代码 [HMAC].&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;HMACMD5&lt;/font&gt;&lt;font face="Consolas"&gt; 是从 MD5 哈希函数构造的一种键控哈希算法，被用作基于哈希的消息验证代码 [HMAC].此 HMAC 进程将密钥与消息数据混合，使用哈希函数对混合结果进行哈希计算，将所得哈希值与该密钥混合，然后再次应用哈希函数。输出的哈希值长度为 128 位.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;关于HMAC_MD5算法除了在Codeplex 上[&lt;a href="http://hmacmd5.codeplex.com/"&gt;http://hmacmd5.codeplex.com/&lt;/a&gt;] 找到HMACmd5 Codeplex已经在Windows Phone验证通过外:&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;HMACMD5 For Silverlight/Windows Phone:&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://hmacmd5.codeplex.com/"&gt;&lt;font face="Consolas"&gt;http://hmacmd5.codeplex.com/&lt;/font&gt;&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;其他第三方方式均没有验证过.考虑该算法核心并不复杂.于是自己动手重写一个基于Windows Phone 版本HMACMD5的实现[验证通过]. 核心类如下:&lt;/font&gt;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;span class="lnum"&gt;   1:  &lt;/span&gt;﻿&lt;span class="kwrd"&gt;using&lt;/span&gt; System;  &lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Net;  &lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows;  &lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Controls;  &lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Documents;  &lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Ink;  &lt;span class="lnum"&gt;   7:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Input;  &lt;span class="lnum"&gt;   8:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Media;  &lt;span class="lnum"&gt;   9:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Media.Animation;  &lt;span class="lnum"&gt;  10:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Shapes;  &lt;span class="lnum"&gt;  11:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  12:  &lt;/span&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; DataEncryptBuildDemo.DataEncryptCommon  &lt;span class="lnum"&gt;  13:  &lt;/span&gt;{  &lt;span class="lnum"&gt;  14:  &lt;/span&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  15:  &lt;/span&gt;    &lt;span class="rem"&gt;/// HMACMD Data Encrypt Operator&lt;/span&gt;  &lt;span class="lnum"&gt;  16:  &lt;/span&gt;    &lt;span class="rem"&gt;/// Author:chenkai Data:6/7/2011&lt;/span&gt;  &lt;span class="lnum"&gt;  17:  &lt;/span&gt;    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  18:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HMACMD5DataEncrypt  &lt;span class="lnum"&gt;  19:  &lt;/span&gt;    {  &lt;span class="lnum"&gt;  20:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  21:  &lt;/span&gt;        &lt;span class="rem"&gt;/// HMAC_MD5 DataEncrypt  &lt;/span&gt;  &lt;span class="lnum"&gt;  22:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  23:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="original"&amp;gt;明文&amp;lt;/param&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  24:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="key"&amp;gt;密钥&amp;lt;/param&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  25:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;返回加密的字符串&amp;lt;/returns&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  26:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; HMAC_MD5(&lt;span class="kwrd"&gt;string&lt;/span&gt; original, &lt;span class="kwrd"&gt;string&lt;/span&gt; key)  &lt;span class="lnum"&gt;  27:  &lt;/span&gt;        {  &lt;span class="lnum"&gt;  28:  &lt;/span&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] b_tmp;  &lt;span class="lnum"&gt;  29:  &lt;/span&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] b_tmp1;  &lt;span class="lnum"&gt;  30:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (key == &lt;span class="kwrd"&gt;null&lt;/span&gt;)  &lt;span class="lnum"&gt;  31:  &lt;/span&gt;            {  &lt;span class="lnum"&gt;  32:  &lt;/span&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;  &lt;span class="lnum"&gt;  33:  &lt;/span&gt;            }  &lt;span class="lnum"&gt;  34:  &lt;/span&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] digest = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[512];  &lt;span class="lnum"&gt;  35:  &lt;/span&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] k_ipad = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[64];  &lt;span class="lnum"&gt;  36:  &lt;/span&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] k_opad = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[64];  &lt;span class="lnum"&gt;  37:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  38:  &lt;/span&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] source = System.Text.UTF8Encoding.UTF8.GetBytes(key);  &lt;span class="lnum"&gt;  39:  &lt;/span&gt;            &lt;span class="rem"&gt;//System.Security.Cryptography.MD5 shainner = new MD5CryptoServiceProvider();&lt;/span&gt;  &lt;span class="lnum"&gt;  40:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  41:  &lt;/span&gt;            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 64; i++)  &lt;span class="lnum"&gt;  42:  &lt;/span&gt;            {  &lt;span class="lnum"&gt;  43:  &lt;/span&gt;                k_ipad[i] = 0 ^ 0x36;  &lt;span class="lnum"&gt;  44:  &lt;/span&gt;                k_opad[i] = 0 ^ 0x5c;  &lt;span class="lnum"&gt;  45:  &lt;/span&gt;            }  &lt;span class="lnum"&gt;  46:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  47:  &lt;/span&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;  &lt;span class="lnum"&gt;  48:  &lt;/span&gt;            {  &lt;span class="lnum"&gt;  49:  &lt;/span&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (source.Length &amp;gt; 64)  &lt;span class="lnum"&gt;  50:  &lt;/span&gt;                {  &lt;span class="lnum"&gt;  51:  &lt;/span&gt;                    &lt;span class="rem"&gt;//shainner = new MD5CryptoServiceProvider();&lt;/span&gt;  &lt;span class="lnum"&gt;  52:  &lt;/span&gt;                    source = MD5Core.GetHash(source);&lt;span class="rem"&gt;//shainner.ComputeHash(source);&lt;/span&gt;  &lt;span class="lnum"&gt;  53:  &lt;/span&gt;                }  &lt;span class="lnum"&gt;  54:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  55:  &lt;/span&gt;                &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; source.Length; i++)  &lt;span class="lnum"&gt;  56:  &lt;/span&gt;                {  &lt;span class="lnum"&gt;  57:  &lt;/span&gt;                    k_ipad[i] = (&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(source[i] ^ 0x36);  &lt;span class="lnum"&gt;  58:  &lt;/span&gt;                    k_opad[i] = (&lt;span class="kwrd"&gt;byte&lt;/span&gt;)(source[i] ^ 0x5c);  &lt;span class="lnum"&gt;  59:  &lt;/span&gt;                }  &lt;span class="lnum"&gt;  60:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  61:  &lt;/span&gt;                b_tmp1 = System.Text.UTF8Encoding.UTF8.GetBytes(original);&lt;span class="rem"&gt;//内容&lt;/span&gt;  &lt;span class="lnum"&gt;  62:  &lt;/span&gt;                b_tmp = Adding(k_ipad, b_tmp1);  &lt;span class="lnum"&gt;  63:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  64:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  65:  &lt;/span&gt;                &lt;span class="rem"&gt;//shainner = new MD5CryptoServiceProvider();&lt;/span&gt;  &lt;span class="lnum"&gt;  66:  &lt;/span&gt;                digest = MD5Core.GetHash(b_tmp); &lt;span class="rem"&gt;//shainner.ComputeHash(b_tmp);&lt;/span&gt;  &lt;span class="lnum"&gt;  67:  &lt;/span&gt;                b_tmp = Adding(k_opad, digest);  &lt;span class="lnum"&gt;  68:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  69:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  70:  &lt;/span&gt;                &lt;span class="rem"&gt;//shainner = new MD5CryptoServiceProvider();&lt;/span&gt;  &lt;span class="lnum"&gt;  71:  &lt;/span&gt;                digest = MD5Core.GetHash(b_tmp); &lt;span class="rem"&gt;//shainner.ComputeHash(b_tmp);&lt;/span&gt;  &lt;span class="lnum"&gt;  72:  &lt;/span&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; ByteToString(digest);  &lt;span class="lnum"&gt;  73:  &lt;/span&gt;            }  &lt;span class="lnum"&gt;  74:  &lt;/span&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception e)  &lt;span class="lnum"&gt;  75:  &lt;/span&gt;            {  &lt;span class="lnum"&gt;  76:  &lt;/span&gt;                &lt;span class="kwrd"&gt;throw&lt;/span&gt; e;  &lt;span class="lnum"&gt;  77:  &lt;/span&gt;            }  &lt;span class="lnum"&gt;  78:  &lt;/span&gt;        }  &lt;span class="lnum"&gt;  79:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  80:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  81:  &lt;/span&gt;        &lt;span class="rem"&gt;/// 填充byte  &lt;/span&gt;  &lt;span class="lnum"&gt;  82:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  83:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="a"&amp;gt;&amp;lt;/param&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  84:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="b"&amp;gt;&amp;lt;/param&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  85:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  86:  &lt;/span&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] Adding(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] a, &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] b)  &lt;span class="lnum"&gt;  87:  &lt;/span&gt;        {  &lt;span class="lnum"&gt;  88:  &lt;/span&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] c = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[a.Length + b.Length];  &lt;span class="lnum"&gt;  89:  &lt;/span&gt;            a.CopyTo(c, 0);  &lt;span class="lnum"&gt;  90:  &lt;/span&gt;            b.CopyTo(c, a.Length);  &lt;span class="lnum"&gt;  91:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; c;  &lt;span class="lnum"&gt;  92:  &lt;/span&gt;        }  &lt;span class="lnum"&gt;  93:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  94:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  95:  &lt;/span&gt;        &lt;span class="rem"&gt;/// Byte To String  &lt;/span&gt;  &lt;span class="lnum"&gt;  96:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  97:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="buff"&amp;gt;&amp;lt;/param&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  98:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;  &lt;/span&gt;  &lt;span class="lnum"&gt;  99:  &lt;/span&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ByteToString(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] buff)  &lt;span class="lnum"&gt; 100:  &lt;/span&gt;        {  &lt;span class="lnum"&gt; 101:  &lt;/span&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; sbinary = &lt;span class="str"&gt;""&lt;/span&gt;;  &lt;span class="lnum"&gt; 102:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt; 103:  &lt;/span&gt;            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; buff.Length; i++)  &lt;span class="lnum"&gt; 104:  &lt;/span&gt;            {  &lt;span class="lnum"&gt; 105:  &lt;/span&gt;                sbinary += buff[i].ToString(&lt;span class="str"&gt;"X2"&lt;/span&gt;); &lt;span class="rem"&gt;// hex format  &lt;/span&gt;  &lt;span class="lnum"&gt; 106:  &lt;/span&gt;            }  &lt;span class="lnum"&gt; 107:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; (sbinary);  &lt;span class="lnum"&gt; 108:  &lt;/span&gt;        }    &lt;span class="lnum"&gt; 109:  &lt;/span&gt;    }  &lt;span class="lnum"&gt; 110:  &lt;/span&gt;}&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;具体代码也可以从&lt;/font&gt;&lt;a href="https://github.com/chenkai/DataEncryptWindowsPhoneDemo/blob/master/DataEncryptBuildDemo/DataEncryptCommon/HMACMD5_DataEncrypt.cs#L107" target="_blank"&gt;&lt;font face="Consolas"&gt;HMACMD5 For Windows Phone&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;&amp;nbsp; GitHub上可以查看.如上代码验证通过.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-05-15_144836" border="0" alt="2012-05-15_144836" src="http://images.cnblogs.com/cnblogs_com/chenkai/201205/201205151452046472.png" width="253" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;TripleDES[3DES]&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Triple DES又称3DES，是&lt;/font&gt;&lt;font face="Consolas"&gt;DES&lt;/font&gt;&lt;font face="Consolas"&gt;加密算法&lt;/font&gt;&lt;font face="Consolas"&gt;的一种模式.[TDEA，Triple Data Encryption Algorithm]块密码的通称。它相当于是对每个数据块应用三次DES加密算法.现在计算机运算能力的增强，原版DES密码的密钥长度变得容易被暴力破解；3DES即是设计用来提供一种相对简单的方法，即通过增加DES的密钥长度来避免类似的攻击，而不是设计一种全新的块密码算法.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;一开始我大概看了DES 算法在C下面的实现很简单.费了点时间很快就移植Windows Phone DES算法版本. DES算法的核心采用位运算的. 每次8个字节也就是64位内容.密钥key也为64位.然后经过16轮置换. 可惜 TripleDES[3DES]始终没有移植成功.重复造轮子无果后.果断寻求第三方解决方案.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;在Silverlight和Windows Phone 在CodePlex值得推荐开源第三方库是&lt;/font&gt;&lt;a href="http://sshnet.codeplex.com/"&gt;&lt;font face="Consolas"&gt;SSH.NET Library&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;SSH.NET Library:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://sshnet.codeplex.com/"&gt;&lt;font face="Consolas"&gt;http://sshnet.codeplex.com/&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;SSH.NET Library库移植灵感是来源于Java版本.不过SSH。NET是完全基于.NET 没有采用任何第三方组件和引用. 其中实现也包含同步和异步的封装. Socket通信库. HTTP代等.其中最为重要的是基于.NET 实现DES和TripleDES[3DES] 两种核心算法. 并且支持.NET 3.5 、Silverlight、Windows Phone.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;当然除了Codeplex上这个比较成熟SSH.NET Library开源组件外.关于DES和TripleDES[3DES] 还可以找到其他类似可选的开源组件.针对Windows Phone 缺乏3DES支持.国外一个WP 开发者&lt;/font&gt;&lt;a href="http://www.linkedin.com/in/nicolashumann" target="_blank"&gt;&lt;font face="Consolas"&gt;Nicolas Humann[Link in]&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; 基于&lt;/font&gt;&lt;a href="http://www.broccoliproducts.com/" target="_blank"&gt;&lt;font face="Consolas"&gt;broccoliproducts&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; 的&lt;a href="http://www.broccoliproducts.com/softnotebook/desblowfish/desblowfish.php" target="_blank"&gt;DES, TripleDES and BlowFish in Silverlight&lt;/a&gt; 版本库做了进一步的集成和封装. 并成功移植&lt;/font&gt;&lt;font face="Consolas"&gt;DES和TripleDES[3DES]Windows phone版本:&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;a href="http://www.linkedin.com/in/nicolashumann" target="_blank"&gt;&lt;font face="Consolas"&gt;Nicolas Humann[Link in]&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;&amp;nbsp; DES And TripleDES[3DES] Component:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;a href="http://blog.humann.info/post/2011/09/02/TripleDES-cryptography-on-silverlight-and-Windows-Phone.aspx" target="_blank"&gt;TripleDES Cryptography On Silverlight And Windows Phone&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;针对&lt;/font&gt;&lt;a href="http://www.linkedin.com/in/nicolashumann" target="_blank"&gt;&lt;font face="Consolas"&gt;Nicolas Humann[Link in]&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; 这个3DES版本移植ku.在其基础做了进一步的封装.为了是实现对TripleDESCryptoServiceProvider 类[3DES核心实现类]对数据加密和解密的操作. 大概分为两种情况.一种是需要IV密钥Key 另外一种不需要密钥Key 数据基于3DES和DES 加密和解密的封装. 核心Code如下:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;  &lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Net;  &lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows;  &lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Controls;  &lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Documents;  &lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Ink;  &lt;span class="lnum"&gt;   7:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Input;  &lt;span class="lnum"&gt;   8:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Media;  &lt;span class="lnum"&gt;   9:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Media.Animation;  &lt;span class="lnum"&gt;  10:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Windows.Shapes;  &lt;span class="lnum"&gt;  11:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  12:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;  &lt;span class="lnum"&gt;  13:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Security.Cryptography;  &lt;span class="lnum"&gt;  14:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; DataEncryptBuildDemo.DataEncryptCommon.DESDataEncrypt;  &lt;span class="lnum"&gt;  15:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  16:  &lt;/span&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; DataEncryptBuildDemo.DataEncryptCommon  &lt;span class="lnum"&gt;  17:  &lt;/span&gt;{  &lt;span class="lnum"&gt;  18:  &lt;/span&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  19:  &lt;/span&gt;    &lt;span class="rem"&gt;/// Des And TripleDES DataEncrypt Operator&lt;/span&gt;  &lt;span class="lnum"&gt;  20:  &lt;/span&gt;    &lt;span class="rem"&gt;/// Author:chenkai Date:14/5 2012&lt;/span&gt;  &lt;span class="lnum"&gt;  21:  &lt;/span&gt;    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  22:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Des_DataEncrypt  &lt;span class="lnum"&gt;  23:  &lt;/span&gt;    {  &lt;span class="lnum"&gt;  24:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  25:  &lt;/span&gt;        &lt;span class="rem"&gt;/// TripleDes  Data Encrypt With Ot Encrypt Key Operator&lt;/span&gt;  &lt;span class="lnum"&gt;  26:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  27:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="sourceContent"&amp;gt;Source Need to TripleDes Encrpt Data&amp;lt;/param&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  28:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;Encrypt Data Byte[] String&amp;lt;/returns&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  29:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] TripleDesEncryptWithOutKey(&lt;span class="kwrd"&gt;string&lt;/span&gt; sourceContent)  &lt;span class="lnum"&gt;  30:  &lt;/span&gt;        {  &lt;span class="lnum"&gt;  31:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(sourceContent))  &lt;span class="lnum"&gt;  32:  &lt;/span&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;  &lt;span class="lnum"&gt;  33:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  34:  &lt;/span&gt;            var toEncryptSourceStr = Encoding.UTF8.GetBytes(sourceContent);  &lt;span class="lnum"&gt;  35:  &lt;/span&gt;            TripleDESCryptoServiceProvider tripleDesEncryptProvider = &lt;span class="kwrd"&gt;new&lt;/span&gt; TripleDESCryptoServiceProvider();  &lt;span class="lnum"&gt;  36:  &lt;/span&gt;            ICryptoTransform encryptTransform=tripleDesEncryptProvider.CreateEncryptor();  &lt;span class="lnum"&gt;  37:  &lt;/span&gt;            &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] encryptToBytes = encryptTransform.TransformFinalBlock(toEncryptSourceStr, 0, toEncryptSourceStr.Length);  &lt;span class="lnum"&gt;  38:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  39:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; encryptToBytes;  &lt;span class="lnum"&gt;  40:  &lt;/span&gt;        }  &lt;span class="lnum"&gt;  41:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  42:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  43:  &lt;/span&gt;        &lt;span class="rem"&gt;/// TripleDes Data DeEncrypt With Out Encrypt Key Operator&lt;/span&gt;  &lt;span class="lnum"&gt;  44:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  45:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="encryptBytes"&amp;gt;Encrypt Byte Array&amp;lt;/param&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  46:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;DeEncrypt SourceContent String&amp;lt;/returns&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  47:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; TripleDesDeEncryptWithOutKey(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] encryptBytes)  &lt;span class="lnum"&gt;  48:  &lt;/span&gt;        {  &lt;span class="lnum"&gt;  49:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (encryptBytes == &lt;span class="kwrd"&gt;null&lt;/span&gt; || encryptBytes.Length &amp;lt;= 0)  &lt;span class="lnum"&gt;  50:  &lt;/span&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;  &lt;span class="lnum"&gt;  51:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  52:  &lt;/span&gt;            TripleDESCryptoServiceProvider tripleDesProvider = &lt;span class="kwrd"&gt;new&lt;/span&gt; TripleDESCryptoServiceProvider();  &lt;span class="lnum"&gt;  53:  &lt;/span&gt;            ICryptoTransform deEncryptTransform = tripleDesProvider.CreateDecryptor();  &lt;span class="lnum"&gt;  54:  &lt;/span&gt;            var deEncryptBytes = deEncryptTransform.TransformFinalBlock(encryptBytes, 0, encryptBytes.Length);  &lt;span class="lnum"&gt;  55:  &lt;/span&gt;            var deEncryptFormatStr = Encoding.UTF8.GetString(deEncryptBytes, 0, deEncryptBytes.Length);  &lt;span class="lnum"&gt;  56:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  57:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; deEncryptFormatStr;  &lt;span class="lnum"&gt;  58:  &lt;/span&gt;        }  &lt;span class="lnum"&gt;  59:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  60:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  61:  &lt;/span&gt;        &lt;span class="rem"&gt;/// TripleDes Data Encrypt Use IVKey Operator&lt;/span&gt;  &lt;span class="lnum"&gt;  62:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  63:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="sourceContent"&amp;gt;Source Content&amp;lt;/param&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  64:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="encryptKey"&amp;gt;Encrypt Key&amp;lt;/param&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  65:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;Encrypt Bytes  Array&amp;lt;/returns&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  66:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] TripleDesEncryptUseIvKey(&lt;span class="kwrd"&gt;string&lt;/span&gt; sourceContent, &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] encryptIVKey)  &lt;span class="lnum"&gt;  67:  &lt;/span&gt;        {  &lt;span class="lnum"&gt;  68:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(sourceContent) || encryptIVKey == &lt;span class="kwrd"&gt;null&lt;/span&gt; || encryptIVKey.Length &amp;lt;= 0)  &lt;span class="lnum"&gt;  69:  &lt;/span&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;  &lt;span class="lnum"&gt;  70:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  71:  &lt;/span&gt;            var toEncryptSourceStr = Encoding.UTF8.GetBytes(sourceContent);  &lt;span class="lnum"&gt;  72:  &lt;/span&gt;            TripleDESCryptoServiceProvider tripleDesProvider = &lt;span class="kwrd"&gt;new&lt;/span&gt; TripleDESCryptoServiceProvider();  &lt;span class="lnum"&gt;  73:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  74:  &lt;/span&gt;            &lt;span class="rem"&gt;//No Seting Pading&lt;/span&gt;  &lt;span class="lnum"&gt;  76:  &lt;/span&gt;            var key = tripleDesProvider.Key; &lt;span class="rem"&gt;//Save Key&lt;/span&gt;  &lt;span class="lnum"&gt;  77:  &lt;/span&gt;            IsolatedStorageCommon.IsolatedStorageSettingHelper.AddIsolateStorageObj(&lt;span class="str"&gt;"EncryptKey"&lt;/span&gt;, key);  &lt;span class="lnum"&gt;  78:  &lt;/span&gt;            ICryptoTransform encryptTransform = tripleDesProvider.CreateEncryptor(key, encryptIVKey);  &lt;span class="lnum"&gt;  79:  &lt;/span&gt;            var encryptBytes = encryptTransform.TransformFinalBlock(toEncryptSourceStr, 0, toEncryptSourceStr.Length);  &lt;span class="lnum"&gt;  80:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  81:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; encryptBytes;  &lt;span class="lnum"&gt;  82:  &lt;/span&gt;        }  &lt;span class="lnum"&gt;  83:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  84:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  85:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  86:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  87:  &lt;/span&gt;        &lt;span class="rem"&gt;/// Triple Des DeEncrypt Operator Use IvKey&lt;/span&gt;  &lt;span class="lnum"&gt;  88:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  89:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="encryptKey"&amp;gt;Encrypt key can be null&amp;lt;/param&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  90:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="ivKey"&amp;gt;Iv&amp;lt;/param&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  91:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="encryptBytes"&amp;gt;EncryptBytes&amp;lt;/param&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  92:  &lt;/span&gt;        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;Return String &amp;lt;/returns&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt;  93:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; TripleDesDeEncryptUseIvKey(&lt;span class="kwrd"&gt;byte&lt;/span&gt;[] encryptKey, &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] ivKey, &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] encryptBytes)  &lt;span class="lnum"&gt;  94:  &lt;/span&gt;        {  &lt;span class="lnum"&gt;  95:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (encryptBytes == &lt;span class="kwrd"&gt;null&lt;/span&gt; || encryptBytes.Length &amp;lt;= 0)  &lt;span class="lnum"&gt;  96:  &lt;/span&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;  &lt;span class="lnum"&gt;  97:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt;  98:  &lt;/span&gt;            TripleDESCryptoServiceProvider tripleDesProvider = &lt;span class="kwrd"&gt;new&lt;/span&gt; TripleDESCryptoServiceProvider();  &lt;span class="lnum"&gt;  99:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt; 100:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (encryptKey == &lt;span class="kwrd"&gt;null&lt;/span&gt;)  &lt;span class="lnum"&gt; 101:  &lt;/span&gt;                encryptKey = IsolatedStorageCommon.IsolatedStorageSettingHelper.GetIsolateStorageByObj(&lt;span class="str"&gt;"EncryptKey"&lt;/span&gt;) &lt;span class="kwrd"&gt;as&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[];  &lt;span class="lnum"&gt; 102:  &lt;/span&gt;            ICryptoTransform deEncryptTransform = tripleDesProvider.CreateDecryptor(encryptKey, ivKey);  &lt;span class="lnum"&gt; 103:  &lt;/span&gt;            var DecryptBytes = deEncryptTransform.TransformFinalBlock(encryptBytes, 0, encryptBytes.Length);  &lt;span class="lnum"&gt; 104:  &lt;/span&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; unDecryptFomatStr = Encoding.UTF8.GetString(DecryptBytes, 0, DecryptBytes.Length);  &lt;span class="lnum"&gt; 105:  &lt;/span&gt;&amp;nbsp;  &lt;span class="lnum"&gt; 106:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; unDecryptFomatStr;            &lt;span class="lnum"&gt; 107:  &lt;/span&gt;        }  &lt;span class="lnum"&gt; 108:  &lt;/span&gt;    }  &lt;span class="lnum"&gt; 109:  &lt;/span&gt;}&lt;/div&gt;&lt;p&gt;&lt;font face="Consolas"&gt;当然这个只是&lt;/font&gt;&lt;a href="http://www.linkedin.com/in/nicolashumann" target="_blank"&gt;&lt;font face="Consolas"&gt;Nicolas Humann[Link in]&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; 对3DEs Windows Phone版本进一步封装. 目的方便能够形成一套API.无需关心TripleDESCryptoServiceProvider 类具体如何实现.至于这段代码可以&lt;a href="https://github.com/chenkai/DataEncryptWindowsPhoneDemo/blob/master/DataEncryptBuildDemo/DataEncryptCommon/Des_DataEncrypt.cs" target="_blank"&gt;GitHub&lt;/a&gt;上找到.验证通过.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-05-15_144921" border="0" alt="2012-05-15_144921" src="http://images.cnblogs.com/cnblogs_com/chenkai/201205/201205151452055326.png" width="253" height="484" /&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;至此关于应用开发常见的MD5、MAC_MD5、DES、3DES Windows Phone移植版本算法可用库如上.如上代码均实际项目中验证通过.对于还在苦苦重复造轮子同学.如果觉得为了使用效率.还是值得参考的.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;关于本片全部源码可以GitHub下载到[ &lt;a href="https://github.com/chenkai/DataEncryptWindowsPhoneDemo"&gt;https://github.com/chenkai/DataEncryptWindowsPhoneDemo&lt;/a&gt; ].如有Bug请即时反馈 Email:chenkaiHome@live.cn&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;或通过Sina 微博：[&lt;a href="http://weibo.com/chenkaihome"&gt;http://weibo.com/chenkaihome&lt;/a&gt;] 即时沟通.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;参考链接:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://blog.humann.info/post/2011/09/02/TripleDES-cryptography-on-silverlight-and-Windows-Phone.aspx" target="_blank"&gt;&lt;font face="Consolas"&gt;TripleDES Cryptography On Silverlight And Windows Phone&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.broccoliproducts.com/softnotebook/desblowfish/desblowfish.php" target="_blank"&gt;&lt;font face="Consolas"&gt;DES, TripleDES and BlowFish in Silverlight&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/chenkai/aggbug/2501592.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/05/15/2501592.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/chenkai/archive/2012/04/17/2454164.html</id><title type="text">Windows phone应用开发[15]-辅助工具</title><summary type="text">在Windows phone应用开发中很多场景中可以使用对外开源的小工具高效完成,而使我们在应用开发,提交审核,处理数据,UI设计资源上做到事半功倍的效果.本篇幅将主要来介绍Windows phone Development 中涉及使用开发小工具. [1]Metro Studio Windows Phone 基于Metro设计的UI风格.微软设计资源的考虑分配上.在Windows phone SDK 分别内置了32个ApplicationBar可以使用Icon图标.如果你安装了Windows phone SDK可以在如下目录下找到: C:\Program Files (x86)\Micr...</summary><published>2012-04-17T11:14:00Z</published><updated>2012-04-17T11:14:00Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><link rel="alternate" href="http://www.cnblogs.com/chenkai/archive/2012/04/17/2454164.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/archive/2012/04/17/2454164.html"/><content type="html">&lt;p&gt;&lt;font face="Consolas"&gt;在Windows phone应用开发中很多场景中可以使用对外开源的小工具高效完成,而使我们在应用开发,提交审核,处理数据,UI设计资源上做到事半功倍的效果.本篇幅将主要来介绍Windows phone Development 中涉及使用开发小工具. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;a href="http://www.syncfusion.com/downloads/metrostudio" target="_blank"&gt;&lt;font face="Consolas"&gt;[1]Metro Studio&lt;/font&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Windows Phone 基于Metro设计的UI风格.微软设计资源的考虑分配上.在Windows phone SDK 分别内置了32个ApplicationBar可以使用Icon图标.如果你安装了Windows phone SDK可以在如下目录下找到:&lt;font color="#4f81bd"&gt; &lt;strong&gt;C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Icons\light&lt;/strong&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;因Windows phone 有两Black、Light明暗背景.出现两种不同前景色的Icon图标.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;这32个图标并不能完全满足所有APP实际需求.而由 syncfusion公司开发的一款Metro图标制作工具Metro Studio一款Metro图标制作工具，内置600多个Metro风格图标足以解决这个 问题.MetroStudio按照不同的分类区别图标类型&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-04-17_164310" alt="2012-04-17_164310" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913322845.png" border="0" height="465" width="644" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;通过设置修改图标大小[允许自定义],设置填充的像素.背景图形以及背景色.在短短几秒钟之内就可以完成一个标准ApplicationBar Icon图标制作.无需设计人员参与.Metro Studio 1除了图标编辑，还有XAML输出功能，假如你创建Windows Phone或者&lt;/font&gt;&lt;a href="http://www.win8mi.com/tag/windows-8"&gt;&lt;font face="Consolas"&gt;Windows 8&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;应用程序的话，这种以XAML显示的模式将会非常方便。你还可以点击Save按钮来将获取一张png图片，所以当你打算以HTML/JS的形式来创建Windows 8应用的话，想想这将会有多省事:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-04-17_164624" alt="2012-04-17_164624" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913332039.png" border="0" height="422" width="644" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Metro Studio安装需要注册码方式，注册Email有一个Product unlock key. 工具下载:&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;Development Tool Download:&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;Metro Studio Download Link:[&lt;/font&gt;&lt;/strong&gt;&lt;a title="http://www.syncfusion.com/downloads/metrostudio" href="http://www.syncfusion.com/downloads/metrostudio"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;http://www.syncfusion.com/downloads/metrostudio&lt;/font&gt;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;]&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;a href="http://isostorespy.codeplex.com/" target="_blank"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;[2]IsoStroe Spy&lt;/font&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;原来做过Silverlight的同学应该都熟悉.如果我们临时数据交互常常存储沙箱中.也就是常说独立存储空间Isolated Storage.查看数据也才Spy工具.Windows phone 在早期Mango 7.0版本并没有内置SQLCE之前.独立存储也肩负存储应用数据重任.而官方只给出一个Windows phone Development Tool 部署工具.无法直接查看XAP中内容和具体数据文件.远远不能满足需求.模拟器Xap包资源文件查看和XAP管理&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;开源的IsoStroe Spy 就应运而生:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-04-17_180854" alt="2012-04-17_180854" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913356174.png" border="0" height="469" width="644" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;虽然能够通过手动修改Xap文件修改.zip解压.获取文件具体内容. SPy工具则可以直接查看XAP 包中各种图片、文本、语音文件:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="IsoStoreSpyPreviewImage" alt="IsoStoreSpyPreviewImage" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913366796.jpg" border="0" height="434" width="644" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;最难得可贵的是.直接当前存储环境支持SQlCe数据库 执行sQL语句执行查询获取结果:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="IsoStoreSpy-SqlRequest" alt="IsoStoreSpy-SqlRequest" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913385391.jpg" border="0" height="462" width="644" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;类似这种XAP部署管理工具有很多.这也是随着Windows phone 开发者群体逐渐开始壮大.衍生很多实际需求.相信最早进入开发者一定不会忘记当初查看XAP第一款工具.&lt;/font&gt;&lt;a href="http://wp7explorer.codeplex.com/" target="_blank"&gt;&lt;font face="Consolas"&gt;WP7 Isolated Storage Explorer&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;.简陋UI和极少查看文件别扭的功能相对今天的强大SPy版本真的无法比拟的:类似IsoStoreSpy还有XAP 管理部署查看工具还有很多、类似后来不断加入的&lt;/font&gt;&lt;a href="http://wptools.codeplex.com/" target="_blank"&gt;&lt;font face="Consolas"&gt;Windows Phone Power Tools&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;和&lt;/font&gt;&lt;a href="http://wpmanagertool.codeplex.com/" target="_blank"&gt;&lt;font face="Consolas"&gt;Windows phone Xap Manager&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; 但功能远没有Spy强大.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="wptools2" alt="wptools2" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913387617.png" border="0" height="329" width="450" /&gt;&lt;img style="background-image: none; border-width: 0px; border-style: none; border-color: -moz-use-text-color; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px;" title="20-01-2012-00-06-37" alt="20-01-2012-00-06-37" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913394651.png" border="0" height="315" width="496" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;Windows phone Xap Manager:&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;IsoStore Spy Download Link：[&lt;/font&gt;&lt;/strong&gt;&lt;a title="http://isostorespy.codeplex.com/" href="http://isostorespy.codeplex.com/"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;http://isostorespy.codeplex.com/&lt;/font&gt;&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;]&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://wpiconmaker.codeplex.com/" target="_blank"&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;[3]Windows Phone Icons Maker&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;提交过应用的同学应该都知道.在对应的Windows phone APP中需要针对应用自身提供不同规格的图片.&lt;/font&gt;&lt;font face="Consolas"&gt;而且像素必须完全按照官方给出规格来制作.这在早期常常因为一些图片像素问题容易被官方打回.类似Windows phone APP图标在提交官方MarketPlace时就需要如下6中规格的图片:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="201112221747246916" alt="201112221747246916" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913439475.png" border="0" height="488" width="410" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;96DPI,规格图片分别需要62*62、99*99,173*173,200*200.如果能够有一个图片自动生成工具批量生成WP提交应用所需要的图片.Windows phone Icons Maker则做了这个工作.:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-04-17_184930" alt="2012-04-17_184930" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913466740.png" border="0" height="435" width="644" /&gt;&lt;/p&gt;  &lt;p&gt;点击saveIcon图标则自动在左面创建一个文件目录 保存文件如见:&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-04-17_185148" alt="2012-04-17_185148" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913469871.png" border="0" height="243" width="644" /&gt;&lt;/p&gt;  &lt;p&gt;如此在无需设计师参与项目下.就能够通过工具快速自动生成对应所需图片.工具虽小 但非常的实用.&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Windows phone Image Tool:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Windows phone Icons Maker: [&lt;/strong&gt;&lt;/font&gt;&lt;a title="http://wpiconmaker.codeplex.com/" href="http://wpiconmaker.codeplex.com/"&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;http://wpiconmaker.codeplex.com/&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;]&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;[4]&lt;/font&gt;&lt;a href="http://wp7emuskinswitcher.codeplex.com/"&gt;&lt;font face="Consolas"&gt;Windows Phone 7 Emulator Skin Switcher&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;在开发环境中.如果你已经厌倦微软默认给出模拟器外形皮肤.可以尝试切换成你想要的模拟器效果.Windows&amp;nbsp; phone Emulator Skin Switcher 则是整合当前市面所有Windows phone真机设备的皮肤。用来随时切换:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-04-17_190339" alt="2012-04-17_190339" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913479970.png" border="0" height="484" width="268" /&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-04-17_190457" alt="2012-04-17_190457" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913486448.png" border="0" height="484" width="268" /&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-04-17_190623" alt="2012-04-17_190623" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913498216.png" border="0" height="484" width="268" /&gt;&lt;/p&gt;  &lt;p&gt;换一份皮肤.Coding时也能换一份心情:&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-04-17_190822" alt="2012-04-17_190822" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204171913514303.png" border="0" height="364" width="524" /&gt;&lt;/p&gt;  &lt;p&gt;下载地址:&lt;/p&gt;    &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Windows phone SKin Switcher :&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Skin Swithcer Download Link: [&lt;/strong&gt;&lt;/font&gt;&lt;a title="http://wp7emuskinswitcher.codeplex.com/" href="http://wp7emuskinswitcher.codeplex.com/"&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;http://wp7emuskinswitcher.codeplex.com/&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;]&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;img src="http://www.cnblogs.com/chenkai/aggbug/2454164.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/04/17/2454164.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/chenkai/archive/2012/04/16/2451257.html</id><title type="text">团队协作资源工具</title><summary type="text">本篇幅主要用来记录收集到关于TeamWork 协作需要的资源和工具.去年在Windows phone Team中一直开始试用Scrum敏捷方法.但Scrum只是提供简单管理框架.在日常团队协作上还需要其他的资源和工具来填充一些空白.如下整理一些日常开发流程试用过一些协作工具. 类似在小团队中我们常常需要在Team中传递一些Task即需要即时ToDoList.常见的是很多人在口头传递.容...</summary><published>2012-04-16T02:05:00Z</published><updated>2012-04-16T02:05:00Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><link rel="alternate" href="http://www.cnblogs.com/chenkai/archive/2012/04/16/2451257.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/archive/2012/04/16/2451257.html"/><content type="html">&lt;font face="Consolas"&gt;   &lt;p&gt;本篇幅主要用来记录收集到关于TeamWork 协作需要的资源和工具.去年在Windows phone Team中一直开始试用Scrum敏捷方法.但Scrum只是提供简单管理框架.在日常团队协作上还需要其他的资源和工具来填充一些空白.如下整理一些日常开发流程试用过一些协作工具.&lt;/p&gt;    &lt;p&gt;类似在小团队中我们常常需要在Team中传递一些Task即需要即时ToDoList.常见的是很多人在口头传递.容易照成出错或是没有可见的Task优先级.在任务管理工具上试用过易度,Remine,ZenTao 感觉都不是达到我的需求:&lt;/p&gt;    &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;     &lt;p&gt;&lt;font size="2"&gt;协作需求:&lt;/font&gt;&lt;/p&gt;      &lt;p&gt;&lt;font size="2"&gt;数据存储在云端,或者可以自己架设，基于类似B/S架构&lt;/font&gt;&lt;/p&gt;      &lt;p&gt;&lt;font size="2"&gt;Task任务管理Tolist,可以设置优先级,并可以分配制定资源&lt;/font&gt;&lt;/p&gt;      &lt;p&gt;&lt;font size="2"&gt;任务可以排序,并对任务数据可以加以分析形成不同数据图.&lt;/font&gt;&lt;/p&gt;      &lt;p&gt;&lt;font size="2"&gt;知识库管理.类似简单Wiki功能即可了.&lt;/font&gt;&lt;/p&gt;   &lt;/blockquote&gt;    &lt;p&gt;简单的协作工具，尤其强调 todo list 功能，那么选择有如下几个：&lt;/p&gt;    &lt;ul&gt;     &lt;li&gt;&lt;strong&gt;Asana&lt;/strong&gt; - 地球上最复杂（笑）、也是最先进的基于 todo 条目的团队协作软件，是免费 web app，目前正在 beta 测试阶段 [&lt;a href="http://beta.asana.com/"&gt;http://beta.asana.com/&lt;/a&gt;] &lt;/li&gt;      &lt;li&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-16_095117" border="0" alt="2012-04-16_095117" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204161005003752.png" width="644" height="484" /&gt; &lt;/li&gt;   &lt;/ul&gt; &lt;/font&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Flow&lt;/strong&gt; - 由著名设计团队 MetaLab 出品的 UI 华丽、功能实用的协作软件，收费，具有全功能的 iOS 客户端[&lt;a href="http://www.getflow.com/"&gt;http://www.getflow.com/&lt;/a&gt;]&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-16_095429" border="0" alt="2012-04-16_095429" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204161005028477.png" width="644" height="484" /&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Basecamp&lt;/strong&gt; - 37signals 的明星产品，是以“项目”为导向的 web app，收费，除 todo list 外还有很多精致的功能[&lt;strong&gt;知乎团队在用]&lt;/strong&gt;         &lt;br /&gt;&lt;/font&gt;[&lt;a href="http://basecamphq.com/"&gt;&lt;font face="Consolas"&gt;http://basecamphq.com/&lt;/font&gt;&lt;/a&gt;] &lt;/li&gt;    &lt;li&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-16_095718" border="0" alt="2012-04-16_095718" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204161005048326.png" width="644" height="484" /&gt; &lt;/li&gt;    &lt;li&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Producteev&lt;/strong&gt; - 最近推出的一款拥有完善的 web 端和 Mac 桌面客户端的协作软件，个人使用免费，企业使用收费         &lt;br /&gt;&lt;/font&gt;[&lt;a href="http://www.producteev.com/"&gt;&lt;font face="Consolas"&gt;http://www.producteev.com/&lt;/font&gt;&lt;/a&gt;] &lt;/li&gt;    &lt;li&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-16_095810" border="0" alt="2012-04-16_095810" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/2012041610050719.png" width="644" height="484" /&gt; &lt;/li&gt;    &lt;li&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Kickoff&lt;/strong&gt; - 为迷你型团队打造的全功能协作软件，被誉为“Basecamp 的 Mac 简化版”，很贵[&lt;strong&gt;知乎团队在试用]&lt;/strong&gt;         &lt;br /&gt;&lt;/font&gt;[&lt;a href="http://kickoffapp.com/"&gt;&lt;font face="Consolas"&gt;http://kickoffapp.com/&lt;/font&gt;&lt;/a&gt;] &lt;/li&gt;    &lt;li&gt;&lt;/li&gt;    &lt;li&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Wunderlist&lt;/strong&gt; - 一款轻巧的、拥有全平台客户端的 todo 软件，免费，支持协作         &lt;br /&gt;&lt;/font&gt;&lt;a href="http://www.6wunderkinder.com/wunderlist/"&gt;&lt;font face="Consolas"&gt;6wunderkinder.com/wunderli...&lt;/font&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-16_100008" border="0" alt="2012-04-16_100008" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204161005139251.png" width="644" height="484" /&gt; &lt;/li&gt;    &lt;li&gt;&lt;font face="Consolas"&gt;&lt;a href="https://teambox.com/" target="_blank"&gt;Team Box&lt;/a&gt; - 一款比较标准化管理流程的工具.应该算是最长使用工具之一,目前集成终端的有IPhone和IPAd的客户端.这款工具优势在于其流程非常标准 没有其他工具的差异hua。容易建立比较清晰管理流程.不复杂却高速有效. 但相对其他管理 它没有操作系统级别上同步客户端 这是一个不好的地方.只能给予在线方式操作.&lt;/font&gt;&lt;/li&gt;    &lt;li&gt;&lt;font face="Consolas"&gt;[&lt;a title="https://teambox.com/" href="https://teambox.com/"&gt;https://teambox.com/&lt;/a&gt;]&lt;/font&gt;&lt;/li&gt;    &lt;li&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-04-23_095954" border="0" alt="2012-04-23_095954" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204231004479784.png" width="606" height="484" /&gt;&lt;/li&gt; &lt;/ul&gt; &lt;font face="Consolas"&gt;同类的软件还有很多很多，我只列举了很小一部分，而且都是我使用过的。    &lt;br /&gt;抱歉的是，以上软件几乎都没有中文版，不过软件使用起来足够直觉化的话，是不需要完全中文也可以理解的。&lt;/font&gt;   &lt;ul&gt;&lt;/ul&gt;&lt;img src="http://www.cnblogs.com/chenkai/aggbug/2451257.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/04/16/2451257.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/chenkai/archive/2012/04/15/2443164.html</id><title type="text">敏捷之道Scrum篇</title><summary type="text">从去年我一直设想能够在公司的整个开发部门有机会在成型开发团队尝试中小范围的敏捷开发.这个想法其实也是由来已久.或者是说源自于自己在工作中深受传统瀑布开发模型一些弊端的切身感受. 作为一个软件工程师不断重复努力开发出高质量的软件.希望我们的用户能够使用到无Bug最佳的应用程序和良好的用户体验.而构建一个稳定可靠的软件是在软件开发流程中其实一件很困难的工作.而仅仅吧软件质量的责任归咎于程序员是不公平的. 软件开发流程是需要来自不同领域人或Team参与一个过程. 而软件质量在这个整个开发流程也是息息相关的. 那本篇我要说什么呢? 针对开发流程.业界早已衍生出一些相对成熟. 可控. 能够预估...</summary><published>2012-04-14T16:14:00Z</published><updated>2012-04-14T16:14:00Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><link rel="alternate" href="http://www.cnblogs.com/chenkai/archive/2012/04/15/2443164.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/archive/2012/04/15/2443164.html"/><content type="html">&lt;p&gt;&lt;font face="Consolas"&gt;从去年我一直设想能够在公司的整个开发部门有机会在成型开发团队尝试中小范围的敏捷开发.这个想法其实也是由来已久.或者是说源自于自己在工作中深受传统瀑布开发模型一些弊端的切身感受.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;作为一个软件工程师不断重复努力开发出高质量的软件.希望我们的用户能够使用到无Bug最佳的应用程序和良好的用户体验.而构建一个稳定可靠的软件是在软件开发流程中其实一件很困难的工作.而仅仅吧软件质量的责任归咎于程序员是不公平的. 软件开发流程是需要来自不同领域人或Team参与一个过程. 而软件质量在这个整个开发流程也是息息相关的.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="blackberry_developer" border="0" alt="blackberry_developer" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204112320396566.jpg" width="469" height="283" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;那本篇我要说什么呢?&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;针对开发流程.业界早已衍生出一些相对成熟. 可控. 能够预估软件开发模型. 本篇你能够了解如下两个方面内容: A:如果你是一个开发人员.还停留传统瀑布开发模型中.想了解软件开发的敏捷方法? B:软件质量控制在传统瀑布开发模型与敏捷方法不同之处,有何优劣?&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;软件开发流程是一个很大的命题.所以本篇我不会对此进行泛泛而谈.我要说的所有内容都会围绕着，如何在传统瀑布开发和敏捷开发方法之间进行软件质量控制? 二者有何差异和不同? 两个问题展开.&lt;/font&gt;&lt;/p&gt;  &lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;传统方法瀑布开发模型&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;瀑布[Waterfall Model]开发方法.相信对于大多数开发人员来说都是很熟悉的.可能很多人和Team现在依然还停留在这个开发方法中进行日常开发工作. 瀑布方法是由Winston W.Royce 博士在1970年代发表的一篇论文中&amp;#8220;管理大型软件系统开发[&lt;a href="http://dl.acm.org/citation.cfm?id=41801" target="_blank"&gt;Managing the Development of Large Software System&lt;/a&gt;]&amp;#8221;提出的.很多人都认为瀑布开发方法都是源之于这篇论文. 其实如果你仔细的阅读这篇论文.你会发现在最初的文章中，Royce提倡重复地使用瀑布模型，以一种迭代的方式. Royce实际在论文中试图拿这种Waterfall Model开发方法来论证说明这种开发模式是存在缺陷的.而且可能导致项目失败. 而Royce没有料到的是Waterfall Model却意外的成为业界大多数软件开发的最早标准.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;瀑布模型[Waterfall Model]最早强调系统开发应有完整生命周期，且必须完整的经历周期中每一开发阶段，并系统化的考量分析与设计的技术、时间与资源之投入等，因此瀑布模型又可以称为&amp;#8216;系统发展生命周期&amp;#8217;[System Development Life Cycle, SDLC]。由于该模式强调系统开发过程需有完整的规划、分析、设计、测试及文件等管理与控制，因此能有效的确保系统品质&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Waterfall Model瀑布开发模型强调的是软件开发周期中每一个阶段都是线性的向下进行的:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="waterfalldevelopment" border="0" alt="waterfalldevelopment" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204150013305854.gif" width="671" height="489" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;至于这个流程相信很多开发人员已经是非常熟悉了.但在实际开发流程瀑布模型存在哪些问题、&amp;gt;?&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;首先第一点不得不说的就是在瀑布模型每个步骤都必须要按照顺序执行.直到整个软件开发周期完成. 最关键的是每个阶段在完成之前不能开始下一个阶段. 每一步的执行则是完全依赖于上一个阶段. 另外相信很多人会说在瀑布模型里说明问题是需要文档来记录的. 而且文档在这个过程每个阶段都需要详细文档来维系. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;很多人会问 如何在瀑布模型中保证软件质量?&amp;gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;相信很多在实际项目中完整执行过该流程开发人员。应该清楚我们确定需求需要做持续做在文档做出软件概要设计和详细设计. 其实瀑布模型这样做要求在设计分析阶段尽可能多发现纰漏. 才能在开发阶段避免错误. 这有什么问题呢?&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;&lt;font size="2"&gt;相信很多人发现.这种要求在设计分析阶段就能发现整个软件开发周期要发现所有可能出现的问题. 基本是不可能的. 而很多关键的细节如果不到具体的实现阶段是不可能发现的&lt;/font&gt;. &lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;而由于这个模型.强制要求在编码开始之前要冻结规范文档. 也就是说很难在发布阶段将早起用户以及测试反馈的问题包含进来. 这样一来就降低开发团队响应客户需求的能力. 特别在发布周期要求比较高时.开发团队不能持续想客户交付有效功能点. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;至于测试则是整个编码结束后拖到整个开发周期的最后. 这就是集成化测试的开始阶段.为交付有效功能点和软件质量照成一定风险.&lt;/font&gt;&lt;/p&gt;  &lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;敏捷方法之Scrum&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;其实对用瀑布模型这种臃肿不堪.要求严格.而无法适应软件开发周期变化开发模型.业界渐渐可是兴起向更轻型的软件开发方法演化。在90年代时提出好几种轻型方法.强调专注于软件自我管理的团队. 提倡面对面的交流. 轻型文档和迭代发布等概念.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;最终这些方法论的缔造者. 其中包括Kent Beck、Martin Fowler,以及Ward Cunningham.组成敏捷联盟[Agile Alliance]。统一了敏捷软件开发的原则.从而就有了所谓后来的敏捷宣言[Agile Manifesto]&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;那什么是敏捷?&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;敏捷方法是试图通过小型的. 自我管理的团队用短小的合作发布周期来鼓励迭代式软件开发方法.软件的质量贯穿敏捷软件开发每一个阶段.且非常重要.,并提出很多关键的规则[例如: 结对编程. Test Driver Development测试驱动开发.,重构和持续集成]来保证能在每一个迭代周期内及早是的发现并及时相应消灭开发过程中出现错误. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;有哪些敏捷方法?&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;在敏捷方法提出理念下.衍生出了很多不同敏捷软件开发方法.类似这里马上会提到的Scrum、极限编程[EXtreme Programning XP]，测试驱动开发[Test Driver Development]，重构和持续集成.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Scrum大概是目前敏捷方法里面最出名. 至少也是各位实行听说敏捷方法最熟悉一个.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;那什么是Scrum?&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;其实冲本质上来说Scrum本身并不是所谓方法论.而是一组实践和为其过程参与者制定角色框架.其实它和其他敏捷方法是殊途同归.Scrum鼓励小型的,自我管理的团队在短的开发周期完成一系列定义良好的开发任务.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Scrum虽然提供了一个很有价值的框架. 但实际上和XP TDD不同的是它并没有定义明确可行的方法来管理开发出来的软件的质量.但其实这没有问题.Scrum的做法只是这个工作下放到Scrum团队每一个人.让开发团队自己决定选择实现什么样的质量控制实践.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;在这一点上和XP TDD提出关注项目的框架.Scrum则淡化这一部分.而是更多对管理代码质量做出很多实践规定.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Scrum周期如何执行的?&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="agile-scrum-1" border="0" alt="agile-scrum-1" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204150013303445.jpg" width="707" height="450" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;每一个Scrum项目周期都被看做一个Sprint.它用来标识完成一组功能开发所需要的时间.Sprint即从Scrum团队打算把精力放在一组功能上开始.而这组功能是由Scrum团队在源自于Product Backlog的计划阶段期间选择的. Produc Backlog其实是指一张关于软件开发所有可能功能点优先级列表.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;其中在计划阶段的末尾.所有从Product Backlog里选出来的功能都会被加入Sprint Backlog里执行跟踪.Sprint Backlog表示团队要开发的具体功能的细节.或者就是需求表现出来的功能点.一旦Sprint Backlog定义完成整个Sprint周期就开始.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;通畅在一个Sprint周期会持续30天.在Sprint期间团队成员会聚在一起检查工作进展并帮助每一个队员保持工作效率.而在这个Sprint末尾。在Sprint Backlog里定义的功能点将全部完成并可用.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;而这个过程就如上图.Scrum优缺点在那?&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Scrum相对传统瀑布模型.在构建真个开发活动前.思考并记录下来真个流程.,按照具体的计划实施，保持各项事务尽可能的有组织性.另外可以从整个Sprint周期来看到.Scrum模型的一个显著特点就是响应变化，它能够尽快地响应变化.使用传统的软件开发模型(瀑布模型、螺旋模型或迭代模型)。随着系统因素（内部和外部因素）的复杂度增加，项目成功的可能性就迅速降低:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="scrum4" border="0" alt="scrum4" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204150013312922.gif" width="491" height="371" /&gt;&lt;/p&gt;  &lt;p&gt;Scrum模型和传统模型的对比:&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="scrum5" border="0" alt="scrum5" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204150013315986.gif" width="480" height="372" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;在这个过程中.,与XP（eXtreme Programming，极限&lt;u&gt;&lt;strong&gt;编程&lt;/strong&gt;&lt;/u&gt;）不同，Scrum并没有提供核心的价值观与指导原则，也缺乏具体的实践方法，例如结队编程、测试驱动开发。Scrum仅仅规定了实施的基本流程与检查表，它是一个开放的管理框架，重心在于项目管理，而不是指导团队成员如何进行开发。它很灵活，能够适应大多数场景，也可以兼容并包地引入其他方法学所提倡的实践.这既是Scrum的优点.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;但在实际执行中也存在缺陷缺陷，使得它难以被实践。如果没有一位优秀的Scrum Master，而团队成员又缺乏自我组织和管理的能力，就会让开发过程变得混乱无法达到预期效果.&lt;/font&gt;&lt;/p&gt;  &lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;Scrum小结&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Scrum的核心在于迭代。团队首先浏览开发需求，考虑可用技术，并对自身技术及能力做出评估。然后共同确定构建功能的方案，并每日调整方法，以应对新的复杂问题、困难和出乎意料的情况。团队找出并选择最佳方案去完成任务。此创造性过程便是Scrum生产力的核心[1]。Scrum的所有实践就是围绕着一个迭代和增量的过程开展的&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;关于Scrum 可以参考:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;a href="http://books.google.com.hk/books/about/Succeeding_with_Agile.html?id=8IglA6i_JwAC" target="_blank"&gt;Succeeding with Agile:Software Development Using Scrum&lt;/a&gt;&lt;/font&gt;&lt;font face="Consolas"&gt; 中文名：《&lt;/font&gt;&lt;font face="Consolas"&gt;&lt;a href="http://www.book265.com/book1477179.html" target="_blank"&gt;Scrum敏捷软件开发&lt;/a&gt;&lt;/font&gt;&lt;font face="Consolas"&gt;》&amp;nbsp; 作者：&lt;/font&gt;&lt;a href="http://www.iasn.com.cn/page/jbkc/"&gt;&lt;font face="Consolas"&gt;Mike Cohn&lt;/font&gt;&lt;/a&gt;    &lt;br /&gt;&lt;font face="Consolas"&gt;《Scrum敏捷软件开发》是&lt;/font&gt;&lt;a href="http://www.iasn.com.cn/page/jbkc/"&gt;&lt;font face="Consolas"&gt;敏捷联盟&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;及&lt;/font&gt;&lt;a href="http://www.iasn.com.cn/page/jbkc/"&gt;&lt;font face="Consolas"&gt;Scrum联盟&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;创始人之一、&lt;/font&gt;&lt;a href="http://www.iasn.com.cn/page/jbkc/"&gt;&lt;font face="Consolas"&gt;敏捷估算&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;及计划的鼻祖Mike Cohn三大经典著作中影响最为深厚的扛鼎之作，也是全球敏捷社区中获得广泛肯定的企业敏捷转型权威参考&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;a href="http://books.google.com.hk/books/about/User_Stories_Applied.html?id=SvIwuX4SVigC" target="_blank"&gt;&lt;font face="Consolas"&gt;User Stories Applied&lt;/font&gt;&lt;font face="Consolas"&gt;:&lt;/font&gt;&lt;font face="Consolas"&gt;For Agile Software Development&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;&lt;a href="http://www.iasn.com.cn/page/jbkc/"&gt; &lt;/a&gt;&lt;/font&gt;&lt;font face="Consolas"&gt;中文名：《&lt;/font&gt;&lt;font face="Consolas"&gt;用户故事与敏捷方法&lt;/font&gt;&lt;font face="Consolas"&gt;》&amp;nbsp; 作者:Mike Cohn     &lt;br /&gt;《用户故事与敏捷方法》：敏捷大师Mike Cohn的软件需求方法圣经，小型团队(项目)不可或缺的敏捷开发宝典，亚马逊五星级长销图书，敏捷社区重点推荐，结合精髓和实例，充分演绎用户故事的智慧。&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.amazon.com/Agile-Project-Management-Microsoft-Professional/dp/073561993X" target="_blank"&gt;&lt;font face="Consolas"&gt;Ken Schwaber. Agile Project Management with Scrum[M].&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; 上海：世界图书出版公司，2007：&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;agile敏捷实践书中.&amp;lt;&amp;lt;Agile Estimating and Planning&amp;gt;&amp;gt; 的作者mike cohn3本著作最为经典. 其中04年这本&amp;lt;&amp;lt;User Stories Applied: For Agile Software Development&amp;gt;&amp;gt;算敏捷宣言最早一个版本. 09年&amp;lt;&amp;lt;Succeeding with Agile: Software Development Using Scrum&amp;gt;&amp;gt;则是深入敏捷实践推荐.&lt;/font&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/chenkai/aggbug/2443164.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/04/15/2443164.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/chenkai/archive/2012/04/07/2435874.html</id><title type="text">Silverlight 可能迎来新版本</title><summary type="text">一大早起来.在Windows phone Developer Blog就看到Silverlight 可能会迎来新版本的官方背景消息.我们知道.在2011年12月9日 Silverlight 官方团队不同如往常般低调的发布Silverlight 第5个正式版本[PS 详见:Silverlight 5 正式版发布了].发布这个版本时一直有很多行业资深人士预测在即将袭来的HTML 5大潮下. 原来与silverlight 竞争对手Flex被Adobe捐献给开源组织的命运逆转背景. Silverlight 5 也即将失去MS总体布局中于Flex对抗的战略地位.Silverlight 5 可能作为官方发</summary><published>2012-04-07T04:55:00Z</published><updated>2012-04-07T04:55:00Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><link rel="alternate" href="http://www.cnblogs.com/chenkai/archive/2012/04/07/2435874.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/archive/2012/04/07/2435874.html"/><content type="html">&lt;p&gt;&lt;font face="Consolas"&gt;一大早起来.在Windows phone Developer Blog就看到Silverlight 可能会迎来新版本的官方背景消息.我们知道.在2011年12月9日 Silverlight 官方团队不同如往常般低调的发布Silverlight 第5个正式版本[PS 详见:&lt;/font&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2011/12/10/2283064.html"&gt;&lt;font face="Consolas"&gt;Silverlight 5 正式版发布了&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;].发布这个版本时一直有很多行业资深人士预测在即将袭来的HTML 5大潮下. 原来与silverlight 竞争对手Flex被Adobe捐献给开源组织的命运逆转背景. Silverlight 5 也即将失去MS总体布局中于Flex对抗的战略地位.Silverlight 5 可能作为官方发布最后一个Silverlight 版本.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="silverlight5features" alt="silverlight5features" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204071255284894.jpg" border="0" height="328" width="604" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;而当时Silverlight 5发布后. 官方并没有向以往发布Silverlight版本一样借此机会提供该平台未来几年可能进一步版本发展计划做出说明. 对于Silverlight 5之后下一个版本Silverlight 6一直存在一些&lt;/font&gt;&lt;a href="http://www.zdnet.com/blog/microsoft/will-there-be-a-silverlight-6-and-does-it-matter/11180"&gt;&lt;font face="Consolas"&gt;传闻&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;. 官方对此没有做出任何回应[否认或确认消息的可靠性].而与此官方提供各方面支持直到2021年. 支持的时间相对以前任何一版本都要长. 这些&amp;#8221;异常举动&amp;#8220;加上官方不表态做法无不让很多人相信Silverlight 5 即将是一个终结点.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Well. 直到今天早上在Windows phone Developer Blog 上Larry Lieberma的话 似乎这种情形 偶然发生一些变化 &amp;#8220;&lt;strong&gt;Silverlight 将会引来新版本&lt;/strong&gt;&amp;#8221;.&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font color="#000000" face="Consolas"&gt;&lt;strong&gt;消息出处:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000" face="Consolas"&gt;&lt;strong&gt;Windows phone Developer Larry Lieberma Blog：&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://windowsteamblog.com/windows_phone/b/wpdev/archive/2012/04/05/windows-8-and-the-windows-phone-sdk-pt-2.aspx" target="_blank"&gt;&lt;font color="#000000" face="Consolas"&gt;&lt;strong&gt;Windows 8 and the Windows Phone SDK, pt. 2&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;在这篇文章中Larry Lieberma Blog 首先提到一些Windows phone 平台存在一些问题[直译]:&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font color="#000000" face="Consolas" size="2"&gt;&lt;strong&gt;&amp;#8220;Windows phone现在应用程序和游戏即将会运行下一个Windows phone主要版本上.微软应该做出这样承诺，否则将会失去很多开发人员对该平台的支持.目前情形让.NEt 和Windows phone 感到很困惑一个地方. 在HTML 5 即将到来,尤其最近官方也会推出Windows 8 OS 到来的大背景下. 他们是否还会使用WPF和Silverlight技术?&amp;#8221;&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;同时Larry Lieberma 也针对Windows 8平台中针对Windows phone SDK存在三个主要问题作了如下说明:&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font color="#000000" face="Consolas"&gt;[1] Xna Game Studio: 在尝试Windows 8 平台上安装Windows phone SDK 时用户将会因为XNA组件无法兼容而收到报错信息. 将导致XNA开发组件无法安装Windows 8开发环境中.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000" face="Consolas"&gt;[2]:Windows phone模拟器: 现在在Windows 8开发环境无法运行Windows phone模拟器.这使开发人员在该平台调试工作将难以进行&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000" face="Consolas"&gt;[3]NET 3.5 ：capability.exe和slsvcutil.exe将无法运行在Win 8平台，除非你单独安装NET 3.5 .&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;针对这些Windows phone 在Windows 8 平台存在问题.Larry Lieberma&amp;nbsp; 在其blog中给出一些答案.其中就涉及到 官方会发布下一个Silverlight消息,具体内容如下:&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font color="#000000" face="Consolas"&gt;[1]针对Windows phone SDK 7.1.1. 应该能够使开发员能够做如下两件事: 第一能够在让开发人员能够在低端Windows phone 256MB 设备上开发应用适配的应用. 第二.能够在当前Windows 8 平台能够正常使用使用Windows Phone SDK 开发应用.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000" face="Consolas"&gt;[2]Windows phone现在应用程序和游戏能够运行下一个Windows phone主要版本上.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000"&gt;&lt;font face="Consolas"&gt;[3]关于Silverlight For Windows phone 长远计划:&lt;strong&gt;请不要惊慌，在Windows 8上已经支持XAML， C#和VB.NET可以看做是Silverlight的一种进化。开发者所有的程序开发都将被转移到Windows 8上，换句话说，你所有的代码都能在Windows 8平台上很好的运行,微软承诺为开发者提供最好的应用程序兼容性，不管我们发布新的开发功能，我们都将最大限度的保证你目前的程序开发.&lt;/strong&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;在第三条中说道Silverlight 长远计划上. 从Larry Lieberma 可以解读出两个结论. 第一Silverlight 在HTML 5发展的背景下.自身战略空间已经在不断被压缩. 第二 在Windows phone 和Windows 8长远战略来讲.还是需要对Silverlight做出长远规划.这是否预示着Silverlight 会有下一个版本的可能? 而ZDNet上已经有人明确说官方将会迎来Silverlight 版本. 我觉得不够严谨.所以我在这篇文章标题上加了一个&amp;#8221;可能&amp;#8220;. 至于Silverlight 在第五个版本会如何. 只能让我们拭目以待吧&amp;#8230;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;最后给出Windows 8 Platform and Tool 一张图：&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="20119160144167" alt="20119160144167" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204071255285908.jpg" border="0" height="338" width="604" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://weibo.com/chenkaihome" target="_blank"&gt;&lt;font face="Consolas"&gt;欢迎各位到Sina微博参与讨论[@chenkaiHome]&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;原文应用:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://windowsteamblog.com/windows_phone/b/wpdev/archive/2012/04/05/windows-8-and-the-windows-phone-sdk-pt-2.aspx" target="_blank"&gt;&lt;font color="#000000" face="Consolas"&gt;Windows 8 and the Windows Phone SDK, pt. 2&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/chenkai/aggbug/2435874.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/04/07/2435874.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/chenkai/archive/2012/04/04/2432120.html</id><title type="text">Windows phone 应用开发[14]-调用WebBrowser</title><summary type="text">很久没有更新博客了.最近一直陷身在项目中难以有时间抽身梳理总结.关于博客确实很多想写的主题.节前大概草草 的梳理一下大概就有十几个主题.只能趁着放假的时间来逐渐把这批文章力所能及系统的更新出来. 主要涉及到我们团队现在Windows phone 项目开发中实际碰到一些问题和对应解决方案.如果想关注即时了解每天动态信息可以直接在Sina微博@chenkaiHome 沟通交流.在开始更新这批博文前.一直在顾虑先更新那个主题为好.回头一想索性就说说这半个月有些苦恼的Windows phone中处理 WebBrowser在我们项目中表现出来问题.话说去年.技术团队提出要优化产品在各个平台[IOS/An</summary><published>2012-04-04T09:42:00Z</published><updated>2012-04-04T09:42:00Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><link rel="alternate" href="http://www.cnblogs.com/chenkai/archive/2012/04/04/2432120.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/archive/2012/04/04/2432120.html"/><content type="html">&lt;p&gt;&lt;font face="Consolas"&gt;很久没有更新博客了.最近一直陷身在项目中难以有时间抽身梳理总结.关于博客确实很多想写的主题.节前大概草草 的梳理一下大概就有十几个主题.只能趁着放假的时间来逐渐把这批文章力所能及系统的更新出来. 主要涉及到我们团队现在Windows phone 项目开发中实际碰到一些问题和对应解决方案.如果想关注即时了解每天动态信息可以直接在&lt;/font&gt;&lt;a href="http://weibo.com/chenkaihome" target="_blank"&gt;&lt;font face="Consolas"&gt;Sina微博@chenkaiHome&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; 沟通交流.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;在开始更新这批博文前.一直在顾虑先更新那个主题为好.回头一想索性就说说这半个月有些苦恼的Windows phone中处理 WebBrowser在我们项目中表现出来问题.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;话说去年.技术团队提出要优化产品在各个平台[IOS/Android/WP7/QT]客户端开发业务流程.提出这个问题主要是为了把原来通用业务逻辑流程封装到能力更大的服务器端来做.各个客户端在通过WebView统一的形式调用.这样做目的.主要是解决原来各个客户端在业务升级后更新客户端版本时减少重新开发量.这样一来把核心的业务逻辑变动全部集中服务器端.需求变化自上而下传递过程中.在各个平台之间可以复用. 在每次更迭客户端版本时提升开发团队效率.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;最开始我们采用的方案焦点主要是考虑到WebView封装通用的业务逻辑流程涉及到与对应平台原生应用程序的交互问题上.所以也就理所当然有人提出跨平台移动框架PhoneGap[平台交互]+HTML 5[UI呈现]的处理方案. 原来我们设想真的很简单.也天真的认为PhoneGap+HTML 5搭配会把通用业务流程问题迎刃而解.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;首先.PhoneGap[PS参考:&lt;/font&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2011/12/31/2309035.html"&gt;&lt;font face="Consolas"&gt;Windows phone 应用开发[8]-体验PhoneGap&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;]作为移动跨平台框架.着重解决的问题是通过JavaScript实现跨平台API交互.并没有UI.页面还需要借助HTML 5效果.即使如此.也是难以和原生应用程序界面相媲美的.这就需要在使用过程中.要牺牲掉大量原生应用程序交互细节.用户体验上打了一个折扣.当然这和我们解决的核心问题做出牺牲还是值得.但问题各个平台兼容性需要调整各个平台适配问题大大出乎我们预估.而在性能差异上更是难以兼顾保证的.而对于初次使用PhoneGap团队解决这些问题所耗费的开发周期时间.却远大于开发Native Application原生应用时间还要长.这完全和使用初衷相背离. 其实问题只是换了一种形式存在. 我们只是从一个熟悉能够预估量的泥潭跳到另外完全未知泥潭中.不断尝试挣扎&amp;#8230;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;谈到这.说一个细节.类似在WebBrowser浏览器控件中.打开一个新窗口的问题.Android平台可以采用LoadUrl方法直接打开一个新窗体实现Js控制的页面跳转. 而目前Windows phone WebBrowser情况不支持在当前页打开新窗体.虽然可以通过InvokeJavaScript()放在LoadComplated方法中注入Js控制方法替换打开方式来实现. 但在实际调试中会发现.开发人员在C# 后台代码中调试JavaScript来说是一个挑战. 一来WebBrowser在注入和执行Js过程返回的错误或异常都是简单的代码80开头Code.而没有具体的堆栈信息. 这对找错和确认问题照成很大障碍.另外在C#后台代码处理JS缺乏有效的调试工具支持.这对PhoneGap封装出来页面复杂的Js调用或数据交互操作.照成一定难题.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;说白了.在PhoenGap中通过JS实现Windows phone应用平台交互主要体现在两个点上.第一就是通过在Js中调用：&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;&lt;font color="#000000" face="Consolas" size="2"&gt;【JAvaScript:】&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font color="#000000" face="Consolas" size="2"&gt;window.external.Notify(&amp;#8220;&amp;#8221;);&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;方法把页面交互数据通过WebBrowser控件SCriptNotify事件接收传递给原生应用程序. 另外一个点.就是可以在在Windows phone应用程序直接调用WEbBrowser控件InvokeScript()方法来调用JavaScript函数. 这两个方法.实现了PhoneGap数据传递和交互整个过程.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-03_233226" alt="2012-04-03_233226" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/20120404174138409.png" border="0" height="328" width="719" /&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;那在Windows phone应用程序使用WebBrowser有哪些常见需要解决的问题?&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;[1]异常处理.&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;well.这里不得不首先说在WebBrowser调用JavaSCript时需要处理的异常问题.Windows Phone 提供一个基于桌面版本的 Silverlight 的 &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/microsoft.phone.controls.webbrowser%28v=vs.92%29.aspx"&gt;&lt;font face="Consolas"&gt;WebBrowser&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; 控件，也就是说WindowsPhone 目前的WEbBrowser控件是基于Silverlight桌面版本的WebBrowser控件而来,但仍然有几处不同[&lt;/font&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/ff431795%28v=vs.92%29.aspx" target="_blank"&gt;&lt;font face="Consolas"&gt;WEbBrowser与Silverlight版本不同地方&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;].其中两个版本在开发最大不同主要有如下几点:&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;&lt;font color="#000000" face="Consolas" size="2"&gt;Windows phone WebBrowser控件与Silverlight 桌面版本的不同:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font color="#000000" face="Consolas" size="2"&gt;[1]Windows phone 版本相对Silverlight版本具有直接使用 IsolateStroage独立存储的权限&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font color="#000000" face="Consolas" size="2"&gt;[2]相对Silverlight在执行InvokeScript()方法时限制了执行范围必须是XAP 程序包相同的站点中加载的脚本.而Windows phone 解除该限制.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font color="#000000" face="Consolas" size="2"&gt;[3]在Windows phone版本时从独立存储加载的内容或使用 &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/zh-cn/library/microsoft.phone.controls.webbrowser.navigatetostring%28v=vs.92%29.aspx"&gt;&lt;font color="#000000" face="Consolas" size="2"&gt;NavigateToString(String)&lt;/font&gt;&lt;/a&gt;&lt;font color="#000000" face="Consolas" size="2"&gt; 方法加载的内容没有跨站点访问限制。&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;那么在Windows phone WebBrowser中调用JavaScript常见的可能出现的异常主要有两个,如下重现这两个异常情况.首先创建一个Windows Phone Application 应用程序. Mainpage.CS：&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;&lt;span class="lnum"&gt; 1: &lt;/span&gt;&lt;span class="rem"&gt;&amp;lt;!--ContentPanel - place additional content here--&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 2: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Grid&lt;/span&gt; &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;="ContentPanel"&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="1"&lt;/span&gt; &lt;span class="attr"&gt;Margin&lt;/span&gt;&lt;span class="kwrd"&gt;="12,0,12,0"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 3: &lt;/span&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;StackPanel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 4: &lt;/span&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;phone:WebBrowser&lt;/span&gt; &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;="ComponentContent_WB"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="450"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 5: &lt;/span&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;="ExcuteScript_BT"&lt;/span&gt; &lt;span class="attr"&gt;Content&lt;/span&gt;&lt;span class="kwrd"&gt;="Excute JavaScript"&lt;/span&gt; &lt;span class="attr"&gt;Margin&lt;/span&gt;&lt;span class="kwrd"&gt;="0,50,0,0"&lt;/span&gt; &lt;span class="attr"&gt;Click&lt;/span&gt;&lt;span class="kwrd"&gt;="ExcuteScript_BT_Click"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 6: &lt;/span&gt; &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;StackPanel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 7: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Grid&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;定义一个WebBrowser和Button按钮用来在页面加载完成后执行JavaSCripti函数事件.当然在执行JavaSCript需要设置WEbbrowser可以调用JS的. 设置&lt;/font&gt;IsScriptEnabled="True" &lt;font face="Consolas"&gt;BehindCode 如下:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;&lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="rem"&gt;// Constructor&lt;/span&gt;&lt;span class="lnum"&gt; 2: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; MainPage()&lt;span class="lnum"&gt; 3: &lt;/span&gt; {&lt;span class="lnum"&gt; 4: &lt;/span&gt; InitializeComponent();&lt;span class="lnum"&gt; 5: &lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.Loaded += &lt;span class="kwrd"&gt;new&lt;/span&gt; RoutedEventHandler(MainPage_Loaded);&lt;span class="lnum"&gt; 6: &lt;/span&gt; }&lt;span class="lnum"&gt; 7: &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt; 8: &lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; MainPage_Loaded(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;span class="lnum"&gt; 9: &lt;/span&gt; {&lt;span class="lnum"&gt; 10: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; navigateUrl = &lt;span class="str"&gt;@"http://www.163.com"&lt;/span&gt;;&lt;span class="lnum"&gt; 11: &lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.ComponentContent_WB.Navigate(&lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(navigateUrl, UriKind.RelativeOrAbsolute));&lt;span class="lnum"&gt; 12: &lt;/span&gt; }&lt;span class="lnum"&gt; 13: &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt; 14: &lt;/span&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ExcuteScript_BT_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;span class="lnum"&gt; 15: &lt;/span&gt; {&lt;span class="lnum"&gt; 16: &lt;/span&gt; &lt;span class="rem"&gt;//Button Client Event Excute InvokeJavaScript Method&lt;/span&gt;&lt;span class="lnum"&gt; 17: &lt;/span&gt; &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;span class="lnum"&gt; 18: &lt;/span&gt; {&lt;span class="lnum"&gt; 19: &lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.ComponentContent_WB.InvokeScript(&lt;span class="str"&gt;"DefineNoExistJSMethod"&lt;/span&gt;);&lt;span class="lnum"&gt; 20: &lt;/span&gt; }&lt;span class="lnum"&gt; 21: &lt;/span&gt; &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception se)&lt;span class="lnum"&gt; 22: &lt;/span&gt; {&lt;span class="lnum"&gt; 23: &lt;/span&gt; MessageBox.Show(&lt;span class="str"&gt;"Excute JavaScript Have Exception:"&lt;/span&gt; + se.Message);&lt;span class="lnum"&gt; 24: &lt;/span&gt; }&lt;span class="lnum"&gt; 25: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;调用通用网易站点.在加载页面完成后通过Button按钮执行一个不来就不存在JavaScript函数.执行效果如下"：&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-04_151451" alt="2012-04-04_151451" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/20120404174139800.png" border="0" height="484" width="268" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;因这个JavaScript函数不存在所以执行肯定报错.注意这里报错信息是以80020006为开头的UnKnowError如下:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-04_152050" alt="2012-04-04_152050" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204041741404846.png" border="0" height="257" width="644" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可见在堆栈的异常信息一栏中对JavaScripit提供的信息非常有限.这个Message代码为80020006.其实就是在当前应用程序执行范围找不到该JavaScript方法.另外一种情况恰恰相反.在执行已经定义JavaScript Function 函数出现的异常. 类似找到163.com站点中一个任意JAvaScript函数在后台方法调用: &lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;&lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="kwrd"&gt;function&lt;/span&gt; NTESAutoComplete ( inputElem, nextElem ) {&lt;span class="lnum"&gt; 2: &lt;/span&gt; &lt;span class="kwrd"&gt;var&lt;/span&gt; t = &lt;span class="kwrd"&gt;this&lt;/span&gt;;&lt;span class="lnum"&gt; 3: &lt;/span&gt; t._inputElem = inputElem;&lt;span class="lnum"&gt; 4: &lt;/span&gt; t._nextElem = nextElem;&lt;span class="lnum"&gt; 5: &lt;/span&gt; t._idName = &lt;span class="str"&gt;"login_auto_list"&lt;/span&gt;;&lt;span class="lnum"&gt; 6: &lt;/span&gt; t._className = &lt;span class="str"&gt;"login-auto-list"&lt;/span&gt;;&lt;span class="lnum"&gt; 7: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;注意InvokeScript方法在执行带有JAvaScript参数时. 参数传递是以String[]数组方式传递给JAvaScript函数.调用:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;&lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ExcuteScript_BT_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;span class="lnum"&gt; 2: &lt;/span&gt; {&lt;span class="lnum"&gt; 3: &lt;/span&gt; &lt;span class="rem"&gt;//Button Client Event Excute InvokeJavaScript Method&lt;/span&gt;&lt;span class="lnum"&gt; 4: &lt;/span&gt; &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;span class="lnum"&gt; 5: &lt;/span&gt; {&lt;span class="lnum"&gt; 6: &lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.ComponentContent_WB.InvokeScript(&lt;span class="str"&gt;"NTESAutoComplete"&lt;/span&gt;,&lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[]{&lt;span class="str"&gt;"NoExistElement"&lt;/span&gt;, &lt;span class="str"&gt;"NoExistStringArgument"&lt;/span&gt;});&lt;span class="lnum"&gt; 7: &lt;/span&gt; }&lt;span class="lnum"&gt; 8: &lt;/span&gt; &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception se)&lt;span class="lnum"&gt; 9: &lt;/span&gt; {&lt;span class="lnum"&gt; 10: &lt;/span&gt; MessageBox.Show(&lt;span class="str"&gt;"Excute JavaScript Have Exception:"&lt;/span&gt; + se.Message);&lt;span class="lnum"&gt; 11: &lt;/span&gt; }&lt;span class="lnum"&gt; 12: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;执行效果如下:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-04_162830" alt="2012-04-04_162830" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204041741414190.png" border="0" height="484" width="268" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;执行过程中InvokeScript得到异常 "An unknown error has occurred. Error: 80020101".而这个异常是在往往执行过程JavaScript内部错误引起.因在后台代码没有有效的工具.支持.所以对于JavaScript的错误是很难查找确认问题具体在那. 这个问题出现一般会有两种大概原因.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;第一点.在调用InvokeScript()是WebBrowser控件事件执行顺序.其实针对WEbBrowser控件.除了从&lt;a href="http://msdn.microsoft.com/en-us/library/ms602714%28vs.95%29"&gt;FrameworkElement&lt;/a&gt;类和&lt;a href="http://msdn.microsoft.com/en-us/library/ms609826%28vs.95%29"&gt;Control&lt;/a&gt;类继承了通用了UIElement属性和方法外.WEbBrowser重点扩展自身导航操作.类似其中三个比较中重要的方法.Navigating、Navigated 和 LoadCompleted事件.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;那么说到这 这个三个事件在实际操作执行顺序是?&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;&lt;p&gt;&lt;font color="#000000" face="Consolas" size="2"&gt;WebBrowser导航事件的执行顺序:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font color="#000000" face="Consolas" size="2"&gt;Navigating &amp;gt; Navigated &amp;gt; LoadCompleted&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Navigating是执行Navigate方法表示当前WEbBrowser正在执行加载URL操作、Navigated事件WebBrowser 控件成功导航后发生 和 LoadCompleted事件在 WebBrowser 控件成功加载内容后发生.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;如果在这种情况下.即使我们发现我们Codebehind中InvokeScript()调用JS没有问题.同时HTML JavaScript函数测试也没有问题.这就导致我们始终无法通过程序测试找到JS 报错80020101异常在那. 这是在后台代码调试JAvaScript最让人痛苦的地方.比如我们在如下方法掉用如上JavaScript函数:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Wb_Navigated(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, System.Windows.Navigation.NavigationEventArgs e) { Wb.InvokeScript(&lt;span class="str"&gt;"eval"&lt;/span&gt;, &lt;span class="str"&gt;"document.forms[0].submit();"&lt;/span&gt;); &lt;span class="rem"&gt;// Throws 80020101&lt;/span&gt; }&amp;nbsp; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; MainPage_MouseLeftButtonDown(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, MouseButtonEventArgs e) { Wb.InvokeScript(&lt;span class="str"&gt;"eval"&lt;/span&gt;, &lt;span class="str"&gt;"document.forms[0].submit();"&lt;/span&gt;); &lt;span class="rem"&gt;// Works&lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以发现.如果在Navigated事件触发时.即使我们后台代码调用和JavaScript函数都没有错误.依然还是爆出80020101的异常.这主要是因为DOM对象操作在页面触发Navigated事件还没有完全初始化.导致调用页面执行时出现异常.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;第二点.则是比较常见的即使需要对JavaSCript做一定修改.确保JS函数在执行时不会出错. 则这个80020101异常一般都会在如上两种情况下出现.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;[2]现实静态页面.&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;在WEbBrowser中.可能需要在没有网络情况下.需要在某一些情况下通过后台应用程序操作HTML页面. 而在Windows phone提供两种方式来加载本地静态的HTML页面.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;在Windows phone 中WEbBrowser中提供NavigateToString方法将 HTML 字符串置于 Web 浏览器控件中以便进行呈现.操作也是简单的:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;&lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; defineHtmlStr = &lt;span class="str"&gt;@"&amp;lt;html&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 2: &lt;/span&gt; &amp;lt;head&amp;gt;&lt;span class="lnum"&gt; 3: &lt;/span&gt; &amp;lt;script&amp;gt;&lt;span class="lnum"&gt; 4: &lt;/span&gt; function DefineExistFun(elementStr)&lt;span class="lnum"&gt; 5: &lt;/span&gt; {&lt;span class="lnum"&gt; 6: &lt;/span&gt; var getElems=document.getElementByTag(elementStr);&lt;span class="lnum"&gt; 7: &lt;/span&gt; alert(elementStr);&lt;span class="lnum"&gt; 8: &lt;/span&gt; }&lt;span class="lnum"&gt; 9: &lt;/span&gt; &amp;lt;/script&amp;gt;&lt;span class="lnum"&gt; 10: &lt;/span&gt; &amp;lt;body&amp;gt;&lt;span class="lnum"&gt; 11: &lt;/span&gt; &amp;lt;a href=" + &lt;span class="str"&gt;"http://chenkai.cnblogs.com"&lt;/span&gt; + &lt;span class="str"&gt;"&amp;gt;Test&amp;lt;/a&amp;gt;"&lt;/span&gt;&lt;span class="lnum"&gt; 12: &lt;/span&gt; + &lt;span class="str"&gt;"&amp;lt;/body&amp;gt;"&lt;/span&gt;&lt;span class="lnum"&gt; 13: &lt;/span&gt; + &lt;span class="str"&gt;"&amp;lt;/head&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;;&lt;span class="lnum"&gt; 14: &lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.ComponentContent_WB.NavigateToString(defineHtmlStr);&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;加载页面效果:&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-04_171035" alt="2012-04-04_171035" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204041741424963.png" border="0" height="484" width="268" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;另外一种方式.则是加载一定定制好静态HTML页面.使用 WebBrowser 控件在应用程序中显示已设置格式的静态内容。例如，开发人员可能希望在应用程序包中包含帮助文本，以便用户可以随时访问.创建一个静态HTML界面:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;&lt;span class="lnum"&gt; 1: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 2: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 3: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 4: &lt;/span&gt; &lt;span class="kwrd"&gt;function&lt;/span&gt; DefineExistFun(elementStr)&lt;span class="lnum"&gt; 5: &lt;/span&gt; {&lt;span class="lnum"&gt; 6: &lt;/span&gt; &lt;span class="kwrd"&gt;var&lt;/span&gt; getElems=document.getElementByTag(elementStr);&lt;span class="lnum"&gt; 7: &lt;/span&gt; alert(elementStr);&lt;span class="lnum"&gt; 8: &lt;/span&gt; }&lt;span class="lnum"&gt; 9: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 10: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 11: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt; &lt;span class="attr"&gt;href&lt;/span&gt;&lt;span class="kwrd"&gt;="http://chenkai.cnblogs.com"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Test&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;a&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 12: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 13: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="lnum"&gt; 14: &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;在执行第一步需要把该CreateProduct.html页面添加解决方案.设置引用资源为Content.需要向独立存储中添加存储静态文件.:&lt;/p&gt;&lt;p class="csharpcode"&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;&lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SaveFilesToIsoStore()&lt;span class="lnum"&gt; 2: &lt;/span&gt; {&lt;span class="lnum"&gt; 3: &lt;/span&gt; &lt;span class="rem"&gt;//These files must match what is included in the application package,&lt;/span&gt;&lt;span class="lnum"&gt; 4: &lt;/span&gt; &lt;span class="rem"&gt;//or BinaryStream.Dispose below will throw an exception.&lt;/span&gt;&lt;span class="lnum"&gt; 5: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] files = {&lt;span class="lnum"&gt; 6: &lt;/span&gt; &lt;span class="str"&gt;"CreateProduct.html"&lt;/span&gt;&lt;span class="lnum"&gt; 7: &lt;/span&gt; };&lt;span class="lnum"&gt; 8: &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt; 9: &lt;/span&gt; IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication();&lt;span class="lnum"&gt; 10: &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt; 11: &lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;false&lt;/span&gt; == isoStore.FileExists(files[0]))&lt;span class="lnum"&gt; 12: &lt;/span&gt; {&lt;span class="lnum"&gt; 13: &lt;/span&gt; &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; f &lt;span class="kwrd"&gt;in&lt;/span&gt; files)&lt;span class="lnum"&gt; 14: &lt;/span&gt; {&lt;span class="lnum"&gt; 15: &lt;/span&gt; StreamResourceInfo sr = Application.GetResourceStream(&lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(f, UriKind.Relative));&lt;span class="lnum"&gt; 16: &lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; (BinaryReader br = &lt;span class="kwrd"&gt;new&lt;/span&gt; BinaryReader(sr.Stream))&lt;span class="lnum"&gt; 17: &lt;/span&gt; {&lt;span class="lnum"&gt; 18: &lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] data = br.ReadBytes((&lt;span class="kwrd"&gt;int&lt;/span&gt;)sr.Stream.Length);&lt;span class="lnum"&gt; 19: &lt;/span&gt; SaveToIsoStore(f, data);&lt;span class="lnum"&gt; 20: &lt;/span&gt; }&lt;span class="lnum"&gt; 21: &lt;/span&gt; }&lt;span class="lnum"&gt; 22: &lt;/span&gt; }&lt;span class="lnum"&gt; 23: &lt;/span&gt; }&lt;span class="lnum"&gt; 24: &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt; 25: &lt;/span&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SaveToIsoStore(&lt;span class="kwrd"&gt;string&lt;/span&gt; fileName, &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] data)&lt;span class="lnum"&gt; 26: &lt;/span&gt; {&lt;span class="lnum"&gt; 27: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; strBaseDir = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;&lt;span class="lnum"&gt; 28: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; delimStr = &lt;span class="str"&gt;"/"&lt;/span&gt;;&lt;span class="lnum"&gt; 29: &lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[] delimiter = delimStr.ToCharArray();&lt;span class="lnum"&gt; 30: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;[] dirsPath = fileName.Split(delimiter);&lt;span class="lnum"&gt; 31: &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt; 32: &lt;/span&gt; &lt;span class="rem"&gt;//Get the IsoStore.&lt;/span&gt;&lt;span class="lnum"&gt; 33: &lt;/span&gt; IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication();&lt;span class="lnum"&gt; 34: &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt; 35: &lt;/span&gt; &lt;span class="rem"&gt;//Re-create the directory structure.&lt;/span&gt;&lt;span class="lnum"&gt; 36: &lt;/span&gt; &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; dirsPath.Length - 1; i++)&lt;span class="lnum"&gt; 37: &lt;/span&gt; {&lt;span class="lnum"&gt; 38: &lt;/span&gt; strBaseDir = System.IO.Path.Combine(strBaseDir, dirsPath[i]);&lt;span class="lnum"&gt; 39: &lt;/span&gt; isoStore.CreateDirectory(strBaseDir);&lt;span class="lnum"&gt; 40: &lt;/span&gt; }&lt;span class="lnum"&gt; 41: &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt; 42: &lt;/span&gt; &lt;span class="rem"&gt;//Remove the existing file.&lt;/span&gt;&lt;span class="lnum"&gt; 43: &lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (isoStore.FileExists(fileName))&lt;span class="lnum"&gt; 44: &lt;/span&gt; {&lt;span class="lnum"&gt; 45: &lt;/span&gt; isoStore.DeleteFile(fileName);&lt;span class="lnum"&gt; 46: &lt;/span&gt; }&lt;span class="lnum"&gt; 47: &lt;/span&gt;&amp;nbsp;&lt;span class="lnum"&gt; 48: &lt;/span&gt; &lt;span class="rem"&gt;//Write the file.&lt;/span&gt;&lt;span class="lnum"&gt; 49: &lt;/span&gt; &lt;span class="kwrd"&gt;using&lt;/span&gt; (BinaryWriter bw = &lt;span class="kwrd"&gt;new&lt;/span&gt; BinaryWriter(isoStore.CreateFile(fileName)))&lt;span class="lnum"&gt; 50: &lt;/span&gt; {&lt;span class="lnum"&gt; 51: &lt;/span&gt; bw.Write(data);&lt;span class="lnum"&gt; 52: &lt;/span&gt; bw.Close();&lt;span class="lnum"&gt; 53: &lt;/span&gt; }&lt;span class="lnum"&gt; 54: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;把需要展示的静态HTML页面在调用前需要存储到独立存储中.调用如下:&lt;/p&gt;&lt;p class="csharpcode"&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;&lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; MainPage_Loaded(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;span class="lnum"&gt; 2: &lt;/span&gt; { &lt;span class="lnum"&gt; 3: &lt;/span&gt; SaveFilesToIsoStore();&lt;span class="lnum"&gt; 4: &lt;/span&gt; ComponentContent_WB.Navigate(&lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;"CreateProduct.html"&lt;/span&gt;, UriKind.Relative)); &lt;span class="lnum"&gt; 5: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;成功加载的页面:&lt;p class="csharpcode"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-04-04_171035" alt="2012-04-04_171035" src="http://images.cnblogs.com/cnblogs_com/chenkai/201204/201204041741447863.png" border="0" height="484" width="268" /&gt;&lt;/p&gt;&lt;p&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;font face="Consolas"&gt;针对在Windows phone WEbBrowser中于JavaScript交付问题的问题出现的异常.在后台代码上处理是非常弱的.首先在CodeBehind中没有成行JS调试工具支持.这对不熟悉前段JavaSCript代码的开发人员来说是一个挑战. 另外一个问题就是一旦调用JavaScript出现异常情况.很难确认问题源头.这也大大影响开发效率.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;当然在WEbBroser还涉及到页面加载控制. 新窗口打开. 控制WEbBrowser页面缩放等问题.这里就不再一一赘述.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;关于本片源码详见:&lt;a href="https://github.com/chenkai/WebBrowser-Case-Windows-phone-Sample"&gt;https://github.com/chenkai/WebBrowser-Case-Windows-phone-Sample&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;源码下载:&lt;a href="http://files.cnblogs.com/chenkai/WebBrowserWP7Demo.rar"&gt;/Files/chenkai/WebBrowserWP7Demo.rar&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;如有问题可以Weibo上沟通交流:&lt;a href="http://weibo.com/chenkaihome"&gt;http://weibo.com/chenkaihome&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&amp;nbsp;&lt;/font&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/chenkai/aggbug/2432120.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/04/04/2432120.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/chenkai/archive/2012/01/30/2332133.html</id><title type="text">Windows phone 应用开发[13]-源码保护</title><summary type="text">关于源代码的保护.Windows phone在2010年10月份发布第一个RTM版本时. 相信国内最早进入Windows phone开发者都应该知道.在2010年11月Windows phone刚刚发布一个多月时.国外的一个网址为winmobile7.apphab.com的网站不知用什么方法获得了微软官方MarketPlace应用的直接下载地址，当时直接导致很多WP7的游戏和应用的.XAP安装包被泄露出去.当然那个时候应用量才3000多个.这对于刚刚推出Windows phone平台不久即遭到开发者知识产权保护漏洞.那时开发者还不多.但也在一定程度照成开发者对于微软平台安全性遭到质疑和不信任.</summary><published>2012-01-30T08:20:00Z</published><updated>2012-01-30T08:20:00Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><link rel="alternate" href="http://www.cnblogs.com/chenkai/archive/2012/01/30/2332133.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/archive/2012/01/30/2332133.html"/><content type="html">&lt;p&gt;&lt;font face="Consolas"&gt;关于源代码的保护.Windows phone在2010年10月份发布第一个RTM版本时. 相信国内最早进入Windows phone开发者都应该知道.在2010年11月Windows phone刚刚发布一个多月时.国外的一个网址为&lt;a href="https://ssl.zxproxy.com/browse.php?u=0d7e11861605Oi8vd2lubW9iaWxlNy5hcHBoYWIuY29tLw%3D%3D&amp;amp;b=6"&gt;winmobile7.apphab.com&lt;/a&gt;的网站不知用什么方法获得了微软官方MarketPlace应用的直接下载地址，当时直接导致很多WP7的游戏和应用的.XAP安装包被泄露出去.当然那个时候应用量才3000多个.这对于刚刚推出Windows phone平台不久即遭到开发者知识产权保护漏洞.那时开发者还不多.但也在一定程度照成开发者对于微软平台安全性遭到质疑和不信任.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Windows phone同样也是采用XAP安装包.而XAP其实可以通过强制修改文件格式转换成.rar.即可以通过解压工具获取XAP打包的DLL文件.通过逆向工程反编译工具.NET REflector是可以查看到源代码的.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;当然官方团队意识到这个问题.很快完善修补该漏洞.并对于.XAP安装包中的文件可被直接破解反编译的问题.对开发者提出可以使用Dotfuscator这类的代码混淆工具来保护自己的源代码.即使XAP在第三方情况被恶意破解泄露.但也不会至源码会被直接暴漏出来.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;针对这个问题微软官方很快就在2010年11月6日就宣布PreEmptive Solutions 合作推出 &lt;/font&gt;&lt;a href="http://www.preemptive.com/windowsphone7.html"&gt;&lt;font face="Consolas"&gt;Runtime Intelligence for Windows Phone&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;，这是一款面向 Windows Phone 7 的应用统计与分析工具.在2011年PreEmptive Solutions也相继推出专门针对Windows phone 应用程序源码混淆的免费工具&lt;a href="http://www.preemptive.com/windowsphone7.html" target="_blank"&gt;PreEmptive Protection For Windows phone 7&lt;/a&gt;.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;本篇将从Dotfuscator工具的角度来切入Windows phone应用的源码保护.&lt;/font&gt;&lt;/p&gt;  &lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&amp;lt;1&amp;gt;源码保护现状&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;源码保护这个已经不是什么新鲜主题..NET CLR的出现.衍生出Native Code和Managed Code[一说托管代码].执行在 .Net CLR 环境下的应用程序都是属于 Managed Code 的范围，而 Managed Code 在编译时会先编译成 MSIL (Microsoft Intermediate Language)，实际执行时交由 JIT (Just-In-Time) 编译成机器码之后执行，而由于架构上的变更，MSIL (也就是我们的 .Net exe、dll 档案等) 是比较容易被反编译.[该段落引用自&lt;/font&gt;&lt;a href="http://www.wikipedia.org/" target="_blank"&gt;&lt;font face="Consolas"&gt;Wikipedia&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;].NET代码被编译成IL代码，而不是ARM汇编.对于没有没进行源码混淆的应用程序Souce Code泄露的风险明显增大.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;其实对于SouceCode保护.并不仅是Windows phone平台所面临的问题. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Android平台采用的是Java语言开发.Jave和.NET平台一样.在各自环境执行时.并不会将代码直接便异常机器码.而是编译成一种叫java字节码的中间语言.一般的java程序编译完成后是一个完整的Jar包.Android则使用DEX。你可以通过诸如&lt;/font&gt;&lt;a href="http://code.google.com/p/dex2jar/"&gt;&lt;font face="Consolas"&gt;dex2jar&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;这样的工具将DEX文件转换成jar文件，然后使用诸如&lt;/font&gt;&lt;a href="http://java.decompiler.free.fr/?q=jdgui"&gt;&lt;font face="Consolas"&gt;JD-GUI&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;这样的工具反编译成Java代码。其风险和Windows Phone平台是类似的.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;iPhone/iPad使用Objective-C语言，并且将代码直接编译成机器码。因此反编译会有较大的困难。然而，市场上依然存在一些专业反向工程工具，例如&lt;/font&gt;&lt;a href="http://www.hex-rays.com/products/ida/index.shtml"&gt;&lt;font face="Consolas"&gt;IDA&lt;/font&gt;&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;目前主流平台对比可见.各个平台情况也是参差不齐.&lt;/p&gt;  &lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&amp;lt;2&amp;gt;Dotfuscator构建源码混&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;PreEmptive Solutions在没有和MS合作之前,Dotfuscator代码混淆工具还需要额外的申请.官方需要一到两天的审核时间.现在只需要到&lt;font face="Consolas"&gt;PreEmptive Solutions官网上找到Windows phone对应的主页:&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;PreEmptive Solutions For Windows phone：&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://www.preemptive.com/windowsphone7.html"&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;http://www.preemptive.com/windowsphone7.html&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;直接可以在当前页申请.:&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_1744424" border="0" alt="2012-01-29_1744424" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201301619454316.png" width="363" height="484" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;现在申请流程已经大大简化了.基本在申请成功后可以收到官方发过来的一封说明邮件如下:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_174950" border="0" alt="2012-01-29_174950" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201301619459365.png" width="644" height="171" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;邮件中提供对应的软件下载地址.对应S/N注册码,该S/N码会在软件安装提示输入:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_175729" border="0" alt="2012-01-29_175729" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201301619467446.png" width="609" height="202" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;安装完成后可以看到 切换并选择对应assemblies集合:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_181124" border="0" alt="2012-01-29_181124" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/20120130161946860.png" width="410" height="332" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;采用默认设置运行可见操作主页面&lt;/font&gt;:&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-30_143924" border="0" alt="2012-01-30_143924" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201301619475037.png" width="644" height="482" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;这时创建一个用于测试Windows Phone Application 命名为:SouceCodeProtect_Demo.在MainPage页面添加一个简单的TextBox和Button按钮.在按钮事件处理TextBox用户输入处理方法如下:&lt;/font&gt;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;span class="lnum"&gt;   1:  &lt;/span&gt;      &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Confirm_BT_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)  &lt;span class="lnum"&gt;   2:  &lt;/span&gt;        {  &lt;span class="lnum"&gt;   3:  &lt;/span&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; userInputText = &lt;span class="kwrd"&gt;this&lt;/span&gt;.UserInput_TB.Text.Trim();  &lt;span class="lnum"&gt;   4:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(userInputText))  &lt;span class="lnum"&gt;   5:  &lt;/span&gt;            {  &lt;span class="lnum"&gt;   6:  &lt;/span&gt;                MessageBox.Show(&lt;span class="str"&gt;"Please Input Basic Message Text!"&lt;/span&gt;);  &lt;span class="lnum"&gt;   7:  &lt;/span&gt;                &lt;span class="kwrd"&gt;this&lt;/span&gt;.UserInput_TB.Focus();  &lt;span class="lnum"&gt;   8:  &lt;/span&gt;            }  &lt;span class="lnum"&gt;   9:  &lt;/span&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt;  &lt;span class="lnum"&gt;  10:  &lt;/span&gt;                MessageBox.Show(&lt;span class="str"&gt;"You have been Input "&lt;/span&gt; + userInputText);  &lt;span class="lnum"&gt;  11:  &lt;/span&gt;        }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;运行效果如下:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-30_150439" border="0" alt="2012-01-30_150439" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201301619478450.png" width="268" height="484" /&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-30_150458" border="0" alt="2012-01-30_150458" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201301619481581.png" width="268" height="484" /&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;这时有了一个简单功能的Windows phone 应用程序.当然此处的目的为了测试演示的目的.这时如果我们要把这个应用程序上线官方MarketPlace.一般情况需要发布一个Release版本的XAP安装包.&lt;/font&gt;&lt;font face="Consolas"&gt;找到对应SouceCodeProtect_Demo.xap 强制修改xap为rar格式并解压可以见到XAP打包的文件列表如下:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-30_152053" border="0" alt="2012-01-30_152053" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201301619488026.png" width="707" height="154" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;此时当前DLL并没有任何代码保护措施. 如果当前发布的应用程序的XAP安装意外流出.或是遭到第三方强制破解.如果通过逆向工程反编译工具.NET REflector查看对应SourceCodeProtect_Demo.DLL可以看到:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-30_152605" border="0" alt="2012-01-30_152605" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201301619492826.png" width="625" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;我们的核心代码就会向密码中明文一样在没有任何保护措施的情况下被暴露出来.这时该如何保护自主知识产权的源代码呢.?&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;积极采用云平台.把重要逻辑放到云端:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;如果Windows phone在做客户端工作.你也可以考虑将部分重要的逻辑放到云端，例如Windows Azure之上，尤其是那些需要很多计算资源的逻辑，例如电影编码。手机是一个客户端，性能和存储空间都有限，有部分功能不适用于在手机上进行。事实上，Windows Phone自带的一部分功能，例如朗读文本，就需要通过微软的云服务才能完成。将逻辑放在云端还有一个好处就是，各种各样的客户端都能够通过访问服务的方式使用该功能，而不需要针对每个客户端写专门的代码。像部署在Windows Azure这样的云平台上的服务，客户端无法直接取得程序，只能通过服务暴露出的接口间接地访问云端的程序逻辑，因此也不存在反编译问题。当然，这样做也有坏处，例如可能需要用户支付网络流量相关费用，而且有时候网络传输可能有点慢.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;使用高级编程语言特性:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;C#这样的语言有一些高级语言功能，例如lambda expression和yield return。使用这样的功能不仅使得写代码变得方便，同时也会增加逆向工程反编译的难度。因为很多使用高级语言功能撰写的代码会在编译时由编译器自动转化成一些比较繁琐，读起来比较累的代码。大多数逆向工程反编译工具只能产生这些由编译器生成的代码，而看不到你的原始代码。&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;使用源代码混淆工具:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;当然从成本和开发者可控的角度而言.通常的做法就是版本发布后考虑将源代码进行混淆。这会使得反向工程后的源代码很难被读懂。在.NET平台上，可以使用诸如&lt;/font&gt;&lt;a href="http://www.preemptive.com/products/dotfuscator/overview"&gt;&lt;font face="Consolas"&gt;Dotfuscator&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;这样的工具.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;如何使用Dotfuscator工具执行源代码混淆操作?&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;...&lt;/font&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/chenkai/aggbug/2332133.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/30/2332133.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/chenkai/archive/2012/01/29/2331263.html</id><title type="text">Windows phone 应用开发[12]-Pex 构建自动化白盒测试[下]</title><summary type="text">本篇承接于上篇Windows phone 应用开发[11]-Pex 构建自动化白盒测试[上] .大概了解Pex作为自动化白盒测试工具工作方式.以及提出参数化单元测试的概念.为开发人员减少手动编写大量独立路径下单元测试时间.Pex允许开发人员编写单独的参数化测试方法，并根据测试方法的逻辑分支自动生成测试数据及Assert语句。虽然开发人员还是需要手动编写单元测试，但是Pex可以确保对代码进行了充分的...</summary><published>2012-01-29T08:42:00Z</published><updated>2012-01-29T08:42:00Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><link rel="alternate" href="http://www.cnblogs.com/chenkai/archive/2012/01/29/2331263.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/archive/2012/01/29/2331263.html"/><content type="html">&lt;p&gt;&lt;font face="Consolas"&gt;本篇承接于上篇&lt;/font&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/19/2327580.html"&gt;&lt;font face="Consolas"&gt;Windows phone 应用开发[11]-Pex 构建自动化白盒测试[上]&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; .大概了解Pex作为自动化白盒测试工具工作方式.以及提出参数化单元测试的概念.为开发人员减少手动编写大量独立路径下单元测试时间.Pex允许开发人员编写单独的参数化测试方法，并根据测试方法的逻辑分支自动生成测试数据及Assert语句。虽然开发人员还是需要手动编写单元测试，但是Pex可以确保对代码进行了充分的测试.并能通过Pex自动修复Bug.添加测试项目.其中的Moles组件可用于模拟框架中包括静态成员在内的几乎所有成员，大幅提高了对测试的支持程度.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;本篇来探索一些Pex 在Windows phone Application应用程序中使用.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;首先在Visual Studio 2010中构建一个Windows phone 应用程序BasicWinPhoneComponent_Demo.并实现一个简单分类列表显示.Well.定义一个标准的ViewModel执行数据绑定.&amp;#160;&amp;#160; Viewmodel代码如下:&lt;/font&gt;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;span class="lnum"&gt;   1:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MainPage_ViewModel:BasicViewModel  &lt;span class="lnum"&gt;   2:  &lt;/span&gt;    {  &lt;span class="lnum"&gt;   3:  &lt;/span&gt;        ObservableCollection&amp;lt;CatalogInfo&amp;gt; catalogInfoCol = &lt;span class="kwrd"&gt;new&lt;/span&gt; ObservableCollection&amp;lt;CatalogInfo&amp;gt;();  &lt;span class="lnum"&gt;   4:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; ObservableCollection&amp;lt;CatalogInfo&amp;gt; CatalogInfoCol  &lt;span class="lnum"&gt;   5:  &lt;/span&gt;        {  &lt;span class="lnum"&gt;   6:  &lt;/span&gt;            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.catalogInfoCol; }  &lt;span class="lnum"&gt;   7:  &lt;/span&gt;            set  &lt;span class="lnum"&gt;   8:  &lt;/span&gt;            {  &lt;span class="lnum"&gt;   9:  &lt;/span&gt;                &lt;span class="kwrd"&gt;this&lt;/span&gt;.catalogInfoCol = &lt;span class="kwrd"&gt;value&lt;/span&gt;;  &lt;span class="lnum"&gt;  10:  &lt;/span&gt;                &lt;span class="kwrd"&gt;base&lt;/span&gt;.NotifyPropertyChangedEventHandler(&lt;span class="str"&gt;&amp;quot;CatalogInfoCol&amp;quot;&lt;/span&gt;);  &lt;span class="lnum"&gt;  11:  &lt;/span&gt;            }  &lt;span class="lnum"&gt;  12:  &lt;/span&gt;        }  &lt;span class="lnum"&gt;  13:  &lt;/span&gt;&amp;#160;  &lt;span class="lnum"&gt;  14:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; LoadCatalogInfoDemoData()  &lt;span class="lnum"&gt;  15:  &lt;/span&gt;        {  &lt;span class="lnum"&gt;  16:  &lt;/span&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.catalogInfoCol.Clear();  &lt;span class="lnum"&gt;  17:  &lt;/span&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.catalogInfoCol.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; CatalogInfo() { CatalogTitle=&lt;span class="str"&gt;&amp;quot;Music &amp;amp; Video&amp;quot;&lt;/span&gt;,CatalogContent=&lt;span class="str"&gt;&amp;quot;Base Catalog Title&amp;quot;&lt;/span&gt; });  &lt;span class="lnum"&gt;  18:  &lt;/span&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.catalogInfoCol.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; CatalogInfo() { CatalogTitle = &lt;span class="str"&gt;&amp;quot;Book &amp;amp; Libray&amp;quot;&lt;/span&gt;,CatalogContent=&lt;span class="str"&gt;&amp;quot;Basic Book&amp;quot;&lt;/span&gt; });  &lt;span class="lnum"&gt;  19:  &lt;/span&gt;        }  &lt;span class="lnum"&gt;  20:  &lt;/span&gt;     }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;在MainPage Code-Behind执行数据绑定代码如下:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt;   1:  &lt;/span&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; MainPage_ViewModel mainPage_ViewModel = &lt;span class="kwrd"&gt;null&lt;/span&gt;;  &lt;span class="lnum"&gt;   2:  &lt;/span&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; MainPage_Loaded(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)  &lt;span class="lnum"&gt;   3:  &lt;/span&gt;        {  &lt;span class="lnum"&gt;   4:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.mainPage_ViewModel == &lt;span class="kwrd"&gt;null&lt;/span&gt;)  &lt;span class="lnum"&gt;   5:  &lt;/span&gt;                &lt;span class="kwrd"&gt;this&lt;/span&gt;.mainPage_ViewModel = &lt;span class="kwrd"&gt;new&lt;/span&gt; MainPage_ViewModel();  &lt;span class="lnum"&gt;   6:  &lt;/span&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.mainPage_ViewModel.LoadCatalogInfoDemoData();  &lt;span class="lnum"&gt;   7:  &lt;/span&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.DataContext = mainPage_ViewModel;  &lt;span class="lnum"&gt;   8:  &lt;/span&gt;        }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;运行效果:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-21_112747" border="0" alt="2012-01-21_112747" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642199870.png" width="268" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;一个基础功能实现完成后.现在要对ViewModel中代码做基本的UT.安装完PEX之后直接右键点击可以看到如下操作选项Run Pex 和PEX:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_152753" border="0" alt="2012-01-19_152753" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642197079.png" width="378" height="225" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;首先Run Pex即时生成测试用例 如果是安装后.首次运行Run Pex 在Windows phone Application中.会提示:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_100304" border="0" alt="2012-01-19_100304" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642192967.png" width="540" height="181" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;该窗体提示选择当前构建UT所基于的测试框架.PEX的扩展允许下载并支持Nunit MBUnit、或Xunit.Net测试框架.当前根据官方说明PEX会自动检测当前应用程序类型.根据不同应用会在测试框架选择项中给出指定测试框架.当然针对Silverlight、Windows phone应用标准的还是Silverlight Unit Test FrameWork[SUTF]框架. 如果没有安装Silverlight Toolkit或是修改了默认的安装目录.这里还需要手动指定当前框架安装路径.在前几篇中提到SUTF&amp;#160; windows phone版本测试框架需要两个核心的DLL:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;//Silverlight Unit Test FrameWork For Windows phone Version DLL&lt;/span&gt;  &lt;span class="lnum"&gt;   2:  &lt;/span&gt;Microsoft.Silverlight.Testing.dll  &lt;span class="lnum"&gt;   3:  &lt;/span&gt;Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以把该DLL文件拷贝到一个独立的目录下并初始化路径:.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_105212" border="0" alt="2012-01-19_105212" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642204952.png" width="540" height="181" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;点击Ok 出现问题提示无法Assembly Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll 这个DLL. 在目录中删除掉该DLL.点击OK.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-21_121337" border="0" alt="2012-01-21_121337" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642204146.png" width="488" height="177" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;PEX 目前需要单独解析DLL.需要重新指定Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll文件映射.PEX自动解析成功后 Run PEX在创建测试用例过程中出现异常:.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_100545" border="0" alt="2012-01-29_100545" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642218639.png" width="644" height="220" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;谈到这个问题.这里有必要解释一下Run Pex和Pex-&amp;gt;Create Parameterized Unit Test 两种运行Pex方式之间的区别.如果独立运行Run Pex 选项操作时我们能发现它没有像Pex-&amp;gt;Create Parameterized Unit Test 选项一样，需要独立创建一个单元测试项目.实现测试代码与宿主源代码之间的分离. 但当你执行Run Pex时你可以在Visual Studio 左下角状态栏下.可以看到Run Pex时其实把创建这个单元测试项目交给Pex内部来做.这一方面能够为测试用例构建驱动环境. 同时能够实现在无需开发人员维护测试用例代码情况下即时run Pex方式运行代码块的UT. 查找Bug并通过Pex自动修复.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;那二者区别在哪呢?&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;其实这个问题上篇&lt;/font&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/19/2327580.html"&gt;&lt;font face="Consolas"&gt;Windows phone 应用开发[11]-Pex 构建自动化白盒测试[上]&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; 中Pex构建参数化单元测试中提到.只是没有联系到run Pex. Pex-&amp;gt;Create Parameterized Unit Test 目的其实通过创建一个手写的参数化单元测试，Pex完全自动地分析代码，来决定相关的测试输入。其结果就是生成一个有着高度代码覆盖的传统单元测试.而Run Pex运行的Ut效果是即时.开发人员在无需维护测试代码前提下就能看到当前代码块Ut测试结果. 其实二者内部的原理并无差异. Run Pex其实在内部创建一个代码不可见的参数化单元测试项目在此基础之上构建测试用例.多次执行而获得即时测试结果.而Pex-&amp;gt;Create Parameterized Unit Test 则可见的把当前测试代码放到当前解决方案中.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;那现在遇到什么问题?&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Event：&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;&amp;quot;could not create an instance of BasicWinPhoneComponent_Demo.ViewModels.MainPage_ViewModel&amp;quot;&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Message：&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Click on 'Edit Factory', or, as a workaround, create a parameterized test that constructs the value from simpler values.&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以看到在构建单元测试用例时.无法创建MainPage_ViewModel实例.导致整个Run Pex在构建测试用例驱动环境时中断执行. 是否觉得上面步骤还不够具体详细. 因为我们始终在执行Run Pex时.不知道Pex内部是如何工作的? well.这时选中”Cound not Create an Instance …”测试Event事件:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_105525" border="0" alt="2012-01-29_105525" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642216720.png" width="644" height="221" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以看到在右栏Detail 下有一个Ignore操作.目的忽视当前错误继续在Pex创建ViewModels实例.:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_110034" border="0" alt="2012-01-29_110034" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/20120129164221134.png" width="598" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;点开折叠的节点.可以清晰看到内部Pex在执行Run Pex时内部执行整个流程步骤.可以看到Run PEx 时PEx 内部执行流程如下:&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Pex 执行流程:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Create Pex Project –&amp;gt; Create Test Project –&amp;gt; Create Visual Studio Unit TEst Silverlight Project …&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;首先创建一个Pex Project. 在Pex Project基础上创建一个普通的测试项目Test Project.其中这14操作中1-6步是用来创建测试项目.7-10是为当前测试项目添加构建测试用例驱动环境所需的引用.11-13步为当前测试项目添加指定的测试文件,. 带黄色长方块即是要忽视的操作&amp;quot;，执行:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_110524" border="0" alt="2012-01-29_110524" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642221803.png" width="644" height="215" /&gt;&lt;/p&gt;&lt;p&gt;需要基于一个独立的测试项目来承载测试用例.创建:&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_110646" border="0" alt="2012-01-29_110646" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642229361.png" width="644" height="480" /&gt;:&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;当执行Ignore操作第四步Create ViualStudio Unit Test Silverlight Project时.出错. 具体信息如下:&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Update result:         &lt;br /&gt;failed to generate project CSharp\Silverlight\Silverlight Unit Test Project.zip, Could not find template for new project&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以看到在创建普通单元测试项目时找不到对应Silverlight unit Test Framework Windows phone模板.well.这是查看Pex And Moles&lt;a href="http://research.microsoft.com/en-us/projects/pex/releasenotes.aspx" target="_blank"&gt;官方Realse Note&lt;/a&gt;记录,针对这个模板支持的问题可以找到如下说明:&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&lt;font style="font-weight: bold"&gt;v0.92.50603.1, 06/07/2010&lt;/font&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;    &lt;li&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Highlights&lt;/strong&gt;&lt;/font&gt;       &lt;ul&gt;        &lt;li&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Rex integrates Pex. &lt;/strong&gt;&lt;/font&gt;&lt;a href="http://research.microsoft.com/rex"&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Rex&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;&lt;strong&gt; is a tool that explores regular expression. It's algorithms have been integrated into the whitebox exploration engine of Pex. As a result, Pex is much smarter about generating strings that match a Regex.IsMatch call. &lt;/strong&gt;&lt;/font&gt;&lt;/li&gt;        &lt;li&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Preparable Types. It is possible to register a lazy setup method for a type. This method has to be static and will be invoked by Pex before any method of the given type is executed. This is a great way to mole parts of your system on demand. &lt;/strong&gt;&lt;/font&gt;&lt;/li&gt;        &lt;li&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font color="#000000"&gt;Silverlight and Silverlight for Windows Phone support (Alpha).&lt;/font&gt;&lt;/strong&gt; &lt;strong&gt;Right-click on any Silverlight project and hit 'Run Pex'. Pex will run your Silverlight code on the desktop CLR and start generating tests for it. The unit tests can be executed using the Silverlight unit test framework from&lt;/strong&gt;&lt;/font&gt;&lt;a href="http://silverlight.codeplex.com/"&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;http://silverlight.codeplex.com&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;/font&gt; &lt;/li&gt;      &lt;/ul&gt;    &lt;/li&gt;  &lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以看到在2010/7/6日版本更新的Realse Note中.提到这个版本已经支持Silverlight中运行Pex实现白盒自动化测试.Pex针对silverlight中.cs文件，默认使用VisualStudioUnitTestSilverlight框架。[assembly: PexAssemblySettings(TestFramework = &amp;quot;VisualStudioUnitTestSilverlight&amp;quot;)].很多在Silverlight 中做过Ut的同学应该知道.PEX会针对Silverlight应用程序会也会创建一个对应桌面版的Silverlight Project.而针对Silverlight Unit TEst FrameWork测试结果也会自动显示Windows PC端的IE浏览器中:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="图片1" border="0" alt="图片1" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642235282.png" width="644" height="324" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;那针对 Windows Phone Application应用程序呢? 针对这个问题质询官方Pex And Moles团队对Windows phone支持的建议.得到回复如下:&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt;&amp;quot;hi Peli:&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt;I am working on testing WP7 application.&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt;I found a very excellent tool &amp;quot;Silverlight Unit Test Framework&amp;quot; to do unit test.&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt;But, I want to do some automated tests for each function by inputting random data (like stress test).&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;There is a tool called &amp;quot;Pex&amp;quot; (&lt;/strong&gt;&lt;/font&gt;&lt;a href="http://research.microsoft.com/en-us/projects/pex/"&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;http://research.microsoft.com/en-us/projects/pex/&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt; ) that can do that things for me, but it seems not support WP7 right now.&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt;So, is there exist a tool like &amp;quot;Pex&amp;quot; can do stress test on WP7?&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt;Peli Reply:&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt;Hi kaichen,&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt;I am a developer from the Pex project. Unfortunately, Pex does not support Silverlight or Silverlight for Phone currently. We have no immediate plans to support this runtime in the short term.&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;You can post other questions on Pex at: &lt;/strong&gt;&lt;/font&gt;&lt;a href="http://social.msdn.microsoft.com/Forums/en-US/pex/threads/"&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;http://social.msdn.microsoft.com/Forums/en-US/pex/threads/&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt;.&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;font size="2"&gt;Cheers, Peli&lt;/font&gt; &lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;&amp;quot;&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;well. you see! &lt;strong&gt;Pex目前并不支持Windows phone 应用程序自动化白盒测试&lt;/strong&gt;.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;So.通过以上出现的问题.知道.Pex出现问题的地方在于.在Windows phone Application 中Run Pex时 Pex中并没有一个支持Windows Phone的framework作为extension 内置模板.导致创建测试应用程序失败.如果能够Run Pex能够在Silverlight和Windows phone 应用程序之间随意选择切换.就更好了.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;在&lt;/font&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/06/2315214.html"&gt;&lt;font face="Consolas"&gt;Windows phone 应用开发[9]-单元测试&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;中我提到采用默认的Visual Studio Test框架可以在建立测试用例完成后 指定测试用例输出的应用程序. 这是否能够提供一种解决Pex在Windows phone 中实现的思路呢,这点正如园友&lt;a href="http://home.cnblogs.com/u/215508/"&gt;sinodragon21&lt;/a&gt;在&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/06/2315214.html#2296092"&gt;Windows phone应用开发[9]-单元测试评论中&lt;/a&gt;提出想法一致:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;如果我们采用Pex自动化白盒测试工具.可以看到其实Pex的工作相对通过Windows phone Test Project模板创建单元测试项目. Pex的目的主要在于通过参数化单元测试构建测试用例.而目前的问题在于.在构建这些测试用例驱动环境时无法创建对应Windows phone 测试项目. so. 如果二者能够完美的结合.可以通过PEx自动探索分析代码逻辑流，自动产生测试数据和单元测试用例。这时我们需要需要为Pex写一个支持Windows Phone的framework作为extension（假定它叫做VisualStudioUnitTestWindowsPhoneSilverlight），在&amp;quot;Run Pex&amp;quot;时可以选择该framework，最后生成XXX.Tests是Windows Phone工程，而不是PC版的silverlight工程.使其Pex通过SUTF测试结果能够在Windows phone模拟器中输出.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;这时首先在Solution中添加一个Windows phone Test project 测试项目 命名为BuildCompontentDemo.Tests.该模板可以通过在Online Template中搜索Windows phone Test找到:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_141506" border="0" alt="2012-01-29_141506" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642236428.png" width="644" height="446" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;创建完成手动添加Silverlight unit Test Framework框架两个核心DLL的引用:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_141818" border="0" alt="2012-01-29_141818" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642247018.png" width="431" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;well.这时找到源程序BasicWinPhoneCompontent_Demo.中ViewModel 通过Pex-&amp;gt;Create Parameterized Unit Test 选项对应参数化测试用例.输出把该用例代码指定输出到对应的刚刚创建的Windows phone TEst Project 上BuildCompontentDemo.Tests中来:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_114244" border="0" alt="2012-01-29_114244" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642241511.png" width="644" height="215" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;在Add New Test Project中可以看到Pex只能创建自己内置模板内对应Windows phone Test Project .而无法想普通测试的方式在建立测试用例后可以指定测试用例代码输出项目类似:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_142616" border="0" alt="2012-01-19_142616" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642252972.png" width="577" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Pex并没有暴露类似Visual Studio默认带有测试框架可以指定测试用例输出项目的的操作. so. 针对这个思路目前基于现有的Windows phone测试模板还是一条Dead Way.问题还是在于Pex自身.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;well.至此问题已经非常明朗.如果要在Windows phone 采用PEX自动化白盒工具构建单元测试.问题还是集中Pex自身.从开发者角度来说基本是无法行通的.至少从目前尝试的角度没有行通.当然也欢迎其他的园友有好的思路和想法均可以评论中提出.共同探讨实践.但是作为开发者单一从使用工具的角度来说.这些工作并不适合寻求所谓的”突破”。因为官方在构建PEx版本时就没有打算支持Windows Phone的运行时.而目前的问题多集中于Pex自身.所以这些工作应该官方官方团队来做. 如果执意使用该工具.在我看来Pex所有带来的自动化的简便.远大于解决当前问题付出代价要高,这样的性价比远比另寻其他工具要来的简便实在.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;即使解决该问题.也难免在团队协作推广和使用过程遇到问题.光有流程和意识,而在实践中缺乏必要可控方法是很难推广和落地一项新技术的.当然这里更没有探讨所谓的成本,所以关于PEX在Windows phone自动化白盒测试推荐各位以尝试探索的精神去解决.并不推荐在实际项目推广应用.前提是解决该问题,但PEX在自动化白盒测试中设计理念还是值得深入理解的。&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/font&gt; &lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;如上真实记录Pex在Windows phone探索过程.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;当然官方也给出一些关于PEX很有意思一个应用Pex4Fun:&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;font size="2"&gt;&lt;strong&gt;Pex4Fun在线地址:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;&lt;strong&gt;Pex4Fun Online Demo :&lt;/strong&gt;&lt;/font&gt;&lt;a href="http://pex4fun.com/"&gt;&lt;font size="2"&gt;&lt;strong&gt;http://pex4fun.com/&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-29_161912" border="0" alt="2012-01-29_161912" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642253005.png" width="537" height="354" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Pex4Fun这个应用是微软研究院.推出一款Web通过C# /VB/F#语言在线编程.其实你也应该能看出来这里用到Pex那一部分.Pex为何能够自动化建立白盒的UT.最终一点就是PEX能够完全自动地分析代码行为，来决定相关的测试输入.有了PEX作支撑这就不难理解这个在线编译工具强大了吧.当然针对Pex4Fun也推出对应Windows phone 应用:&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Pex4Fun For Windows phone：&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Pex4Fun :&lt;a href="http://www.windowsphone.com/en-US/apps/db980958-7c4a-e011-854c-00237de2db9e"&gt;http://www.windowsphone.com/en-US/apps/db980958-7c4a-e011-854c-00237de2db9e&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2fa104fe-26a2-416f-8d7c-67336dd2f46c" border="0" alt="2fa104fe-26a2-416f-8d7c-67336dd2f46c" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642254990.png" width="292" height="484" /&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="779ae31b-6675-47d1-8f79-0b7e6ea37f00" border="0" alt="779ae31b-6675-47d1-8f79-0b7e6ea37f00" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642263071.png" width="292" height="484" /&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="0017871e-dd1b-4553-a98a-0b94e6d34636" border="0" alt="0017871e-dd1b-4553-a98a-0b94e6d34636" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201291642266692.png" width="292" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;同类型的应用目前在Windows phone平台很少见.原来我在查看应用MSDN Library Reader就考虑到.如果能够在手机应用C#多种语言实现随时随意写Code.同时随时随顶在手机编译运行.该多么Cool.果不其然.Pex4Fun就做了这样的工作.它类似2012年初微软推出Visual Studio开发人员成就系统.可以在线写代码赚取积分进入排行榜.另外不得不说的是.里面还有各种各样的考题和考题对应的需求说明文档.这对开发人员来说真的很不错的一个应用.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Pex4Fun是目前唯一Pex在Windows phone以功能形式出现的应用.但我一直很疑惑该应用在使用Pex功能是如何实现的.? 如果是纯客户端意义.倒觉得意义不大.但该项目非开源.so并不知内部其实现过程.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;关于Pex在Windows phone构建白盒自动化测试整个过程如上.如有疑问请在评论提出.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;本篇演示的源代码下载地址:&lt;a href="http://files.cnblogs.com/chenkai/BasicWinPhoneComponent_Demo.rar"&gt;/Files/chenkai/BasicWinPhoneComponent_Demo.rar&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/chenkai/aggbug/2331263.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/29/2331263.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/chenkai/archive/2012/01/19/2327580.html</id><title type="text">Windows phone 应用开发[11]-Pex 构建自动化白盒测试[上]</title><summary type="text">昨天一位园友sinodragon21在Windows phone应用开发[9]-单元测试评论中.提出关于Windows phone 单元测试中能否使用微软的Pex自动化生成工具生成单元测试用例.和单元测试质量即代码覆盖率统计问题.很有价值. 针对这两个问题.首先需要解释.关于Windows phone 中单元测试现状.针对Windows phone应用程序Unit Test 官方并没有在IDE提...</summary><published>2012-01-19T10:59:00Z</published><updated>2012-01-19T10:59:00Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><link rel="alternate" href="http://www.cnblogs.com/chenkai/archive/2012/01/19/2327580.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/archive/2012/01/19/2327580.html"/><content type="html">&lt;p&gt;&lt;font face="Consolas"&gt;昨天一位园友&lt;/font&gt;&lt;a href="http://home.cnblogs.com/u/215508/" target="_blank"&gt;&lt;font face="Consolas"&gt;sinodragon21&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;在&lt;/font&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/06/2315214.html#2296092" target="_blank"&gt;&lt;font face="Consolas"&gt;Windows phone应用开发[9]-单元测试评论中&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;.提出关于Windows phone 单元测试中能否使用微软的Pex自动化生成工具生成单元测试用例.和单元测试质量即代码覆盖率统计问题.很有价值.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;针对这两个问题.首先需要解释.关于Windows phone 中单元测试现状.针对Windows phone应用程序Unit Test 官方并没有在IDE提供对应的测试框架,目前开发者社区使用比较广泛框架是MS Windows phone 产品组&lt;/font&gt;&lt;a href="http://www.jeff.wilcox.name/" target="_blank"&gt;&lt;font face="Consolas"&gt;Jeff.wilcox&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;维护的Silverlight Unit Test Framework[SUTF] Windows phone版本.详见Blog:&lt;/font&gt;&lt;a href="http://www.jeff.wilcox.name/2010/05/sl3-utf-bits/"&gt;&lt;font face="Consolas"&gt;Updated Silverlight Unit Test Framework bits for Windows Phone and Silverlight 3&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt; . 但这个版本始终作为个人形式对开发者发布.并没有以正式的官方渠道向Windows phone开发者推送，所以官方对此并没有提供指定的维护和开发者社区支持.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;至此官方也就没有提供自动化测试工具道理. 类似Android 平台自动化Monkeyrunner之外还有更多选择.而Windows phone自动化测试只能靠开发者自己想办法.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;那么关于SUTF 中Code Converage代码覆盖率呢? 针对这个问题 特别咨询SUTF WP版本维护作者Jeff.Wilcox.得到回复信息如下:&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;ul&gt;     &lt;li&gt;       &lt;p&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;HI Jeff,              &lt;br /&gt;how to take code coverage from SilverLight Unit test framework for WP7?&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;     &lt;/li&gt;   &lt;/ul&gt;    &lt;ul&gt;     &lt;li&gt;       &lt;p&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;jeffwilcox Reply:&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;        &lt;p&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;Code coverage is not available, it was a feature that was cut before              &lt;br /&gt;shipping for 2010 from the toolkit.&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;     &lt;/li&gt;   &lt;/ul&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;在2010年发布SUTF版本时已经去掉对Code Converage支持. so.既然如此是否真的就此定论了.? Now 现在提到Pex and Moles.还是不甘心.打算动手在应用程序中亲自验证.本篇并不打算立即采用Pex在SUTF进行验证.有必要系统了解Pex and Moles.&lt;/font&gt;&lt;/p&gt;  &lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&amp;lt;1&amp;gt;构建Pex测试环境&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Well.关于Pex And Moles其实可以分为两个部分.其一Pex-全称是[Program EXploration]是微软研究院的一个关于白盒测试自动生成工具.原来开发人员只能通过指定路径编写独立的测试用例.PEX通过分析代码来自动生成测试用例。对于程序里面的每一行代码，PEX都会尽可能地生成合适的输入值来达到提高覆盖率的目标。同时PEX还会分析代码中的分支，生成覆盖更多分支的测试代码（输入数据）；PEX在执行代码的同时会监控和分析代码的控制流和数据流，了解程序的行为。每运行完单一个测试以后，PEX会选择一条在前面的测试中没有覆盖到的路径，并且尝试执行它.本篇主要来讲到的是PEX.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="pex-testing" border="0" alt="pex-testing" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859127552.png" width="204" height="125" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;PEX自动化生成用例并执行UT返回测试结果的过程.大大减少开发人员手动编写大量测试用例情况发生.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;关于PEX and Moles可通过如下链接了解更多:&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;PEX And Moles：&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://research.microsoft.com/en-us/projects/pex/" target="_blank"&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Pex and Moles - Isolation and White box Unit Testing for .NET&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Download Page:          &lt;br /&gt;&lt;/strong&gt;&lt;a href="http://research.microsoft.com/en-us/projects/pex/downloads.aspx" target="_blank"&gt;&lt;strong&gt;Pex and Moles – Download Page Link&lt;/strong&gt;&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Get Start Online PDF Document:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://research.microsoft.com/en-us/projects/pex/digger.pdf"&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;http://research.microsoft.com/en-us/projects/pex/digger.pdf&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;找到下载页面.PEX现在有3个Flavor，支持2个版本的Visual Studio，分别是VSTS2010和VSTS2008，这3个版本的PEX在功能上存在区别，这主要因为下载受众群体不同,一般用户只能使用到PEX功能.本篇所有演示都是基于Visual Studio 2010. 基于MSDN订阅权限下载PEX And Moles完整版本.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-18_190501" border="0" alt="2012-01-18_190501" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859129155.png" width="742" height="168" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;安装完成后.可以打开Visua Studio 立即创建一个Console Application命名为BasicConsolePexComponent_Demo,在此先不要把焦点放在PEX原理实现上.来快速体验一下PEX.首先需要在Program类中顶一个转换字符串的方式.作为测试用例的宿主程序.创建如下:&lt;/font&gt;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 2: &lt;/span&gt; &lt;span class="rem"&gt;/// Test Case Convert String To Upper&lt;/span&gt;  &lt;span class="lnum"&gt; 3: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 4: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;inputString&amp;quot;&amp;gt;Input String&amp;lt;/param&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 5: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;Converted String&amp;lt;/returns&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 6: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ConvertStringToUpper(&lt;span class="kwrd"&gt;string&lt;/span&gt; inputString)  &lt;span class="lnum"&gt; 7: &lt;/span&gt; {  &lt;span class="lnum"&gt; 8: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; convertString = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;  &lt;span class="lnum"&gt; 9: &lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (!&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(inputString))  &lt;span class="lnum"&gt; 10: &lt;/span&gt; {  &lt;span class="lnum"&gt; 11: &lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[] convertCharArray = inputString.ToCharArray();  &lt;span class="lnum"&gt; 12: &lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (convertCharArray.Length &amp;gt; 0)  &lt;span class="lnum"&gt; 13: &lt;/span&gt; {  &lt;span class="lnum"&gt; 14: &lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; count = 0;  &lt;span class="lnum"&gt; 15: &lt;/span&gt; &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;char&lt;/span&gt; currentChar &lt;span class="kwrd"&gt;in&lt;/span&gt; convertCharArray)  &lt;span class="lnum"&gt; 16: &lt;/span&gt; {  &lt;span class="lnum"&gt; 17: &lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (count % 2 == 0)  &lt;span class="lnum"&gt; 18: &lt;/span&gt; convertString += currentChar;  &lt;span class="lnum"&gt; 19: &lt;/span&gt; }  &lt;span class="lnum"&gt; 20: &lt;/span&gt; }  &lt;span class="lnum"&gt; 21: &lt;/span&gt; }  &lt;span class="lnum"&gt; 22: &lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; convertString;  &lt;span class="lnum"&gt; 23: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;well一般情况下.关于如何建立单元测试应用程序,一般如果没有PEX之前.可能作为开发人员更多的是根据该方法实现.创建一个新的Test测试项目.构建对应测试用例.实现对该方法的UT.其实这个过程已经Visual Studio内置了这些工作已经自动创建.只需右键点击就能看到Create Unit Test选项:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_141603" border="0" alt="2012-01-19_141603" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859121946.png" width="376" height="251" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;点击后能发现.其实Create Unit TEst为了避免测试框架和测试用例污染源代码本身.一般情况要对单元测试用例和源代码执行分离.也就是创建一个新的单独测试项目.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_141211" border="0" alt="2012-01-19_141211" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859131913.png" width="577" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;此时在执行测试之前需要做一些设置点击Settings按钮:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_141311" border="0" alt="2012-01-19_141311" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859137420.png" width="577" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;需要设置创建默认文件以及对应测试类和测试方法名称.点击ok.如果没有设置对应测试项目名称会如下提示:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_141347" border="0" alt="2012-01-19_141347" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859131531.png" width="445" height="159" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;修改完成后开始创建.创建过程可能会有如下提示:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_141420" border="0" alt="2012-01-19_141420" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859137910.png" width="566" height="264" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;创建前提示主要提到两点.需要为测试项目BasiceConsolePexComponent_Demo设置InternalsVisible属性可用.这是设置其实内在的原因是.对一个组件或模块进行单元测试时.单元测试用例需要调用定义在测试组件或模块中的Internal成员对象时. 需要跨程序集访问.而Modifier的Internal类型成员默认设置仅限于当前程序集访问.而对宿主程序而言需要暴露给测试程序集调用.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;另外一点在很多情况下，我们需要将最终的程序集以强命名的形式发布。为此，我们修改Lib项目设置，开启&amp;quot;Sign the assembly”开关，并创建一个密钥文件.不能通过编译，具体的错误信息为：“Friend assembly reference 'Test' is invalid. Strong-name signed assemblies must specify a public key in their InternalsVisibleTo declarations.”,针对需要指定的不是程序名的强命名，而是指定对程序集进行签名时采用的公钥.把公钥指定到&lt;a href="http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx"&gt;InternalsVisibleToAttribute&lt;/a&gt;特性中即可.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;点击ok.看一下项目结构:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_143556" border="0" alt="2012-01-19_143556" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859142337.png" width="389" height="327" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;多了一个测试项目和该项对应Program方法测试类.now构建好了测试项目.在回到宿主程序Program类中对字符串转换操作的方法见一个UT.找到该方法名右键依然可见Create Unit Test选项点击看到:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_142616" border="0" alt="2012-01-19_142616" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859142304.png" width="577" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以看到针对方法做UT时会把该UT的应用程序的输出默认为刚才创建的测试项目:AutomationConsole.Test.点击ok.找到测试项目下ProgramProgramTestHelper类可以看到增加一个测试方法如下：&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 2: &lt;/span&gt; &lt;span class="rem"&gt;///A test for ConvertStringToUpper&lt;/span&gt;  &lt;span class="lnum"&gt; 3: &lt;/span&gt; &lt;span class="rem"&gt;///&amp;lt;/summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 4: &lt;/span&gt; [TestMethod()]  &lt;span class="lnum"&gt; 5: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ConvertStringToUpperTestConvertString_Test1()  &lt;span class="lnum"&gt; 6: &lt;/span&gt; {  &lt;span class="lnum"&gt; 7: &lt;/span&gt; Program target = &lt;span class="kwrd"&gt;new&lt;/span&gt; Program(); &lt;span class="rem"&gt;// TODO: Initialize to an appropriate value&lt;/span&gt;  &lt;span class="lnum"&gt; 8: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; inputString = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty; &lt;span class="rem"&gt;// TODO: Initialize to an appropriate value&lt;/span&gt;  &lt;span class="lnum"&gt; 9: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; expected = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty; &lt;span class="rem"&gt;// TODO: Initialize to an appropriate value&lt;/span&gt;  &lt;span class="lnum"&gt; 10: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; actual;  &lt;span class="lnum"&gt; 11: &lt;/span&gt; actual = target.ConvertStringToUpper(inputString);  &lt;span class="lnum"&gt; 12: &lt;/span&gt; Assert.AreEqual(expected, actual);  &lt;span class="lnum"&gt; 13: &lt;/span&gt; Assert.Inconclusive(&lt;span class="str"&gt;&amp;quot;Verify the correctness of this test method.&amp;quot;&lt;/span&gt;);  &lt;span class="lnum"&gt; 14: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以看到该测试方法命名依然采用默认命名方式.方法内代码实现关于调用Program类中字符串转换大写操作的方法ConvertStringToUpper. 分别定义三个变量的字.其实从变量名称完全可以看出这是一个默认的测试用例.要想改UT达到想做.只需修改对应变量参数的值来匹配.InputString作为方法参数输入.经过测试用例会会生成对应期望值和方法执行实际值.最后通过对期望值和实际比对获得对应测试结果.直接运行 可以看到测试结果如下:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_144542" border="0" alt="2012-01-19_144542" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859146416.png" width="752" height="189" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;well因为两个测试用例都没做了修改没有实际值传入所以都是Inconcluetive测试结果不确定.现在看看这种传统方式下一Visual Studio Unit TEst框架为主UT编写开发人员要重复做哪些工作.?首先要重复手动编写大量的UT测试用例.目的是在给定的方法中为每个执行路径手写独立测试. 而且针对这种无法避免的要创建一个独立的测试项目.其实在实际编码中.并不是所有模块都需要即时建立UT.可能需求发生变更.从开发人员角度来说创建一个笨重测试项目这意味更多精力发在测试代码维护上.可能我们更需要一种既能够创建对应测试项目同时也能即时看到当前版本Code UT效果.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Now.UT属于白盒测试的范畴.如果能够有一个很好白盒测试工具能够封装这些重复的行为.并能够重复执行UT测试用例.让开发人员从Ut的过多细节和维护中解放出来关注更核心的业务逻辑.Pex and moles就是这样的一个工具.&lt;/font&gt;&lt;/p&gt;&lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&amp;lt;2&amp;gt;Pex 构建白盒测试&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;虽然本篇幅没有核心焦点放到Pex实现原理上.但关于Pex and Moles其实分为两块整理官方原文翻译如下[直译]:&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;ul&gt;    &lt;li&gt;      &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Pex&amp;#160;&amp;#160; Pex 是一个 Visual Studio 外接程序，用于补充 .NET Framework 应用程序上的单元测试。 Pex 在 Visual Studio 代码编辑器中查找对应程序方法的输入和输出值。 PEx将这些值另存为将具有高代码覆盖率的小型测试套件。&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;/li&gt;    &lt;li&gt;      &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;Moles&amp;#160;&amp;#160; Moles 允许开发人员将任何 .NET 方法替换为委托。 Moles 通过使用 Detour 和 Stub 提供隔离来支持单元测试。 因为 Moles 在方法级别工作，所以当目标 API 不支持它时，它提供替代项进行模拟。 SharePoint 是一个受益于隔离的常见 API 示例，但不直接支持模拟。Moles 还可用于错误植入，因为它使得开发人员在测试下向代码中注入任意行为变得轻松.&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;/li&gt;  &lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Pex核心是给开发人员一个手写的参数化单元测试，Pex完全自动地分析代码，来决定相关的测试输入。其结果就是生成一个有着高度代码覆盖的传统单元测试，另外，Pex还会建议开发人员如何去修复所发现的Bug.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;安装完Pex and Moles工具后.打开Visual Studio 可以看到右键选项中多了:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_152753" border="0" alt="2012-01-19_152753" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859148891.png" width="378" height="225" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Run Pex 和Pex 下Create Parameterized Unit Tests两个可操作选项.针对Pex测试效果.首先在Programe类添加一个字符串合并操作方法代码如下:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 2: &lt;/span&gt; &lt;span class="rem"&gt;/// Test Case Spilt String And Merge Operator&lt;/span&gt;  &lt;span class="lnum"&gt; 3: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 4: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;firstname&amp;quot;&amp;gt;First Name&amp;lt;/param&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 5: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;param name=&amp;quot;lastname&amp;quot;&amp;gt;Last Name&amp;lt;/param&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 6: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;Merge String&amp;lt;/returns&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 7: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; SpiltStringToMerge(&lt;span class="kwrd"&gt;string&lt;/span&gt; firstname, &lt;span class="kwrd"&gt;string&lt;/span&gt; lastname)  &lt;span class="lnum"&gt; 8: &lt;/span&gt; {  &lt;span class="lnum"&gt; 9: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; mergeString = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;  &lt;span class="lnum"&gt; 10: &lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[] firstNameArray = firstname.ToCharArray();  &lt;span class="lnum"&gt; 11: &lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[] lastNameArray = lastname.ToCharArray();  &lt;span class="lnum"&gt; 12: &lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; count = 0;  &lt;span class="lnum"&gt; 13: &lt;/span&gt; &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;char&lt;/span&gt; currentChar &lt;span class="kwrd"&gt;in&lt;/span&gt; firstNameArray)  &lt;span class="lnum"&gt; 14: &lt;/span&gt; {  &lt;span class="lnum"&gt; 15: &lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (count % 2 == 0)  &lt;span class="lnum"&gt; 16: &lt;/span&gt; mergeString += currentChar + lastNameArray[count];  &lt;span class="lnum"&gt; 17: &lt;/span&gt; }  &lt;span class="lnum"&gt; 18: &lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; mergeString;  &lt;span class="lnum"&gt; 19: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;注意该方法的输入参数firstname和lastname在方法内都没有判断是否空字符串或是Null而且里面涉及字符数组的操作.针对该方法采用Pex方式执行UT操作.右键调集选中Run Pex 提示如下:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_153430" border="0" alt="2012-01-19_153430" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859159730.png" width="466" height="189" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;注意我们当前类是在Program类下.该类的签名如下:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt; 1: &lt;/span&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; Program  &lt;span class="lnum"&gt; 2: &lt;/span&gt; {  &lt;span class="lnum"&gt; 3: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;提示的意思当前类型不可见.无法通过Pex方式创建UT,需要把当前类的签名改成公开 虚类型即可:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Program  &lt;span class="lnum"&gt; 2: &lt;/span&gt; {  &lt;span class="lnum"&gt; 3: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;在来运行Run Pex 弹出执行 结果窗体如下:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_154740" border="0" alt="2012-01-19_154740" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859158825.png" width="644" height="184" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以看到Pex在没有创建一个独立单元测试项目和对应测试类情况.自动对当前方法进行白盒测试封装.运行测试109 Runs次.创建了7个测试用例. PEx会监视当前类，并且运行这个方法.执行多次测试.其中有三次测试失败的.并Sunmmary/Exception 提出具体测试参数和出现的异常信息.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;点击对应失败的测试用例.可以在右侧弹出对应异常堆栈详细信息.:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_155250" border="0" alt="2012-01-19_155250" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859157156.png" width="644" height="259" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;点击DEtails可以看到执行该测试用例的代码和对应异常信息:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_155427" border="0" alt="2012-01-19_155427" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859168202.png" width="644" height="279" /&gt;&lt;/p&gt;&lt;p&gt;在查看异常详情右侧窗口中.可以执行如下操作:&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_155609" border="0" alt="2012-01-19_155609" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859167090.png" width="644" height="38" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Save Test保存当前PEX的测试用例为普通单元测试用例.点击保存:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_155734" border="0" alt="2012-01-19_155734" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859166185.png" width="598" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;如果在此之前没有创建对应Pex测试项目会提示当前测试用例输出.或是提示创建一个新的测试项目:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_155905" border="0" alt="2012-01-19_155905" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859177547.png" width="644" height="215" /&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;上面Project Under Test是待测试的宿主项目.而下面是需要创建新的测试项目设置.点击OK创建一个新的测试项目.这里在RunPex时并没有强制开发人员强制建立一个新的测试项目.但是这里SAve 目的是在于如果觉得当前测试代码可以留存做以后回归测试.PEX也是支持测试代码保存的.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;add Precondition是用来通过Pex自动添加代码来避免错误的发生.而All Exception则允许次异常在当前应用程序中出现.send to如果你的项目采用TFS版本控制.sendto操作会吧所有信息发到文本或剪切板中.这里所有的信息包括Detail和STack Trace 如果TFS里配置WorkItem,PEX会自动发送对应的WorkItem中.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;well现在既然存在异常.通过Add PreCondition来通过Pex来修正.会看到如下菜单:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_160539" border="0" alt="2012-01-19_160539" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859179466.png" width="598" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;这个窗体中上半部分告诉开发人员PEX在当前会做哪些操作.操作会修改哪些方法等.下半部分则是PEX具体的添加的修复代码.可以看到对firstname输入参数因当前NullException异常所以添加了是否非Null的判断。点击Apply可以看到原来代码中添加一段判断代码 完整如下:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; SpiltStringToMerge(&lt;span class="kwrd"&gt;string&lt;/span&gt; firstname, &lt;span class="kwrd"&gt;string&lt;/span&gt; lastname)  &lt;span class="lnum"&gt; 2: &lt;/span&gt; {  &lt;span class="lnum"&gt; 3: &lt;/span&gt; &lt;span class="rem"&gt;// &amp;lt;pex&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 4: &lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (firstname == (&lt;span class="kwrd"&gt;string&lt;/span&gt;)&lt;span class="kwrd"&gt;null&lt;/span&gt;)  &lt;span class="lnum"&gt; 5: &lt;/span&gt; &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="str"&gt;&amp;quot;firstname&amp;quot;&lt;/span&gt;);  &lt;span class="lnum"&gt; 6: &lt;/span&gt; &lt;span class="rem"&gt;// &amp;lt;/pex&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 7: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; mergeString = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;  &lt;span class="lnum"&gt; 8: &lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[] firstNameArray = firstname.ToCharArray();  &lt;span class="lnum"&gt; 9: &lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[] lastNameArray = lastname.ToCharArray();  &lt;span class="lnum"&gt; 10: &lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; count = 0;  &lt;span class="lnum"&gt; 11: &lt;/span&gt; &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;char&lt;/span&gt; currentChar &lt;span class="kwrd"&gt;in&lt;/span&gt; firstNameArray)  &lt;span class="lnum"&gt; 12: &lt;/span&gt; {  &lt;span class="lnum"&gt; 13: &lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (count % 2 == 0)  &lt;span class="lnum"&gt; 14: &lt;/span&gt; mergeString += currentChar + lastNameArray[count];  &lt;span class="lnum"&gt; 15: &lt;/span&gt; }  &lt;span class="lnum"&gt; 16: &lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; mergeString;  &lt;span class="lnum"&gt; 17: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&amp;lt;pex&amp;gt;标签之间注释就是PEX修复是添加的代码.如果觉得PEX代码不够美化.开发人员也完全可以手工修改.自此你会看到PEX帮开发人员找到一个Bug并尝试不在维护UT代码的情况下并修复该异常.&lt;/font&gt;&lt;font face="Consolas"&gt;well.当然如上演示只是PEX作为白盒测试工具的丰富功能一个特性.其实刚开始看官方给出解释最吸引我莫过于它支持写参数化单元测试[Parameterized Unit Test].方式.&lt;/font&gt;&lt;/p&gt;&lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&amp;lt;3&amp;gt;Pex参数化单元测试&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;在Pex中针对白盒测试提出参数化单元测试的概念-Parameterized Unit Test。Dang我们通过PEX实现更多模块的UT操作.确保所有单个模块能够按照程序设计预期执行. 其实实际效果并非如此.PEX通过一个指令一个指令地分析.NET代码，解释代码执行时的动作，然后“以一种完全自动的方式，计算出那些能触发边角代码的相关测试输入。”&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;PEX在执行和分析代码行为时.只是得到代码最基本代码模块行为简单异常类似NullException.但是实际上开发人员并没有写过一个关于所有模块集成起来之后完整测试用例. 无法预期当前软件的行为.PEX提供参数化的单元测试提供一种强大的方式来评估当前代码在集成后是否如预期一样行为.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;找到上次增加SpiltStringToMerge字符串合并操作方法做实例.创建参数化单元测试:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_170850" border="0" alt="2012-01-19_170850" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859174449.png" width="653" height="65" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;找到该方法选中右键点击可以看到Pex-&amp;gt;Create Parameterized Unit Tests选项:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_171118" border="0" alt="2012-01-19_171118" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859186052.png" width="644" height="321" /&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;如果原来没有创建对应的PEX测试项目会提示创建一个新的Test Project.与宿主程序分离.可以看到增对测试文件目标PEX增加多重过滤项. 在Test Project项目输出上如果没有创建Test Project则创建.当然针对创建的测试项目可以指定不同的测试框架.PEX中集成了NUnit/Visual Studio Unit TEst/MbUnit V系列等.让开发人员以自己最熟悉的测试框架来维护测试代码.Pex还基于&lt;a href="http://research.microsoft.com/pex/wiki/book.html#Microsoft.ExtendedReflection"&gt;扩展反射可管理子协议API&lt;/a&gt; （Extended Reflection managed profiling API）对监测应用程序的集成提供了支持.在创建看一下设置项Settings:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_171629" border="0" alt="2012-01-19_171629" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859186019.png" width="644" height="321" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以设置默认创建的命名空间和测试类下默认PexMethod测试方法.这里采用默认方式创建:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_171955" border="0" alt="2012-01-19_171955" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859186302.png" width="644" height="215" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;创建成功后Solution目录:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_172228" border="0" alt="2012-01-19_172228" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859196825.png" width="388" height="295" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;打开ProgramTest.cs文件可以看到这个PEX自动生成的参数化单元测试方法:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt; 1: &lt;/span&gt; [PexClass(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(Program))]  &lt;span class="lnum"&gt; 2: &lt;/span&gt; [PexAllowedExceptionFromTypeUnderTest(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(InvalidOperationException))]  &lt;span class="lnum"&gt; 3: &lt;/span&gt; [PexAllowedExceptionFromTypeUnderTest(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ArgumentException), AcceptExceptionSubtypes = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]  &lt;span class="lnum"&gt; 4: &lt;/span&gt; [TestClass]  &lt;span class="lnum"&gt; 5: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ProgramTest  &lt;span class="lnum"&gt; 6: &lt;/span&gt; {  &lt;span class="lnum"&gt; 7: &lt;/span&gt; &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;Test stub for SpiltStringToMerge(String, String)&amp;lt;/summary&amp;gt;&lt;/span&gt;  &lt;span class="lnum"&gt; 8: &lt;/span&gt; [PexMethod]  &lt;span class="lnum"&gt; 9: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; SpiltStringToMerge(  &lt;span class="lnum"&gt; 10: &lt;/span&gt; [PexAssumeUnderTest]Program target,  &lt;span class="lnum"&gt; 11: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; firstname,  &lt;span class="lnum"&gt; 12: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; lastname  &lt;span class="lnum"&gt; 13: &lt;/span&gt; )  &lt;span class="lnum"&gt; 14: &lt;/span&gt; {  &lt;span class="lnum"&gt; 15: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; result = target.SpiltStringToMerge(firstname, lastname);  &lt;span class="lnum"&gt; 16: &lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; result;  &lt;span class="lnum"&gt; 17: &lt;/span&gt; &lt;span class="rem"&gt;// TODO: add assertions to method ProgramTest.SpiltStringToMerge(Program, String, String)&lt;/span&gt;  &lt;span class="lnum"&gt; 18: &lt;/span&gt; }  &lt;span class="lnum"&gt; 19: &lt;/span&gt; }&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;其实关于PEX参数化单元测试的概念.其实它就是一个带有参数并通过调用宿主测试程序简单测试方法.其实这里很多人都很疑惑怎么和传统创建单元测试方法和PEX参数化方法区别在哪呢?其实昨天我在看到这时也很困惑很久.后来在官方找了很多资料.总算是找到一点权威的论述:&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;strong&gt;A unit test is a method without parameters represents a test case which typically executes. a method of a class-under-test with fixed arguments and verifies that it returns the.&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;  &lt;font face="Consolas"&gt;    &lt;p&gt;      &lt;br /&gt;&lt;strong&gt;expected result. A parameterized unit test (PUT) is the straightforward generalization。of a unit test by allowing parameters. PUTs make statements about the code’s behavior.&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;strong&gt;for an entire set of possible input values, instead of just a single exemplary input value.&lt;/strong&gt;&lt;/p&gt;  &lt;/font&gt;&lt;/blockquote&gt;&lt;font face="Consolas"&gt;  &lt;p&gt;相对传统创建的单元测试一般情况参数都是指定固定的参数值.并在执行后会预期函数中返回对应的结果.PEX参数化单元测试概念则不同.在PEX中单元测试的参数可以输入任何可能的参数用来验证程序代码执行中所有可能的行为.你大概明白PEX提出这个概念的目的了吧.也就是说PEX在执行的时候会分析PEX参数化单元测试代码方式来查看宿主程序代码的行为.当然这个过程需要集成宿主程序的代码.而相对于传统固定参数值.PEX单元测试参数可以是任意的.这样更便于测试过程中测试宿主程序代码可能出现崩溃的几率和行为.&lt;/p&gt;  &lt;p&gt;当前已经创建PEX对应的测试项目.在回到宿主横须Program类中.再次运行Run PEX:&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_152753" border="0" alt="2012-01-19_152753" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859197349.png" width="378" height="225" /&gt;&lt;/p&gt;  &lt;p&gt;出了能看到原来Pex Test Results窗体测试结果.注意这时PEX内部根据测试需要会在测试项目对应测试ProgramTEst类中.创建普通测试方法[TestMethod]同时也会创建PEX下参数化单元测试. 创建普通测试的数量和测试结果中测试用例的数量是一致的.如果TestReaults.PEX使用7个用例那么在ProgramTest.SpiltStringToMerme.g.cs文件中肯定会有相同数量的普通测试方法存在.PEX参数化单元测试方法则放在ProgramTest.cs文件中.&lt;/p&gt;  &lt;p&gt;如果你觉得这个过程不明显.或是想了解一些PEX工作处理过程.可以选中右键可以PEX-&amp;gt;Delete Generated Unit Tests操作:&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_182301" border="0" alt="2012-01-19_182301" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859196236.png" width="649" height="227" /&gt;&lt;/p&gt;  &lt;p&gt;其实该操作的目的会自动删除ProgramTest.SpiltStringToMerme.g.cs文件中所有的普通测试方法[TestMethod]也就是当前使用测试用例.然后找到该方法在运行Run PEX./运行玩后可以找到对应测试实例的Save Test方式在把指定的测试用例保存到ProgramTest.SpiltStringToMerme.g.cs文件中.well 这里保存第一个通过的测试用例 低级Save TEst:&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_183133" border="0" alt="2012-01-19_183133" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859197283.png" width="598" height="484" /&gt;&lt;/p&gt;  &lt;p&gt;Apply.完成后.会看到ProgramTest.SpiltStringToMerme.g.cs文件中多了一个普通测试方法.同时在Test Result窗体中发现每个测试的图标不再包含一个磁盘位图而是一个对号.:&lt;/p&gt;  &lt;div class="csharpcode"&gt;    &lt;span class="lnum"&gt; 1: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ProgramTestTest    &lt;span class="lnum"&gt; 2: &lt;/span&gt; {    &lt;span class="lnum"&gt; 3: &lt;/span&gt; [TestMethod]    &lt;span class="lnum"&gt; 4: &lt;/span&gt; [PexGeneratedBy(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ProgramTestTest))]    &lt;span class="lnum"&gt; 5: &lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SpiltStringToMerge355()    &lt;span class="lnum"&gt; 6: &lt;/span&gt; {    &lt;span class="lnum"&gt; 7: &lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; s;    &lt;span class="lnum"&gt; 8: &lt;/span&gt; ProgramTest s0 = &lt;span class="kwrd"&gt;new&lt;/span&gt; ProgramTest();    &lt;span class="lnum"&gt; 9: &lt;/span&gt; Program s1 = &lt;span class="kwrd"&gt;new&lt;/span&gt; Program();    &lt;span class="lnum"&gt; 10: &lt;/span&gt; s = &lt;span class="kwrd"&gt;this&lt;/span&gt;.SpiltStringToMerge(s0, s1, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;);    &lt;span class="lnum"&gt; 11: &lt;/span&gt; Assert.AreEqual&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;(&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;, s);    &lt;span class="lnum"&gt; 12: &lt;/span&gt; Assert.IsNotNull((&lt;span class="kwrd"&gt;object&lt;/span&gt;)s0);    &lt;span class="lnum"&gt; 13: &lt;/span&gt; }    &lt;span class="lnum"&gt; 14: &lt;/span&gt; }  &lt;/div&gt;  &lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;  &lt;p&gt;这样有选择的方式让开发人员很轻松能够保存在不同版本需求变动生成的测试用例/.而且是可选择的.当然在添加过程往往会提示一些命名上问题例如如下提示:&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-19_183143" border="0" alt="2012-01-19_183143" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201191859207250.png" width="498" height="310" /&gt;&lt;/p&gt;  &lt;p&gt;这是因为现在PEX现在对中文GB2312格式支持存在乱码的问题. 当然在创建是PEX为了防止访问路径过长.就限制在PEX所有文件命名长度.&lt;/p&gt;  &lt;p&gt;其实到这里很多人依然对PEX 参数化单元测试的概念依然有些困惑.这个概念其实很简单.但在实际运用你会发现它的实际用途的好处.如果你熟悉并常用的单元测试.但还不理解PEX中参数化单元测试概念.可以从以下几个方向去考虑[仅作参考]：&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;    &lt;p&gt;&lt;strong&gt;理解参数化单元测试的方向:&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;[1]:当时你手写普通的单元测试.思考以下你要测试代码的行为.在构建单元测试时你的需要多少个独立参数传入.?&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;[2]:目前尚不清楚确切的数字可能会是什么.但在测试过程它是很重要的,因PEX角度来说开发人员永远有时间来即时创建和维护测试代码.&lt;/strong&gt;&lt;/p&gt;  &lt;/blockquote&gt;&lt;/font&gt;&lt;p&gt;&lt;font face="Consolas"&gt;当然更多还请参考官方的资料:&lt;/font&gt;&lt;a href="http://research.microsoft.com/en-us/projects/pex/default.aspx"&gt;&lt;font face="Consolas"&gt;http://research.microsoft.com/en-us/projects/pex/default.aspx&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;&lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&amp;lt;4&amp;gt;Pex小结&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;本篇PEX 自身应用角度来阐述PEX相对传统单元测试所具有的特点.作为一个白盒的测试工具.开发人员常在程序开发过程中.需求往往也是不断变化的.当然也无法避免未来开发过程中.或进入代码维护阶段是.所需要面对代码修正的问题.&lt;/font&gt;&lt;font face="Consolas"&gt;为了每次都能保证软件代码工作都正确无误.而且即时在需求发生变更需要添加新功能时.也能保证原有功能正常运行.使用可控的测试导向的开发模式是必行的.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;当然作为开发人员要在开发过程手工编写大量的测试用例并维护笨重测试的代码.这会在一定程度上导致项目开发进度延缓。这也是很多开发人员忽视UT一个原因之一.但现在PEX白盒测试工具.可以把测试流程完全的自动化.把开发人员从单元测试的需求中解脱出来专注于核心业务开发之上.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;本篇并没有急于在Windows phone Application 中验证PEX是否可行.但是PEX透露出来关于测试理念确实很有深入的价值.稍后会在下篇副中无论成功还是失败.演示Windows phone应用程序中使用PEX整个过程.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;如有问题请在评论中提出.本篇所有源代码下载地址如下:&lt;a href="http://files.cnblogs.com/chenkai/BasicConsolePexComponent_Demo.rar"&gt;/Files/chenkai/BasicConsolePexComponent_Demo.rar&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/chenkai/aggbug/2327580.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/19/2327580.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/chenkai/archive/2012/01/13/2321722.html</id><title type="text">Git Tool Part 2</title><summary type="text">针对Git的使用.在Git中文操作指南手册中.讲解大量关于GiT的细节操作.可是对于从SVN或是TFS转换的很多开发人员来说.很多并没有更多学习周期时间.那么如何才能短时间内抓住Git核心枝干.短时间内快速进入Git并在代码中集成使用工具呢.? 由于Git中富含大量的Git 命令.细节太多.本来打算在本篇中介绍一些Git通过命令的方式基本操作.等写了大概四分之一.发现完全和最初写这篇文章初衷完全背...</summary><published>2012-01-13T07:51:00Z</published><updated>2012-01-13T07:51:00Z</updated><author><name>chenkai</name><uri>http://www.cnblogs.com/chenkai/</uri></author><link rel="alternate" href="http://www.cnblogs.com/chenkai/archive/2012/01/13/2321722.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/chenkai/archive/2012/01/13/2321722.html"/><content type="html">&lt;p&gt;&lt;font face="Consolas"&gt;针对Git的使用.在Git中文操作指南手册中.讲解大量关于GiT的细节操作.可是对于从SVN或是TFS转换的很多开发人员来说.很多并没有更多学习周期时间.那么如何才能短时间内抓住Git核心枝干.短时间内快速进入Git并在代码中集成使用工具呢.? &lt;/font&gt;&lt;font face="Consolas"&gt;由于Git中富含大量的Git 命令.细节太多.本来打算在本篇中介绍一些Git通过命令的方式基本操作.等写了大概四分之一.发现完全和最初写这篇文章初衷完全背离了.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;其实本篇的目的很简单.与其陷入在在长长的篇幅中介绍Git Command基本用法 还不如直接采用Windows 平台开发人员最熟悉的GUI界面工具操作更为直观.Git原理理论和操作用法也是非常系统.如果你觉得有必要建立一个系统知识结构.当然也有很好的资源可以当做日常查看手册:&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Git 系统资源:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Git中文操作指南 Download Link[&lt;/strong&gt;&lt;/font&gt;&lt;a title="http://vdisk.weibo.com/s/1UJq4" href="http://vdisk.weibo.com/s/1UJq4"&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;http://vdisk.weibo.com/s/1UJq4&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;]&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;&lt;font size="2" face="Consolas"&gt;Git Command指令在线文档: [&lt;a href="http://www-cs-students.stanford.edu/~blynn/gitmagic/intl/zh_cn/index.html"&gt;http://www-cs-students.stanford.edu/~blynn/gitmagic/intl/zh_cn/index.html&lt;/a&gt;]&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;&lt;font size="2" face="Consolas"&gt;&amp;lt;&amp;lt;Git Community Book中文版&amp;gt;&amp;gt;：[&lt;a href="http://gitbook.liuhui998.com/"&gt;http://gitbook.liuhui998.com/&lt;/a&gt;]&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;&lt;font size="2" face="Consolas"&gt;注:如上在线文档或图书版权源作者拥有.本文只是添加引用.如转载请注明出处.&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;作为Windows 平台开发人员最常用的开发工具莫过于Visual Studio系列.但是可惜的Git作为从Linux平台的舶来品..NET开发人员更习惯于使用用户界面，所以在进行日常任务的时候更习惯使用操作基于具有IDE的界面.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;作为一个Visual Studio用户.在使用Visual SouceSafe/Team Foundation Server、Subversion或甚至Mercurial的过程中.已经建立了使用源码控制习惯.更多的开发人员希望在Solution解决方案目录中就直观看到自己的SouceCode被版本管理工具所控制着.无论在代码修改或添加都能直接获得状态反馈.所以在Visual Studio使用Git需求就一直成为Git一块”硬伤”.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;如何在Visual STudio系列开发工具中使用Git版本控制工具?&lt;/font&gt;&lt;/p&gt;  &lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&amp;lt;1&amp;gt;Visual Studio 构建Git部署环境&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Well，谈到这里在上章节中&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/11/2319775.html" target="_blank"&gt;Git Tool Part 1&lt;/a&gt;中提到能够适用Windows 平台的Git工具主要具有两个模拟*nix like运行环境的工具：&lt;a href="http://www.cygwin.com/"&gt;cygwin&lt;/a&gt;，&lt;a href="http://www.mingw.org/wiki/MSYS"&gt;msys&lt;/a&gt;；Git在&lt;a href="http://www.cygwin.com/"&gt;cygwin&lt;/a&gt;，&lt;a href="http://www.mingw.org/wiki/MSYS"&gt;msys&lt;/a&gt;下都有相应的移植版本.不过就使用体验来说个人觉得msys平台下的&lt;a href="http://code.google.com/p/msysgit/"&gt;msysGit&lt;/a&gt;最好用.在GUI图形工具上有Git extentions ，还是TortoiseGit.更加倾向于前者.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Linux开源社区也考虑到很多Windows平台开发人员的需求.在后来工具支持上推出可以Visual Studio系列开发工具集成Git版本控制系统 插件-&lt;a href="http://code.google.com/p/gitextensions/" target="_blank"&gt;Gitextensions&lt;/a&gt;.这是目前Visual Studio系列开发工具唯一支持Git具有GUI操作界面的插件.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;至此在Visual Studio IDE开发工具构建Git版本控制工具组合就诞生了:&lt;/font&gt;&lt;/p&gt;  &lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;   &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Visual Stuido Git版本控制工具组合:&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Git 命令行(&lt;a href="http://code.google.com/p/msysgit/" target="_blank"&gt;MsysGit&lt;/a&gt;) + &lt;a href="http://code.google.com/p/gitextensions/" target="_blank"&gt;Git Extensions&lt;/a&gt; + &lt;a href="http://visualstudiogallery.msdn.microsoft.com/63a7e40d-4d71-4fbb-a23b-d262124b8f4c" target="_blank"&gt;Git Source Control Provider&lt;/a&gt; [Only Support Visual Studio 2010]&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;&lt;font size="2" face="Consolas"&gt;Git 命令行一般采用BitBash工具来直接采用命令操作.&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;&lt;font size="2" face="Consolas"&gt;Git Extensions：则是直接Visual Studio 开发工具中集成Git GUI操作工具.&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;&lt;font size="2" face="Consolas"&gt;Git Souce Control Provider:为Visual STudio 提供Git版本控制支持.&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;首先安装&lt;font face="Consolas"&gt;MsysGit可以在[&lt;a title="http://code.google.com/p/msysgit/" href="http://code.google.com/p/msysgit/"&gt;http://code.google.com/p/msysgit/&lt;/a&gt;]下载到最新的FullInstall版本.安装步骤请参考GitHub上Wiki[&lt;a href="https://github.com/msysgit/msysgit/wiki/InstallMSysGit"&gt;https://github.com/msysgit/msysgit/wiki/InstallMSysGit&lt;/a&gt;].默认编辑工具是Vim/&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;因Git Extensions工具是基于Git 命令行,可以在安装MsysGit之后通过[&lt;a href="http://code.google.com/p/gitextensions/"&gt;http://code.google.com/p/gitextensions/&lt;/a&gt;]下载安装;在安装过程中因已经安装MsysGit版本[可选也可不选].所以只需选择集成KDiff3工具即可:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_105926" border="0" alt="2012-01-12_105926" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550342430.png" width="513" height="402" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;另外关于Git Extension传输协议 选择:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_110037" border="0" alt="2012-01-12_110037" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550359333.png" width="513" height="402" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;OpenSSH 客户端，提供 Git 访问 ssh 协议的版本库.Git自身支持多种协议.在此选择默认安装OpenSSH.在GitExtension安装完成后.通过Start-&amp;gt;Git Extension安装目录.打开Git Extension.找到Setting设置设置选项页Git:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_182007" border="0" alt="2012-01-12_182007" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550352331.png" width="644" height="476" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;一般情况如果安装顺序没有问题.安装Git Extension工具后都会自动找到对应Git命令行工具安装路径,git命令行工具有两种，一种是 cygwin 下命令行，一种是 msysGit 命令行，git extensions 可以配置使用哪一种命令行工具。因Git Extension是基于命令行操作的.在执行请检查该设置是否指向正确Git命令行安装工具路径.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;最后需要安装&lt;a href="http://visualstudiogallery.msdn.microsoft.com/63a7e40d-4d71-4fbb-a23b-d262124b8f4c" target="_blank"&gt;Git Source Control Provider&lt;/a&gt;,打开Visual STudio 2010开发工具.找到Tools-&amp;gt;Extension Manager选择Online Gallery选项页搜索:&lt;a href="http://visualstudiogallery.msdn.microsoft.com/63a7e40d-4d71-4fbb-a23b-d262124b8f4c" target="_blank"&gt;Git Source Control Provider&lt;/a&gt; 看到：&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_110722" border="0" alt="2012-01-12_110722" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550359790.png" width="644" height="446" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;下载安装.当然也可以不用打开Visual Studio 也可以通过[&lt;a href="http://visualstudiogallery.msdn.microsoft.com/63a7e40d-4d71-4fbb-a23b-d262124b8f4c" target="_blank"&gt;Git Source Control Provider&lt;/a&gt;]地址直接下载安装即可.安装完成后找到Tools-&amp;gt;Options-&amp;gt;Souce Control选项中把Git Souce Control Provider作为默认版本控制工具:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_111126" border="0" alt="2012-01-12_111126" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550361152.png" width="644" height="421" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;至此在Visual Studio 2010搭建好了Git版本控制需要环境.&lt;/font&gt;&lt;/p&gt;  &lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&amp;lt;2&amp;gt;Git在Visual Studio 基本操作&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;构建好Git在Visual Studio 2010开发工具版本控制.通过一个具体的Windows phone Application 来演示一下Git基本操作，首先在硬盘上开辟一个独立的文件夹CodeDevelopment：在该项目源码放在该目录下 新建解决方案如下.看看初始状态：&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_184449" border="0" alt="2012-01-12_184449" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/20120113155036804.png" width="317" height="287" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;在初始状态下并没有继承Git版本控制.如果在Setting目录下设置Git.可以通过右键点击文件可以看到Git操作的选项:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_184655" border="0" alt="2012-01-12_184655" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550367183.png" width="320" height="443" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;如要对某个项目执行Git版本控制管理.只需到此项目所在的目录创建一个仓库.也就是Git-New Repotiory操作，执行完成后能在项目目录下看到多了Git文件目录:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_185008" border="0" alt="2012-01-12_185008" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550379658.png" width="606" height="134" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;初始化后，在当前目录下会出现一个名为 .git 的目录，所有 Git 需要的数据和资源都存放在这个目录中。不过目前，仅仅是按照既有的结构框架初始化好了里边所有的文件和目录，但我们还没有开始跟踪管理项目中的任何一个文件.和.git同处一个目录的所有文件，现在就纳入了这个版本库的范围之内.可以在改目录下执行Git命令.也能够看到Visual STudio多了两个View窗口:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_110900" border="0" alt="2012-01-12_110900" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550375165.png" width="644" height="328" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;当创建完一个仓库发现解决方案的代码文件并没有类似SVN或TFS发生状态变化-即通过文件前小图标标识状态.不知道为何这可能Git Extension一个Bug.这时只有通过重启VS工具才能看到文件跟踪的状态:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_185737" border="0" alt="2012-01-12_185737" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550373496.png" width="346" height="256" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;well.是否可TFS和SVN体验一致.Well来看看库当前状态右键点击项目找到Git-&amp;gt;GitBesh通过Git指令:Git Status执行&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_190147" border="0" alt="2012-01-12_190147" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550389002.png" width="681" height="256" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;这说明你现在的工作目录相当干净。换句话说，当前没有任何跟踪着的文件，也没有任何文件在上次提交后更改过。此外，上面的信息还表明，当前目录下没有出现任何处于未跟踪的新文件，否则 Git 会在这里列出来。最后，该命令还显示了当前所在的分支是 master，这是默认的分支名称.在没有进入代码修改之前.可以提交解决方案最原始的版本.通过右键点击解决方案找到Git-&amp;gt;Commit执行第一次版本提交:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_190505" border="0" alt="2012-01-12_190505" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550386461.png" width="229" height="312" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;执行后看到Commit页面,因现在文件都没有添加到Git暂存区.所以如果直接提交会提示：&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_190844" border="0" alt="2012-01-12_190844" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550397508.png" width="494" height="191" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;所以在执行操作之前可以把所有文件添加到Git暂存区，添加MEssage 直接提交:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_190857" border="0" alt="2012-01-12_190857" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550392458.png" width="644" height="471" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;点击提交Commit按钮 提交成功:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_190904" border="0" alt="2012-01-12_190904" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550391869.png" width="585" height="369" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;现在在代码修改Mainpage页面PageTitle为chenkai.后再次提交.就能直接看到修改的差异:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_191320" border="0" alt="2012-01-12_191320" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/20120113155040723.png" width="644" height="471" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;关于我们创建没有做任何操作直接执行提交操作时提示. 其实是说明Git在执行提交操作必要的流程.在工作目录下面的所有文件都不外乎这两种状态：已跟踪或未跟踪。已跟踪的文件是指本来就被纳入版本控制管理的文件，在上次快照中有它们的记录，工作一段时间后，它们的状态可能是未更新，已修改或者已放入暂存区。而所有其他文件都属于未跟踪文件。它们既没有上次更新时的快照，也不在当前的暂存区域.文件在整个Git版本控制状态周期：&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_192239" border="0" alt="2012-01-12_192239" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550415641.png" width="644" height="407" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;Git的暂存区是在版本未在提交之前存储位置.从上图可以看出.整个提交流程目录变化位置:工作目录-&amp;gt;暂存区-&amp;gt;版本库.暂存区的目的相当于实际编码和真正提交到Git执行版本追踪之间一个缓冲地带.这有什么好处呢.?很简单.暂存区的文件可以任意的在工作目录和版本库实现自由的交互.这样设计目的用户在操作过程可能会出错.暂存区也就给了用户撤销原来操作的可能.在文件没有进行任何操作之前一般通过Git Add指令吧文件添加到暂存区.在执行Commit操作时文件状态就有暂存区提交成为Git版本受控制的版本库中.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;在Commit页面可以看到一个键便捷的操作:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_193018" border="0" alt="2012-01-12_193018" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/20120113155041624.png" width="318" height="38" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;实现从工作目录到暂存区文件批量操作.其实Stage的操作内部封装就是Git add指令.当然也可以通过AddFiles 执行这种批量操作:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_193647" border="0" alt="2012-01-12_193647" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550414179.png" width="227" height="177" /&gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;当然在Git中执行提交操作依然可以跳过暂存区操作.尽管使用暂存区域的方式可以精心准备要提交的细节，但有时候这么做略显繁琐。Git 提供了一个跳过使用暂存区域的方式，只要在提交的时候，给 &lt;code&gt;git commit&lt;/code&gt; 加上 &lt;code&gt;-a&lt;/code&gt; 选项，Git 就会自动把所有已经跟踪过的文件暂存起来一并提交：这就是从工作目录-&amp;gt;版本库直接操作.可以打开命令行:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_193359" border="0" alt="2012-01-12_193359" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550426098.png" width="681" height="214" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;可以看到，提交后它会告诉你，当前是在哪个分支（master）提交的，本次提交的完整 SHA-1 校验和是什么（&lt;code&gt;463dc4f&lt;/code&gt;），以及在本次提交中，有多少文件修订过，多少行添改和删改过.提交成功后.看一下文件状态:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-12_193908" border="0" alt="2012-01-12_193908" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550429653.png" width="346" height="252" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;由原来的加号变锁.标识当前所有的文件已经第一次提交到版本库.如果当前再次修改MainPage.xaml则可以看到文件状态发生改变:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_103118" border="0" alt="2012-01-13_103118" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550421572.png" width="347" height="252" /&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_103519" border="0" alt="2012-01-13_103519" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550437079.png" width="344" height="263" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;红色对勾标识当前文件已经发生了修改.而浅黄色的感叹号.标识当前文件状态由工作目录已经存放暂存区等待提交.假如我们在正常编译操作.执行多次提交.可能某一次版本提交时会出现手工操作失误.比如在这次版本提交以往提交某些文件，或是忘记修改某些文件.可能需要撤消刚才所做的某些操作,请注意，有些操作并不总是可以撤消的，所以请务必谨慎小心，一旦失误，就有可能丢失部分工作成果。可以使用 &lt;code&gt;--amend&lt;/code&gt; 选项重新提交.:&lt;/font&gt;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;span class="lnum"&gt;   1:  &lt;/span&gt;$ git commit --amend&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;令将使用当前的暂存区域快照提交。如果刚才提交完没有作任何改动，直接运行此命令的话，相当于有机会重新编辑提交说明，而所提交的文件快照和之前的一样,如果刚才提交时忘了暂存某些修改，可以先补上暂存操作，然后再运行 &lt;code&gt;--amend&lt;/code&gt; 提交:&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt;   1:  &lt;/span&gt;$ git commit -m &lt;span class="str"&gt;'initial commit'&lt;/span&gt;  &lt;span class="lnum"&gt;   2:  &lt;/span&gt;$ git add forgotten_file  &lt;span class="lnum"&gt;   3:  &lt;/span&gt;$ git commit --amend &lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;ok.现在修改MainPage.xaml。在把这个文件追加上一个版本中添加Add Files操作后执行Git命令如下:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_104539" border="0" alt="2012-01-13_104539" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550436489.png" width="681" height="214" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;well顺利提交.有时我们通过Git Extension集成的命令通过Add Files 方式把当前所有工作的目录的文件添加到暂存区.也就是添加Git版本跟踪. 可能为了减轻操作的负担.对于有些应用程序编译中自动生成的文件.类似日志.或编译的文件并不需要Git版本管理.需要把这些文件从暂存区剔除掉.取消暂存区文件.可以执行如下Git命令:&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt;   1:  &lt;/span&gt; git reset HEAD &amp;lt;file文件名称&amp;gt;...&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;在我们执行提交多次可以Git Extension中查看提交的版本.当然也可以通过命令Git Log方式查看同样的效果:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_105536" border="0" alt="2012-01-13_105536" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550441407.png" width="644" height="420" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以看到最后一次提交版本Message.总共提交三次版本.当然也可以在Git History看到图形化的提交历史版本:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_105915" border="0" alt="2012-01-13_105915" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550443325.png" width="644" height="254" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;当我们修改完成之后.在编辑过程达到一个满意的过程.,git 是分布式版本系统，都有一个 git 版本库的拷贝，为了和远程其他版本库同步，需要进行同步操作.同步操作一般分为拉取pull.另外一个推送Push.针对Git的服务器.如果比较大的组织结构可以企业内部构建自己的Git服务器.如果是小型团队.完全没有必要这么麻烦.现在依然很好第三方托管服务类似GitHub. &lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;首先需要建立一个&lt;a href="https://github.com/" target="_blank"&gt;GitHub&lt;/a&gt;账号.就不多说了打开后能看到操作流程如下:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_112735" border="0" alt="2012-01-13_112735" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550453816.png" width="644" height="273" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;因已经配置过Git环境.所以直接创建一个Create Repository：&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_113014" border="0" alt="2012-01-13_113014" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550454306.png" width="644" height="448" /&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;填写项目名称.描述和HomePage是可选项.当然最关键是可以设置GitHub托管的项目是否公开或私密状态.创建库Repository完成可以看到具体操作Git指令的流程如下:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_113405" border="0" alt="2012-01-13_113405" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550462288.png" width="644" height="397" /&gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;首先需要见车Git Bash是否设置对应的全局的用户名和Email:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_113512" border="0" alt="2012-01-13_113512" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550467554.png" width="644" height="476" /&gt;&lt;/p&gt;&lt;p&gt;设置完成后需要在GitHub针对托管的项目添加一个公钥，如果没有公钥则可以通过Bit Extension工具自动生成一个匹配的公钥和私钥文件并保存在本地,带卡Bit Extension 找到：&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_113633" border="0" alt="2012-01-13_113633" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550478045.png" width="644" height="420" /&gt;&lt;/p&gt;&lt;p&gt;打开操作General 生成一对公私密钥,并保存本地硬盘目录中:&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_113814" border="0" alt="2012-01-13_113814" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550472123.png" width="500" height="484" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;保存上面的公钥字符串和公钥key&lt;/font&gt;&lt;a href="http://www.haogongju.net/tag/%E6%96%87%E4%BB%B6"&gt;&lt;font face="Consolas"&gt;文件&lt;/font&gt;&lt;/a&gt;&lt;font face="Consolas"&gt;为public文件，密钥为private.ppk文件.保存完成后需要到GitHub控制面版页面把该公钥添加上去:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_114110" border="0" alt="2012-01-13_114110" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/20120113155048977.png" width="644" height="299" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;添加成功后.在指令操作流程页面就可以GitHub对外公开该项目访问路径:git@github.com:chenkai/GitBaseOperator_Demo.git,对于Github上对外访问路径格式一般是：一般是 &lt;strong&gt;git@github.com:yourName/yourProject.git &lt;/strong&gt;格式. 这时我们可以把已经修改的应用程序通过Visual Studio 中Git Push到GitHub上:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_141814" border="0" alt="2012-01-13_141814" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550489865.png" width="226" height="168" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;这时会提示一个窗体:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_115335" border="0" alt="2012-01-13_115335" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550485371.png" width="644" height="326" /&gt;&lt;/p&gt;&lt;p&gt;首先点击Manage添加默认的添加项目信息. 找到 Default Pull:&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_115245" border="0" alt="2012-01-13_115245" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550498370.png" width="644" height="314" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;添加远程的Github项目信息.并save，在选择Remote REspositories设置对应项目Reposity的基本信息并Save:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_115156" border="0" alt="2012-01-13_115156" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550491369.png" width="644" height="314" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;关闭窗体回到Push主页面就会看到对应默认项目是BitBaseOperator_Demo.ok此时点击Push开始推送代码到Github上:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_115402" border="0" alt="2012-01-13_115402" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550508827.png" width="644" height="326" /&gt;&lt;/p&gt;&lt;p&gt;确定.在调用Git.Exe是需要允许其对外访问输入yes:&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_115438" border="0" alt="2012-01-13_115438" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550501826.png" width="644" height="199" /&gt;&lt;/p&gt;&lt;p&gt;开始推送 如果提示出错类似如下:&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_140050" border="0" alt="2012-01-13_140050" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550517092.png" width="644" height="406" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;提示当前权限不允许操作.远程连接中断.好吧这个问题折腾我好久.后来在官方社区看到解决方法.其实这主要是GitBash通过cmd命令进入命令行输入界面的。正确的操作是，在git附带的bash（GitBash可以在开始菜单的git目标里面找到）里面运行命令，就可以一切正常。当然如果觉得这种界面操作麻烦也可以根据官方给出的纯指令的方式操作吧代码Push到GitHub上操作流程如下或是参加如下小白解决方案[&lt;a href="http://help.github.com/win-set-up-git/"&gt;ttp://help.github.com/win-set-up-git/&lt;/a&gt;]:&lt;/font&gt;&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;p&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;github的&lt;/strong&gt;&lt;/font&gt;&lt;a href="http://help.github.com/linux-set-up-git/"&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;官方文档&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;  &lt;font size="2" face="Consolas"&gt;&lt;strong&gt;#1. Check for SSH keys.&lt;br/&gt;$ cd ~/.ssh&lt;br/&gt;#2. Backup and remove existing SSH keys.&lt;br/&gt;$ lsLists all the subdirectories in the current directory&lt;br/&gt;$ mkdir key_backupmakes a subdirectory called &amp;quot;key_backup&amp;quot; in the current directory&lt;br/&gt;$ cp id_rsa* key_backupCopies the contents of the id_rsa directory into key_backup&lt;br/&gt;$ rm id_rsa*&lt;br/&gt;#3. Generate a new SSH key.&lt;br/&gt;$ ssh-keygen -t rsa -C &amp;quot;your_email@youremail.com&amp;quot;&lt;br/&gt;#4. Add your SSH key to GitHub.&lt;br/&gt;#5. Test everything out.&lt;br/&gt;$ ssh -T &lt;/strong&gt;&lt;/font&gt;&lt;a href="mailto:git@github.com"&gt;&lt;font size="2" face="Consolas"&gt;&lt;strong&gt;git@github.com&lt;/strong&gt;&lt;/font&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;p&gt;Git Bash中执行push令如下:&lt;/p&gt;&lt;blockquote style='border:2px solid #EFEFEF;color:#333333;padding:5px 10px;'&gt;  &lt;font size="2" face="Consolas"&gt;&lt;strong&gt;Push指令：&lt;/strong&gt;&lt;/font&gt;  &lt;font size="2" face="Consolas"&gt;&lt;strong&gt;$ git remote add origin git@github.com:testinguser/yourproj.git&lt;br/&gt;$ git push origin master&lt;/strong&gt;&lt;/font&gt;&lt;/blockquote&gt;&lt;font face="Consolas"&gt;&amp;#160;&lt;/font&gt;&lt;font face="Consolas"&gt;在实际操作还有另外一种情况.也会导致这种情况出错.出错的原因是因为公私密钥保存位置不在默认目录下.导致在Push时提示需要提示提供公钥.&lt;/font&gt;&lt;font face="Consolas"&gt;所以在并不推荐使用工具的方式生成密钥，如果要保存最好不要自定义保存目录:&lt;/font&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_113901" border="0" alt="2012-01-13_113901" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550512010.png" width="500" height="484" /&gt;&amp;#160;&lt;font face="Consolas"&gt;当然最好的方式就是官方给出通过Bit Bash指令工具自动生成.操作流程如下:&lt;/font&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_151707" border="0" alt="2012-01-13_151707" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550521105.png" width="681" height="438" /&gt;&lt;p&gt;&lt;font face="Consolas"&gt;首先通过自己的电子邮件生成对应的公私密钥.保存和存储指令一律采用默认为空的方式保存默认目录下.注意这个默认目录在User创建成功可以通过如下指令测试是否连接GitHub成功&amp;quot;：&lt;/font&gt;&lt;/p&gt;&lt;div class="csharpcode"&gt;  &lt;span class="lnum"&gt;   1:  &lt;/span&gt;ssh -T git@github.com&lt;/div&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;&lt;font face="Consolas"&gt;测试成功成功后.在来通过Visual STudio 中Git集成Push到GitHub上:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_151135" border="0" alt="2012-01-13_151135" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550523023.png" width="585" height="369" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;you see Push成功.GitHub也能看到对应目录和Code.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;well.当我们通过GitHub首先第三方代理时.通过和其他开发人员或第三方团队时很方便.随时随地就可以把代码Commit或是Pull一个版本，这样分布式结构完全体现Git的威力.ok加入Team另外一个成员修改Github上源码并Commit一个完整版本.现在Pull下来一个最新SouceCode.在Visual Studio中：执行Pull:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_153213" border="0" alt="2012-01-13_153213" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550536894.png" width="644" height="346" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;分支选择以主干Master. 合并策略Merge默认以GitHub SouceCode为基准覆盖本地.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_153231" border="0" alt="2012-01-13_153231" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550534037.png" width="585" height="369" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Pull 成功.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;如果在GitHub看到不错的项目可以通过本地找到指定目录Clone本地:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="2012-01-13_153918" border="0" alt="2012-01-13_153918" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131550538464.png" width="274" height="309" /&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Clone操作执行本地源码:&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="2012-01-13_162502" border="0" alt="2012-01-13_162502" src="http://images.cnblogs.com/cnblogs_com/chenkai/201201/201201131629068593.png" width="517" height="349" /&gt;&lt;/p&gt;&lt;p&gt;…&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Git操作的细节太多了. 我这个短短的篇幅中是无法写完的.只能列举一些在Visual Studio最基本的应用.展示一下Git作为版本控制工具强项.权当抛砖引玉.&lt;/font&gt;&lt;/p&gt;&lt;h3 style="padding-bottom: 3px; background-color: #80ac92; font-family: verdana, geneva, arial, helvetica, sans-serif; height: 44px; color: white; font-size: 15pt; font-weight: bolder; padding-top: 10px"&gt;&lt;strong&gt;&lt;font face="Consolas"&gt;&amp;lt;3&amp;gt;Git小结&lt;/font&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;Git作为很好的分布式的版本控制工具.在版本控制能够优雅实现多种类型模式和Team的协作模式.机动灵活处理了版本控制各种问题.当然这篇文章我写了两天.主要是要重现Git大量细节操作太费时费力了.写的很累.篇幅毕竟有限.不能全面覆盖.只能抛砖引玉.对于Windows平台的用户来 这种分布式控制版本控制工具.与强大Visual Studio集成.对Windows 平台开发人员和日常团队管理来说也是”福音”,极力推荐.&lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Consolas"&gt;可以参考上篇:&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/11/2319775.html"&gt;Git Tool Part 1&lt;/a&gt;&lt;/font&gt;&lt;/p&gt;&lt;img src="http://www.cnblogs.com/chenkai/aggbug/2321722.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/chenkai/archive/2012/01/13/2321722.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry></feed>
