﻿<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:trackback="http://wyjexplorer.cn"><channel><title>汪宇杰的博客</title><link>http://wyjexplorer.cn/　</link><description>来自汪宇杰个人网站的最新文章</description><copyright>2012 wyjexplorer.cn</copyright><generator>EdiBlog</generator><item><title>如何在VS2010里更改TFS的本地映射路径</title><link>http://wyjexplorer.cn/Home/View/89196D008AA30791.html</link><description><![CDATA[<p>今天GET一个项目文件的时候爆了，TFS说不允许路径长度超过256个字符。尼玛如此坑爹的限制，用户体验实在不好。无奈只能换个路径了。但显示路径的地方直接点击，是打开文件夹，而没有更改路径。尼玛研究了好久这个坑爹设置终于搞定了。这什么用户体验！</p>
<p>1. 在Workspace的下拉列表里，选择Workspaces...</p>
<p><img src="/Uploads/tfschangemap1_201205181039337029.PNG" alt="" width="349" height="218" /></p>
<p>2. 在弹出的对话框中选择Edit</p>
<p><img src="/Uploads/tfschangemap2_201205181039384141.PNG" alt="" width="610" height="460" /></p>
<p>3. 然后，就可以更改Local Folder的位置了</p>
<p><img src="/Uploads/tfschangemap3_201205181039437025.PNG" alt="" width="633" height="515" /></p>
<p>4. 最后，系统会建议你GET一下，于是重新GET就好了</p>
<p><img src="/Uploads/tfschangemap4_201205181039500986.PNG" alt="" width="606" height="458" /></p>
<p>关于TFS命名限制的描述可以在MSDN里找到: <a href="http://msdn.microsoft.com/zh-cn/library/aa980550%28v=vs.100%29.aspx">http://msdn.microsoft.com/zh-cn/library/aa980550%28v=vs.100%29.aspx</a></p>]]></description><pubDate>Fri, 18 May 2012 10:42:53 +0800</pubDate></item><item><title>《巫妖王之怒》回忆录（一）：回归</title><link>http://wyjexplorer.cn/Home/View/89CCEC82C933BF5E.html</link><description><![CDATA[<p>接上篇《<a href="/Home/View/B58F1435C68A891E.html">WOW，记忆中的那些欢笑与泪水（完结篇）</a>》。</p>
<p>我从提瑞斯法转服回归基尔罗格以后，心里有些难受。犹如噩梦初醒，再次回到现实中，回到原本属于我的地方。从前的一幕幕在我脑海中飘过，外域、沙塔斯城、祖尔格拉布、北风苔原&hellip;&hellip;。我打开好友名单，寻找我曾经的朋友们，可惜有些人已经加不到了。我想起了转服前的晚上，还有前几天在幽暗城碰到的血精灵妹子，她的信让我心头很暖。还有情人节的时候一个人做探索者成就时碰到的美希希圣骑士妹子，现在再也没机会和她们一起玩了，她们都是好人。我的包包里，还有前一天晚上随波妹子送给我的宝石，看着那颗赤玉石，我突然觉得自己是不是有些残忍，然而，一切已经晚了。</p>
<p>转服之后我起了一个新名字，叫做破烂熊。回来之后第一件事是找到以前的公会。加我的是D妹，我转服以前的朋友，他仍记得我最早的名字，TBC时候的那个小德&mdash;&mdash;得得吉。直到现在他也习惯这么叫我。也许最初的名字最亲切吧。</p>
<p>我想起了以前他带我去刷老虎，虽然没有出，79的时候和他一起做节日任务，刷无头骑士，练级的时候也是他陪我聊天。现在我再次回到以前的公会了，可老面孔少了，突然心里有种说不清的感觉。看着公会里欢迎我回归的消息，我本该高兴的，可是我却没当初转服以后的那份激动了。</p>
<p>我回来的时候，带着一身好装备，GS5919当时不算低，于是直接加入了公会团参加活动。同样的副本，身边却不是曾经的那24个人了。现在的工会相比以前要强力很多，指挥也非常专业。并且，现在我不许要为了小J而分心，这让我更加专注于完成T的任务。</p>
<p><img src="/Uploads/wlk00_201205112037533187.PNG" alt="" width="367" height="82" /></p>
<p>回来不久后，我就发现我们服有人做掉了成就龙，太犀利了。这时候我们团连鲜血议会都没开掉，别说打英雄难度的成就了。</p>
<p><img src="/Uploads/wlk01_201205112038019611.PNG" alt="" width="642" height="339" /></p>
<p>当年除了ICC，还有很多团队本可以打，比如TOC，那时候是有周常的，就是一个礼拜做一次的任务，在达拉然可以接到。好处是换几个寒冰牌子。TOC很简单，团也是随便组就行的。转服回来以后，很少碰到以前认识的朋友，不过有一天打TOC的时候，团队里突然发现了一个熟悉的名字：追风叶。时隔这么久，见到一个老朋友，我无比激动。我和他聊了很久，聊他当年带我刷ZUL，聊WLK时候的重逢，聊我转服的悲剧，曾经的一切。</p>
<p><img src="/Uploads/wlk02_201205112038080607.PNG" alt="" width="375" height="206" /></p>
<p>当年的魔兽世界，还有一个经久不衰的业务&mdash;&mdash;带刷小副本升级。尽管WLK改版以后，不能卡无限刷的bug了，现在1个小时刷5次就会爆本，也就是不能再进副本了。不过还是有很多不高兴自己练级的小号选择带刷。我有空的时候也会去带几次影牙城堡和血色修道院。那时候影牙的老大是阿鲁高，他养了很多狼崽子，刷怪的经验非常多。还有一个怪叫做盲眼守卫奥杜，他有一定几率掉落一根叫做&ldquo;奥杜之杖&rdquo;的法杖。现在的CTM版本里，影牙城堡改了，只有最终BOSS才会掉这根杖。其实奥杜之杖原本没什么特别，不过自从《我叫MT》播出后，它就因为小德的一句&ldquo;奥杜之杖，又粗又硬&rdquo;出名了。我带影牙的时候，也喜欢给自己收藏一把。久而久之，银行里就全是奥杜之杖了&hellip;&hellip;</p>
<p><img src="/Uploads/wlk03_201205112038180447.PNG" alt="" width="578" height="457" /></p>
<p>当年在冰冠冰川每天还有很多日常，都是地图任务，抓狗头人、杀冰龙、骑马作战什么的，如果你运气好，可能在逛地图的时候发现某些稀有精英。如果你把北极的稀有精英都杀一遍，是有成就的。很可惜我运气不够好，一共只杀过三个，下面的那个只见过一次。</p>
<p><img src="/Uploads/wlk04_201205112039508337.PNG" alt="" width="909" height="560" /></p>
<p>4月末是复活节，那年是我第一次做复活节任务，运气不错开出了个兔子宠物。任务还送了一个物品，可以把别的玩家变成兔子。所以打副本休息的时候总是会见到满地板的兔子。</p>
<p><img src="/Uploads/wlk05_201205112040044993.PNG" alt="" width="583" height="281" /></p>
<p>当年的奥格瑞玛没有现在那么宏伟，进门正面是银行，右手边是拍卖行。因为达拉然城没有拍卖行，所以做生意的基本都在奥格瑞玛往返于银行和拍卖行之间。有一次我刚买完东西回头走出拍卖行时，正巧看见了一个叫&ldquo;穆美女&rdquo;的血精灵牧师妹子，顺手就变了她一个兔子。于是我们就聊了起来。穆美女是之前一起打过TOC的妹子，双天赋都是治疗，职业奶妈。她给我的印象很文静，不像别的魔兽妹子那样喜欢在游戏里发嗲犯骚。其实我一直对牧师妹子有种特别的好感，牧师是神职，每当代表圣洁的白色出现在团队框架中时，作为MT的我总是格外有信心。和穆美女聊上以后，我们成了好朋友，因为各自的工会团都要打ICC不能碰头，所以我们每周都会在一起打TOC团，那时候的感觉，真的很好。</p>
<p><img src="/Uploads/wlk06_201205112040107393.PNG" alt="" width="400" height="196" /></p>
<p>以太空间的活动都是人满为患的，不像前面那个服的小公会总是因为组不齐人而解散。所以每周二、三晚上参加公会活动一定得提前上线报名。有时候我回寝室稍微晚点，就只能替补了。虽然我是T，但以太空间从来就不缺T。替补的时候我只能在副本外面采药、钓鱼，YY里要随时待命。至于采药，倒是有个好去处。冰冠冰川的西南方向，是索拉查盆地，它是泰坦的试验地，遍地都是草药。中间的河流之心是做钓鱼日常的地方。阳光角度好的时候，河流上面是有彩虹的。这个地图绝对是诺森德最安逸的地方，所以替补的时候，我一般都会来索拉查盆地闲逛。</p>
<p><img src="/Uploads/wlk07_201205112041129366.PNG" alt="" width="689" height="404" /></p>
<p>有一次我正在采药，突然看见前面有人在天上灰，一定是和我抢草药的。选中目标一看，居然是穆美女！没想到那么巧，她也没活动，在外面采药。于是我果断上去喊了她。我想起了前几天听说的索拉查盆地有一个彩蛋，是在某个湖泊中心有一段神秘代码，似乎和美国某电视剧有关。正好我们两个都无聊，我就带她一起去看这个彩蛋。这种感觉正好，我一直想在WOW里找个能结伴同行的人，就像《我叫MT》里的那样。可惜，那个WOW已经渐渐远去了。每个人都在忙着打副本，刷装备。也许世界已经忘记了一些比装备和金币珍贵的东西。</p>
<p><img src="/Uploads/wlk08_201205112041239502.PNG" alt="" width="552" height="255" /></p>
<p>WOW里的每一天似乎都是同一天，有时候会渐渐觉得无聊，满级后的那些日子里，每个CD就重复打那几个副本。达拉然城每天都在喊ICC团、TOC团，人来人往的主城渐渐有些烦躁。我经常想起了当年练级的时候遇到的一位朋友&mdash;&mdash;芒果一刀。那位寄给我美味风蛇的朋友。转服过去，又转服回来，我的银行里始终存放着当年他给我的那11条美味风蛇。</p>
<p>也许惊喜总是在出乎意料的时候发生。平静的一天，我在TOC门口拉人的时候，打开好友列表，突然看见芒果一刀在线，他74级，在打蜘蛛本。看来的确已经AFK很久了，可能也不知道我转服的事情。于是我就和他聊了起来，当然，也没有心思认真打那个TOC了。</p>
<p><img src="/Uploads/wlk09_201205112042227467.PNG" alt="" width="357" height="52" /></p>
<p><img src="/Uploads/wlk10_201205112042269587.PNG" alt="" width="367" height="188" /></p>
<p>那天，我们聊得很开心。我也很高兴地带他刷副本升级，忘记了时间&hellip;&hellip;</p>
<p>&ldquo;珍贵的东西，就是让你舍不得丢的东西&rdquo;。</p>
<p>《我叫MT》里的这句朴实的话诠释了WOW带给我的感受。我不知道现在的WOW还有多少真情，这个世界正在渐渐变得像我们的现实社会一样冷酷，一样功利。我想起了练级的时候，想起了那个见到路人会随手给别人拍BUFF的年代，想起了那一次次辛苦练级的日日夜夜、一次次学新技能后的激动、一次次探索新地图的快乐。而这些，正渐渐被金币和GS取代。</p>
<p>能够交一位朋友，尤其是在魔兽世界里，是非常珍贵的。因为在游戏里，面对虚拟的社会，人才会摘下自己用来应付社会的面具，才会以最真实的一面对待别人。我们虽然玩的是虚假的角色，用的是虚假的货币，但一切都要比现实中那些虚伪的笑容要真实的多。我已经对现实疲惫了，厌倦了，这个连亲人也要像敌人的社会早已让我心灰意冷。我沉迷了，沉迷的不是游戏，不是杀人，不是装备，不是金币。而是现实社会花再多钱也买不到的，最简单的人情。</p>]]></description><pubDate>Fri, 11 May 2012 20:43:20 +0800</pubDate></item><item><title>Firefox中强制单元格内容换行</title><link>http://wyjexplorer.cn/Home/View/0CE512E7D55222D6.html</link><description><![CDATA[<p>今天在改网站后台的一个表格，里面有个MD5字段，由于页面宽度有限，表格需要换行。于是我给单元格加了如下的规则：</p>
<pre class="brush: css;fontsize: 100; first-line: 1; ">word-wrap: break-word;
width: 120px;</pre>
<p>&nbsp;结果IE里是好的：</p>
<p><img src="/Uploads/wrapie_201205040946566504.PNG" alt="" width="372" height="121" /></p>
<p>Firefox中没有任何变化：</p>
<p><img src="/Uploads/wrapff_201205040947002540.PNG" alt="" width="350" height="73" /></p>
<p>后来发现需要给表格（table）元素加个属性：</p>
<pre class="brush: css;fontsize: 100; first-line: 1; ">table-layout: fixed;</pre>
<p>&nbsp;现在，Firefox下，表格的单元格就可以自动换行了，不过和IE的效果还是稍微有点差别，有些细节的兼容问题避免不了：</p>
<p><img src="/Uploads/wrapff2_201205040947034364.PNG" alt="" width="374" height="115" /></p>
<p>table-layout属性在W3C的说明中如下：</p>
<p>The table-layout property controls the algorithm used to lay out the table cells, rows, and columns.</p>
<table class="filehistory" style="width: 400px;">
<tbody>
<tr><th width="100">Values</th>
<td>auto | fixed | inherit</td>
</tr>
<tr><th width="100">Initial value</th>
<td>auto</td>
</tr>
<tr><th width="100">Applies to</th>
<td>'table' and 'inline-table' elements</td>
</tr>
<tr><th width="100">Inherited</th>
<td>No</td>
</tr>
</tbody>
</table>
<ul>
<li><code>auto</code><br />Use any automatic table layout algorithm.</li>
</ul>
<ul>
<li><code>fixed</code><br />Use the fixed table layout algorithm.</li>
</ul>
<ul>
<li><code>inherit</code><br />Takes the same specified value as the property for the element's parent.</li>
</ul>]]></description><pubDate>Fri, 04 May 2012 09:51:56 +0800</pubDate></item><item><title>SQL Server 2012入门图解（二）：SQL语句入门</title><link>http://wyjexplorer.cn/Home/View/1954E9D4B1AD6CDA.html</link><description><![CDATA[<p>上次介绍了如何在SQL Server中建立数据库和表，并且做备份和还原。这一次将用上次建立的School数据库做演示，学习SQL语句。本文为0基础入门级别，所以介绍的知识非常有限，例子也是最简单的，还是建议大家买本SQL的书学习。</p>
<p>先回顾一下，上次我们建立的数据库和表结构如下：</p>
<p><img src="/Uploads/sql2_1_201205031949587270.PNG" alt="" width="659" height="200" /></p>
<p>School数据库里只有一张Student表，其中Id是自增长的主键。下面我们以它为例，来演示SQL语句的基本用法。</p>
<p>在SSMS中编写SQL脚本的方法是：点击工具栏上的&ldquo;新建查询&rdquo;，在编辑器中输入SQL脚本，选择一个正确的数据库，检查语法正确后，点击&ldquo;执行&rdquo;，最后在消息面板可以看到执行结果。如下图：</p>
<p><img src="/Uploads/sql2_2_201205031950044522.PNG" alt="" width="610" height="331" /></p>
<p><strong>一、 </strong><strong>使用SQL</strong><strong>语句创建表</strong></p>
<p>除了前面一片文章介绍的用图形化界面建表，我们还可以用SQL语句来创建表，创建Student表的SQL脚本如下：</p>
<pre class="brush: sql;fontsize: 100; first-line: 1; ">CREATE TABLE [dbo].[Student](
         [Id] [int] IDENTITY(1,1) NOT NULL,
         [SName] [nvarchar](50) NULL,
         [Phone] [nvarchar](50) NOT NULL,
         [Address] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_Student] PRIMARY KEY CLUSTERED
(
         [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]</pre>
<p>这段脚本不必去记，可以使用SSMS生成。不过当我们用程序去创建表的时候，就需要手写SQL脚本的能力了。</p>
<p><strong>二、&nbsp; </strong><strong>插入数据</strong></p>
<p>例：向Student表插入一条新记录。</p>
<pre class="brush: sql;fontsize: 100; first-line: 1; ">INSERT INTO [dbo].[Student] ([SName],[Phone],[Address]) VALUES ('Edi','123456','ABCDEF');</pre>
<p>执行完成后，右键点击student表，选择&ldquo;选择前1000行&rdquo;，来检验我们的执行结果。</p>
<p><img src="/Uploads/sql2_3_201205031950086174.PNG" alt="" width="332" height="389" /></p>
<p>在下面的结果面板里，已经显示了Student表现在的数据。</p>
<p><img src="/Uploads/sql2_4_201205031951119067.PNG" alt="" width="347" height="356" />&nbsp;</p>
<p><strong>三、 </strong><strong>查询</strong></p>
<p>在刚才点击&ldquo;选择前1000行&rdquo;之后，你可能注意到了SSMS自动为我们编写了查询脚本。这就是现在要介绍的。</p>
<p>刚才的脚本是：</p>
<pre class="brush: sql;fontsize: 100; first-line: 1; ">SELECT TOP 1000 [Id]
      ,[SName]
      ,[Phone]
      ,[Address]
FROM [School].[dbo].[Student]</pre>
<p>其中TOP 1000表示前1000条记录，通常TOP语句都会和ORDER BY 排序一起使用，这在后面会介绍。如果你希望查询所有的数据，就把TOP 1000去掉即可。</p>
<p>另外，SELECT你可以省略后面的字段，用*代替，表示希望查询所有的字段。</p>
<pre class="brush: sql;fontsize: 100; first-line: 1; ">SELECT * FROM Student</pre>
<p>这条语句的结果和之前是一样的，因为之前的SELECT语句也是筛选全部的字段，并且我们目前只有一条记录。</p>
<p>为了介绍后面的技巧，我先给在表中插入一些别的数据。最后结果如下：</p>
<p><img src="/Uploads/sql2_5_201205031951150267.PNG" alt="" width="446" height="155" /></p>
<p>现在，我们的SELECT语句可以玩更多的花样了。比如：</p>
<p>按Id从大到小排序：</p>
<pre class="brush: sql;fontsize: 100; first-line: 1; ">SELECT * FROM Student ORDER BY Id DESC</pre>
<p>按条件查询（匹配Address为AAAAA）的记录：</p>
<pre class="brush: sql;fontsize: 100; first-line: 1; ">SELECT * FROM Student WHERE Address = 'AAAAA'</pre>
<p><img src="/Uploads/sql2_6_201205031951179595.PNG" alt="" width="241" height="95" /></p>
<p>配合起来也能用：</p>
<p>SELECT * FROM Student WHERE Address = 'AAAAA' ORDER BY ID DESC</p>
<p><img src="/Uploads/sql2_7_201205031951206895.PNG" alt="" width="249" height="98" /></p>
<p><strong>四、 </strong><strong>修改</strong></p>
<p>如果我们需要修改记录，就要用到UPDATE语句。比如Stone的地址改为BBBBB：</p>
<pre class="brush: sql;fontsize: 100; first-line: 1; ">UPDATE STUDENT SET Address = 'BBBBB' WHERE SName = 'Stone'</pre>
<p><img src="/Uploads/sql2_8_201205031951251511.PNG" alt="" width="270" height="152" /></p>
<p>当然，你也可以批量UPDATE，这取决于后面的WHERE语句。</p>
<p><strong>五、</strong><strong>删除</strong></p>
<p>最后我们来学习如何删除记录。这个非常简单，不过得注意WHERE条件，以免误删。比如我要删除Id为5的记录：</p>
<pre class="brush: sql;fontsize: 100; first-line: 1; ">DELETE FROM Student WHERE Id = 5</pre>
<p><img src="/Uploads/sql2_9_201205031951288171.PNG" alt="" width="255" height="161" /></p>
<p>最后扯一个小常识。细心的读者可能注意到了，本文所操作的Student表，Id居然不是连续的，读者可能会问了，这个不是自动加1的吗？却是是这样。但数据库的机制必须确保这个Id的唯一性，因为他是主键，数据库也要保证完整性，因为这个Id可能在别的地方被使用。如果因为删除了某条记录而自动更新这个Id的话，那么引用这个Id的地方就会指向错误的位置，毕竟数据库无法知道这个Id到底最后给谁用了。它可能是别的程序，别的表的外键，或者网络上某篇新闻的Id。</p>
<p>其实最后我想说的是，本文只是0基础入门，没有介绍过任何关系型数据库的基本知识，但这些知识非常重要，读者如果想学SQL Server或者其他数据库，一定得去看有关的书籍。</p>]]></description><pubDate>Thu, 03 May 2012 19:54:52 +0800</pubDate></item><item><title>ASP.NET中使用Response方式下载文件</title><link>http://wyjexplorer.cn/Home/View/0281543983665AA6.html</link><description><![CDATA[<p>今天在修改我博客的文件管理功能，尝试解决一直以来的一个问题。即IIS中没有注册MIME映射的文件类型，是无法直接用Http Get方式下载的，也就是不能点击超链接直接转向文件位置。比如7z压缩包，如果直接下载，会是这个样子：</p>
<p><img src="/Uploads/responsedown1_201205031057383885.PNG" alt="" width="799" height="407" /></p>
<p>后来我想到了以前Gridview输出Excel的方式，是通过Response传输字节流的。稍微查阅了一下，发现ASP.NET的Response对象现在有了一个新的方法：TransmitFile()，不过它在MSDN上的描述不是很详细。</p>
<p>具体做法是这样的：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">Response.ContentType = "application/x-compress";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename=要输出的文件名"));
Response.TransmitFile(文件在服务器上的绝对路径));
Response.End();</pre>
<p>现在我的7z压缩包就可以使用Response方式下载了（尽管ContentType可能不太正确）：</p>
<p><img src="/Uploads/responsedown2_201205031057431309.PNG" alt="" width="787" height="415" /></p>
<p>这种方法同样也可以用来输出App_Data等受保护文件夹中的文件。比如网站采用Access数据库，用户希望定期下载备份文件，就可以用Response.TransmitFile来做，不然ASP.NET默认是不让用户访问App_Data文件夹的。</p>]]></description><pubDate>Thu, 03 May 2012 10:59:16 +0800</pubDate></item><item><title>ASP.NET中用Ctrl+S触发按钮事件</title><link>http://wyjexplorer.cn/Home/View/8919B704FC0E9C8F.html</link><description><![CDATA[<p>这个也是上礼拜印度队友给我留的&ldquo;作业&rdquo;，今天搞定了。场景是某个页面，用户输入内容后，希望按Ctrl+S直接提交保存。也就是要用Ctrl+S去触发保存按钮的Click事件。然而在浏览器中，Ctrl+S默认是保存网页（Firefox下就是这样），所以需要写一个可以覆盖浏览器自身快捷键的脚本，去触发按钮事件。</p>
<p>我写了个最简单的Demo，效果如下：点击Button后，会显示一句话以及触发时间。现在需要用Ctrl+S来触发这个事件。注意，先得引入JQuery库。</p>
<p><img src="/Uploads/ctrls_201205021202588622.PNG" alt="" width="586" height="200" /></p>
<p>第一种方法是：</p>
<pre class="brush: jscript;fontsize: 100; first-line: 1; ">$(window).keypress(function (event) {
    if (!(event.which == 115 &amp;&amp; event.ctrlKey) &amp;&amp; !(event.which == 19)) {
        return true;
    }

    $('#Button1').click();

    event.preventDefault();
    return false;
});</pre>
<p>第二种方法（更加通用）：采用jquery.hotkeys.js，引入这个JS库后，代码更加简单明了，并且你可以很轻松的绑定任意键和组合键。</p>
<pre class="brush: jscript;fontsize: 100; first-line: 1; ">function bindKey() {
    jQuery.hotkeys.add('Ctrl+s', function () {
        $('#Button1').click();
    });
}

$(document).ready(bindKey);</pre>
<p>注意，用jquery.hotkeys.js的时候，使用alert调试，是不会覆盖浏览器自身快捷键的，千万不要以为功能不好用。如果去掉alert，一切正常。</p>]]></description><pubDate>Wed, 02 May 2012 12:04:11 +0800</pubDate></item><item><title>SQL Server 2012入门图解（一）：建表、备份、还原</title><link>http://wyjexplorer.cn/Home/View/DDCC3F8BF94472A0.html</link><description><![CDATA[<p>本文很菜，旨在帮助0基础的初学者入门，高手勿看。关于SQL Server 2012的安装可以看我的这篇文章《<a href="/Home/View/6206245B896D6CDE.html" target="_blank"><span id="ctl00_MainContent_txtBlogTitle">SQL Server 2012 Express 安装图解</span></a>》。</p>
<p><strong>一、建立你的第一个数据库和表</strong></p>
<p>例：建立一个用于描述一个学校学生情况的数据库。把它命名为School。并且要在School数据库下建立保存学生信息的表Student。在可视化界面下，我们通常这样操作。（本文是入门教程，不介绍如何用SQL语句建表）</p>
<p>1.&nbsp;&nbsp; &nbsp;连接到本地数据库引擎后，右击数据库，选择【新建数据库】。</p>
<p><img src="/Uploads/newdb1_201205011750475619.PNG" alt="" width="377" height="394" /></p>
<p>2.&nbsp;&nbsp; &nbsp;在弹出的对话框中，把数据库名称设置为School，其他参数保留默认。</p>
<p><img src="/Uploads/newdb2_201205011750499799.PNG" alt="" width="705" height="636" /></p>
<p>3.&nbsp;&nbsp; &nbsp;刷新视图，可以看到School数据库已经建立成功了。</p>
<p><img src="/Uploads/newdb3_201205011750525383.PNG" alt="" width="372" height="416" /></p>
<p>4.&nbsp;&nbsp; &nbsp;下面我们要在这个数据库中新建一张表。展开School数据库，右击&ldquo;表&rdquo;，选择&ldquo;新建表&rdquo;。</p>
<p><img src="/Uploads/newtable1_201205011750567815.PNG" alt="" width="376" height="383" /></p>
<p>5.&nbsp;&nbsp; &nbsp;右边的窗口是表的可视化界面，在这里可以设计一张表，如图：</p>
<p><img src="/Uploads/newtable2_201205011751005879.PNG" alt="" width="398" height="160" /></p>
<p>6.&nbsp;&nbsp; &nbsp;完成之后，我们需要把Id设置为主键，表示它是不重复的值，用来唯一确定一条记录，这对以后的数据操作至关重要。</p>
<p><img src="/Uploads/newtable3_201205011751045035.PNG" alt="" width="399" height="323" /></p>
<p>设置完成后，Id前面会有个小钥匙的图标。设置主键自增长的方法是在&ldquo;标识规范&rdquo;中的&ldquo;是标识&rdquo;中，选择&ldquo;是&rdquo;</p>
<p><img src="/Uploads/newtable4_201205011751083255.PNG" alt="" width="481" height="458" /></p>
<p>7.&nbsp;&nbsp; &nbsp;完成后，按Ctrl+S，保存这张表，表名称为Student。</p>
<p><img src="/Uploads/newtable6_201205011751184031.PNG" alt="" width="396" height="261" /></p>
<p>8.&nbsp;&nbsp; &nbsp;再次刷新视图，可以看到我们的Student表已经建立成功了。</p>
<p><img src="/Uploads/newtable7_201205011751231143.PNG" alt="" width="247" height="463" /></p>
<p><strong>二、如何备份数据库</strong></p>
<p>为了数据安全，我们需要定期备份数据。在SQL Server 2012中，通常这样做。注意界面稍微和SQL Server2008有所不同。还是以School数据库为例。</p>
<p>1. 在School数据库上点击右键，选择任务，备份。</p>
<p><img src="/Uploads/bak1_201205011749587182.PNG" alt="" width="544" height="363" /></p>
<p>2. 在目标中，选择&ldquo;添加&rdquo;。</p>
<p><img src="/Uploads/bak2_201205011750035074.PNG" alt="" width="703" height="634" /></p>
<p>3. 选择一个备份的位置。这个位置你必须有权限访问，不然备份要报错。</p>
<p><img src="/Uploads/bak3_201205011750356903.PNG" alt="" width="560" height="294" /></p>
<p><img src="/Uploads/bak4_201205011750386075.PNG" alt="" width="548" height="700" /></p>
<p>（上图稍有误，建议给文件加上.bak后缀）</p>
<p>3. 添加完成后，点击确定，开始备份。</p>
<p><img src="/Uploads/bak5_201205011750418055.PNG" alt="" width="514" height="246" /></p>
<p>4. 备份成功完成。</p>
<p><img src="/Uploads/bak6_201205011750445043.PNG" alt="" width="615" height="128" /></p>
<p><strong>三、如何恢复数据库</strong></p>
<p>在SQL Server 2012中，恢复数据库的界面也和以往有所不同。具体操作如下，以School数据库的备份文件为例。</p>
<p>1. 在数据库文件夹上点右键，选择&ldquo;还原数据库&rdquo;</p>
<p><img src="/Uploads/restore1_201205011751289955.PNG" alt="" width="284" height="314" /></p>
<p>2. 选择&ldquo;设备&rdquo;，然后将school的备份文件加入列表。</p>
<p><img src="/Uploads/restore2_201205011751339720.PNG" alt="" width="872" height="695" /></p>
<p>3. 检查数据库名称，并选择还原后，点击确定，开始执行。</p>
<p><img src="/Uploads/restore3_201205011752217392.PNG" alt="" width="867" height="693" /></p>
<p>4. 成功还原。</p>
<p><img src="/Uploads/restore4_201205011752261540.PNG" alt="" width="308" height="139" /></p>]]></description><pubDate>Tue, 01 May 2012 18:07:55 +0800</pubDate></item><item><title>SharePoint中用ESC键关闭弹出对话框</title><link>http://wyjexplorer.cn/Home/View/47C0E2DE4F44A573.html</link><description><![CDATA[<p>今天早上被印度队友Hi了一下，提了个难题给我。要用ESC键关闭SharePoint中弹出的模态对话框，自己搞了一天总是有bug。唉，我这个C#程序猿一直被当前端用，伤不起啊。后来我在MSDN上找到了解决办法，并测试可用。国内的网络暂时没有找到这方面的文章。</p>
<p>代码如下：</p>
<pre class="brush: jscript;fontsize: 100; first-line: 1; ">$(document).ready(function() {
        $('body').bind('keypress', function(e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if (code == 27) {
            SP.UI.ModalDialog.commonModalDialogClose(1, 'Submitted');
        }
    });
});</pre>
<p>ESC的keyCode是27。调用的是SP.UI.ModalDialog.commonModalDialogClose()方法。这个ModalDialog本身有个Close，但似乎是C#里写的。我试过那个close是没用的。</p>
<p>MSDN上的原文在：<a href="http://social.technet.microsoft.com/Forums/sv-SE/sharepoint2010programming/thread/7965f57d-8fae-45a9-9f48-954d8a4d4edd" target="_blank">http://social.technet.microsoft.com/Forums/sv-SE/sharepoint2010programming/thread/7965f57d-8fae-45a9-9f48-954d8a4d4edd</a></p>]]></description><pubDate>Mon, 30 Apr 2012 16:41:03 +0800</pubDate></item><item><title>C#读取Excel单元格中的日期</title><link>http://wyjexplorer.cn/Home/View/BE4064EC418718BE.html</link><description><![CDATA[<p>今天写一小程序用来分析某Excel报表，结果在处理日期的时候蛋疼了。</p>
<p>原Excel是这样的:</p>
<p><img src="/Uploads/exceldateorgfile_201204251608226035.PNG" alt="" width="552" height="66" /></p>
<p>Excel加载到DataTable以后，日期都变成了这个样子：</p>
<p><img src="/Uploads/exceldate0_201204251608270807.PNG" alt="" width="397" height="108" /></p>
<p>看起来很像某偏移量。当然也有一部分日期是正常的：</p>
<p><img src="/Uploads/exceldate1_201204251608316204.PNG" alt="" width="159" height="78" /></p>
<p>我尝试用DateTime.Parse直接匹配，结果爆掉了。于是查了下MSDN找到了正确的办法：DateTime.FromOADate(double d) 方法:</p>
<p><span id="mt5" class="sentence" data-guid="479f68dcffa66403b54122c2ed422913" data-source="The <span class=">d</span> 参数是一个双精度浮点数字，它将日期表示为基础日期（1899 年 12 月 30 日午夜）之前或之后的天数。 <span id="mt6" class="sentence" data-guid="8ddf909b8a3586949fe6ea9f112d1c51" data-source="The sign and integral part of <span class=">d</span> 的符号和整数部分将日期编码为相对于 1899 年 12 月 30 日的正负日偏移量，而 <span class="parameter">d</span> 的小数部分的绝对值将当天的时间编码为相对于午夜的小数日偏移量。<span class="parameter">d</span> 必须为负 657435.0 到正 2958466.0 之间的值。</p>
<p>根据我的Excel，我封装了一下转换函数，如下：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">private DateTime ConvertExcelDateTimeIntoCLRDateTime(object value)
{
    if (value is DateTime)
    {
        return DateTime.Parse(value.ToString());
    }
    else
    {
        string dt = DateTime.FromOADate(Convert.ToInt32(value)).ToString("d");
        return DateTime.Parse(dt);
    }
}</pre>
<p>这个函数首先判断日期是否能直接转换，因为我需要处理上图中F12列这样的日期。如果不能识别，就调用FromOADate()，将偏移量转换为日期。</p>
<p>于是就OK了，有图有真相：</p>
<p><img src="/Uploads/exceldate2_201204251608361444.PNG" alt="" width="209" height="347" /></p>]]></description><pubDate>Wed, 25 Apr 2012 16:15:02 +0800</pubDate></item><item><title>代码的咖喱味</title><link>http://wyjexplorer.cn/Home/View/93565D753FD3EF23.html</link><description><![CDATA[<p>最近印度把某项目移交给了我们China Team，所以这几天在研读代码。当我抱着对印度IT无比崇敬和赞美的心情打开印度交给我们的代码时，我的菊花瞬间就紧了一下，并且我的二进制狗眼也被刺瞎了。</p>
<p>首先映入眼帘的是某3470行的类（恩，这还不是最大的那个类），它的确是一个类，不过可能和大家设想的&ldquo;类&rdquo;不太一样。因为它不是一个可重用的class，它只是某页面的code behind，入口是page_load，这个page_load就有280行。某队友看到的方法，更是有900行之多。暂且不论这个类实现的功能如何，光是理清这几千行的一个类，我就对作者深厚的面向过程能力深表敬佩。</p>
<p><img src="/Uploads/fuckcode0_201204251408488997.png" alt="" width="251" height="145" /></p>
<p>我没有用代码分析工具，先大致用二进制狗眼扫描了一下这些代码，其中不乏：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">iflag = 1;
break;
&hellip;
if (iflag == 1)</pre>
<p>这样的代码。我瞬间想起了曾经的C语言，作者的代码唤醒了我从前的记忆&mdash;&mdash;在大学寝室自学C语言的一幕幕，啊，感动的泪流满面有木有。</p>
<p>继续看代码，惊喜之处层出不穷。default1，test123之类的变量总是能带给你无穷的乐趣。无数的if嵌套让我感觉像俄罗斯套娃，并且这些if块中，仅仅变了一个参数，做的事情都是一样的。作者也没有把这相同的逻辑提取出来作为一个函数，而是一遍遍地复制，粘贴，只改一个参数。</p>
<p><img src="/Uploads/fuckcodeif_201204251408548433.png" alt="" width="227" height="571" /></p>
<p>这，也许，大概，可能，当年是按LOC收费的吧。</p>
<p><img src="/Uploads/fuckcode_201204251408408501.png" alt="" width="365" height="609" /></p>
<p>另外，数组、ArrayList等很初级的容器，也深受爱戴，我愣是没找到任何List&lt;T&gt;，更别说接口类型等等面向对象的结构了。Solution中的项目，也只是假分层。用数据库基本都是就地开连接，就地取数据，有时还没有try catch。</p>
<p>披着面向对象的皮，干着面向过程的事。</p>
<p>我不知道是什么样的人写出的这些代码，我也不想讽刺谁，但这绝非个别行为。我也不知道这样的代码是如何通过审查的，或许，根本没有做过审查吧。不过印度人能让这几千行的类工作起来，不愧是开挂的民族。我也很震惊，某软件巨头企业是如何发展到今天的。我只是觉得，作为程序猿，写代码至少得对将来维护他的人负责。进了如此蛋疼的项目让我感觉十分不爽，现在要做二期了，不知道什么时候才能解脱。</p>]]></description><pubDate>Wed, 25 Apr 2012 14:11:02 +0800</pubDate></item><item><title>简单性能测试：使用Stopwatch测算程序执行时间</title><link>http://wyjexplorer.cn/Home/View/A4F24919571134B2.html</link><description><![CDATA[<p>今天逛博客园，发现有人写了一篇关于List&lt;T&gt;.FindAll()和For循环性能的文章，作者木有给出他的代码，因此不晓得他是怎么测时间的。我以前做这种很简单的性能测试往往都是定义两个datetime，dt1放在算法开始之前，dt2放在算法结束之后。最后用dt2-dt1计算出算法执行的时间。我相信许多人都是这么做的，并且我以前看MSDN Webcast的时候，连微软的MVP都是这样做的。所以我对datetime测时间的方法深信不疑。</p>
<p>不过在那片文章的回复中，我看到有人贴出了一段测试代码，其中用的是Stopwatch类。略有意思，于是研究了一下。</p>
<p>对Stopwatch的描述是这样的:</p>
<p>Stopwatch 实例可以测量一个时间间隔的运行时间，也可以测量多个时间间隔的总运行时间。 在典型的 Stopwatch 方案中，先调用 Start 方法，然后调用 Stop 方法，最后使用 Elapsed 属性检查运行时间。</p>
<p>Stopwatch 实例或者在运行，或者已停止；使用 IsRunning 可以确定 Stopwatch 的当前状态。 使用 Start 可以开始测量运行时间；使用 Stop 可以停止测量运行时间。 通过属性 Elapsed、ElapsedMilliseconds 或 ElapsedTicks 查询运行时间值。 当实例正在运行或已停止时，可以查询运行时间属性。 运行时间属性在 Stopwatch 运行期间稳固递增；在该实例停止时保持不变。</p>
<p>默认情况下，Stopwatch 实例的运行时间值相当于所有测量的时间间隔的总和。 每次调用 Start 时开始累计运行时间计数；每次调用 Stop 时结束当前时间间隔测量，并冻结累计运行时间值。 使用 Reset 方法可以清除现有 Stopwatch 实例中的累计运行时间。</p>
<p>一个最简单的例子如下：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">Stopwatch watch = new Stopwatch();

watch.Start();
// 你的算法
watch.Stop();

// 算法执行的时间
Console.WriteLine("FindAll:" + watch.ElapsedMilliseconds);</pre>
<p>和我们之前使用datetime的方法非常相似。不过我相信既然微软提供了Stopwatch这样一个专门做时间计算的类，那一定是有它的道理的。所以以后做简单的性能测试，我建议大家采用Stopwatch。</p>
<p><a href="http://msdn.microsoft.com/zh-cn/library/system.diagnostics.stopwatch.aspx" target="_blank">Stopwatch on MSDN</a></p>]]></description><pubDate>Tue, 24 Apr 2012 13:58:16 +0800</pubDate></item><item><title>HTML5学习小结</title><link>http://wyjexplorer.cn/Home/View/01C07A26FBF9E093.html</link><description><![CDATA[<p>前段时间公司培训了几次HTML5，虽然我还没有实际应用过，但看着好像很厉害的样子！下面总结一下初步的学习收获。</p>
<p><strong>一、更改的标签</strong></p>
<p>HTML5的DOCTYPE标记和以前不一样了。现在只需要一个&ldquo;&lt;!DOCTYPE html&gt;&rdquo;就完成了。文字编码和以往类似，写在meta标签里。如果要让屏幕阅读器等设备知道网站所采用的语言，就在html标记后面加个lang属性，比如&ldquo;&lt;html lang="en"&gt;&rdquo;。一个最简单的结构如下：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;!DOCTYPE html&gt;
&lt;meta charset="UTF-8" /&gt;
&lt;html lang="en"&gt;
    &lt;head&gt;
        &lt;title&gt;Fuck with HTML5&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre>
<p>如果要引入CSS和Javascript，也和以前稍有不同，HTML5是这样引用的：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;link rel="stylesheet" href="styles.css" /&gt;
&lt;script src="scripts.js"&gt;&lt;/script&gt;</pre>
<p>注意，script标记不再有language和type了，style也没有type了。</p>
<p><strong>二、新的标签</strong></p>
<p>HTML5提供了非常语义化的新标签，这些都是根据以往网页设计的经验，提取出的最常用的部分。比如header, footer, nav, aside,section,article以及其他很多新的标签，他们为搜索引擎减轻了很多负担，让网页的内容能够被更准确的解析。这个意义很重要，尤其是对于机器和机器之间的通讯，html5的确优化了许多。下面我们来看看一些最常用的新标签：</p>
<p>首先，布局常用的有：</p>
<p>&lt;header&gt;：表示页面的头部，也就是以前我们喜欢写的&lt;div id=&rdquo;header&rdquo;&gt;，里面常常有logo和导航栏。不过在html5中，header标记也可以作为一小块内容的头部。也就是，可以重复多次。</p>
<p>&lt;footer&gt;：尾部，没啥特别的</p>
<p>&lt;nav&gt;：导航栏。</p>
<p>&lt;aside&gt;：边栏，现在的网站通常都是多列布局的，起辅助作用的边栏就是aside。</p>
<p>&lt;section&gt;：表示一块区域。它的概念是具有相互关联的，可以被划分为一组信息的区域。</p>
<p>&lt;article&gt;：表示一篇文章。</p>
<p>在网站中，尤其是搜索结果的页面，通常需要高亮显示关键词，现在做这件事很方便，只要用HTML5的mark标记。比如：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;p&gt;今天我读完了&lt;mark&gt;ASP.NET&lt;/mark&gt;高级编程&lt;/p&gt;</pre>
<p>对于图片，HTML5也有新的方式去描述：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;figure&gt;
    &lt;img src="图片文件" alt="描述 " /&gt;
    &lt;figcaption&gt;图片的标题&lt;/figcaption&gt;
&lt;/figure&gt;</pre>
<p>在处理时间和日期的显示上，我们有了新的time标签：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;time datetime="2012-04-23"&gt;2012年4月23日&lt;/time&gt;</pre>
<p>其他标签不一一列举了，读者可以去查阅Oreilly的书。</p>
<p><strong>三、处理表单</strong></p>
<p>对表单的优化，是HTML5最让我感到实用的改进。尤其是在验证用户输入上，HTML5定义了许多常用的数据类型，客户端验证将由浏览器自己完成，不用再自己去写javascript了。</p>
<p>比如，定义一个文本框，让用户输入email，并且我们要验证email格式是否正确，可以这样写：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;input type="email" name="email"&gt;</pre>
<p>很简单，这样浏览器根据type=&rdquo;email&rdquo;就知道要用email地址的规则去验证用户的输入。</p>
<p>其他类似的type属性有：url,tel,datetime,date,time,number,甚至是color等等。其中datetime可以弹出日历，以前这件事得用jquery UI来做。Number则可以像winform那样具有上下两个小箭头。部分标签也可以设置最小值、最大值。比如：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;input type="number" name="quantity" min="2" max="20"&gt;</pre>
<p><strong>四、原生的音频、视频</strong></p>
<p>HTML5的又一大牛逼之处在于它内置了对音频、视频的定义。以往我们都是用flash或Silverlight等三方插件来做播放器的。现在可以用原生的了。</p>
<p>音频标记是：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;audio src="music.ogg" controls&gt;&lt;/audio&gt;</pre>
<p>视频标记是：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;video src="video.ogv" controls&gt;&lt;/video&gt;</pre>
<p>但是，目前各大浏览器对媒体格式的支持都不统一。比如mp4格式，火狐就不能直接识别的，但safari可以。</p>
<p>为了兼容不同的浏览器，我们可能需要准备一个视频的多种格式。然后代码这样写：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;video controls&gt;
    &lt;source src="video.mp4" /&gt;
    &lt;source src="video.ogv" /&gt;
    Your device does not support HTML5 video.
&lt;/video&gt;</pre>
<p>如果浏览器不支持mp4，它就会选择ogv格式。</p>
<p><strong>五、Canvas绘图</strong></p>
<p>我们以前制作图表，都是通过后台程序生成静态图片然后放到网页上实现的。如果稍微高级一点，恐怕就要客户端装插件了。现在HTML5的Canvas绘图，能够直接在页面上绘制图表。它使用的是&lt;canvas&gt;标记。</p>
<p>比如我们要在页面上画一个黄色的三角（这个例子取自<a href="http://www.williammalone.com/articles/html5-canvas-example/#subTitle1" target="_blank">http://www.williammalone.com/articles/html5-canvas-example/#subTitle1</a>）：</p>
<p>首先，在页面上定义一个canvas标记：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;canvas id="canvasId" width="165px" height="145px"&gt;&lt;/canvas&gt;</pre>
<p>然后在JavaScript中找到这个canvas的context：</p>
<pre class="brush: jscript;fontsize: 100; first-line: 1; ">var context = document.getElementById("canvasId").getContext("2d");</pre>
<p>接下来，就可以绘制三角形了：</p>
<pre class="brush: jscript;fontsize: 100; first-line: 1; ">var width = 125;  // Triangle Width
var height = 105; // Triangle Height
var padding = 20;

// Draw a path
context.beginPath();
context.moveTo(padding + width/2, padding);        // Top Corner
context.lineTo(padding + width, height + padding); // Bottom Right
context.lineTo(padding, height + padding);         // Bottom Left
context.closePath();

// Fill the path
context.fillStyle = "#ffc821";
context.fill();</pre>]]></description><pubDate>Mon, 23 Apr 2012 10:32:25 +0800</pubDate></item><item><title>Windows 7设置VPN图解</title><link>http://wyjexplorer.cn/Home/View/EEBFD0F07A5A1D7A.html</link><description><![CDATA[<p>在国内上网，因为国情需要，难免搜索被打断，谷歌被重置，让人很是蛋疼。于是我买了个VPN，用了半年还不错。下面教大家设置方法：</p>
<p>注意，前提条件是你得有个VPN帐号和一个可用的internet 连接。</p>
<p>1.&nbsp;&nbsp; &nbsp;右击任务栏系统托盘处的网络图标，打开网络和共享中心，在&ldquo;更改网站设置&rdquo;中，选择第一项：设置新的连接或网络</p>
<p><img src="/Uploads/win7vpn01_201204220907369836.PNG" alt="" width="474" height="271" /></p>
<p>2.&nbsp;&nbsp; &nbsp;选择&ldquo;连接到工作区&rdquo;</p>
<p><img src="/Uploads/win7vpn02_201204220907400568.PNG" alt="" width="631" height="498" /></p>
<p>3.&nbsp;&nbsp; &nbsp;选择&ldquo;使用我的Internet连接(VPN)&rdquo;</p>
<p><img src="/Uploads/win7vpn03_201204220907435356.PNG" alt="" width="628" height="499" /></p>
<p>4.&nbsp;&nbsp; &nbsp;在Internet地址中输入你的VPN供应商提供的服务器地址。目标名称是你这个连接的名字，可以任意。</p>
<p><img src="/Uploads/win7vpn04_201204220907475761.PNG" alt="" width="628" height="498" /></p>
<p>5.&nbsp;&nbsp; &nbsp;输入你VPN帐号的用户名和密码，建议勾选&ldquo;记住密码&rdquo;</p>
<p><img src="/Uploads/win7vpn05_201204220907526929.PNG" alt="" width="632" height="499" /></p>
<p>6.&nbsp;&nbsp; &nbsp;点击连接，稍等片刻，系统提示已经连接。</p>
<p><img src="/Uploads/win7vpn06_201204220907578877.PNG" alt="" width="501" height="225" /></p>
<p>7.&nbsp;&nbsp; &nbsp;现在，你就可以上真正的互联网了。</p>
<p><img src="/Uploads/win7vpn08_201204220908068889.PNG" alt="" width="713" height="419" /></p>
<p>8.&nbsp;&nbsp; &nbsp;注意到，你的网络连接中已经多出了一项VPN。可以直接连接和断开，很方便。</p>
<p><img src="/Uploads/win7vpn07_201204220908010545.PNG" alt="" width="291" height="446" /><br /><br /></p>]]></description><pubDate>Sun, 22 Apr 2012 09:10:15 +0800</pubDate></item><item><title>使用Visual Studio在VMWare虚拟机上远程调试程序</title><link>http://wyjexplorer.cn/Home/View/6C980041516716EF.html</link><description><![CDATA[<p>我用的是VMWare8，安装的时候附送了我一个Visual Studio的插件，似乎是跨机器调试程序用的。也就是在主机的VS上调试虚拟机中的程序，看着很牛逼，于是稍微研究了一下。下面是攻略：</p>
<p>我建了个很简单的控制台程序用来演示。断点加在了主函数入口。</p>
<p><img src="/Uploads/vmdebug00_201204211017023892.PNG" alt="" width="470" height="318" /></p>
<p>第一步：启动虚拟机，我用的是一台XP的虚拟机，记得安装VMWare Tools，要调试.NET程序也当然要安装对应的.NET Framework。然后，去【控制面板\管理工具\本地安全设置\本地策略\安全选项】中，把网络访问：本地帐户的共享和安全模式改成“经典”，如图：</p>
<p><img src="/Uploads/vmdebug01_201204211017065544.PNG" alt="" width="781" height="391" /></p>
<p>第二步：在虚拟机中增加一个和主机当前登录帐户一模一样的帐户。比如主机的帐户是Edi_Wang，密码是123456，那么虚拟机上也得建立同样的用户，并且放在管理员组，然后用这个帐户重新登录虚拟机。</p>
<p>第三步：打开虚拟机设置，在Options选项卡中，找到Shared Folders，设置为Always Enabled，然后将VS工程的Debug目录共享出来。</p>
<p><img src="/Uploads/vmdebug02_201204211017112500.PNG" alt="" width="677" height="588" /></p>
<p>比如我的工程是：E:\DotNetProjects\VMDebugTest\VMDebugTest\bin\Debug，那我就在共享里打开这个目录，如下图所示。</p>
<p><img src="/Uploads/vmdebug03_201204211017153060.PNG" alt="" width="445" height="441" /></p>
<p>这一步很重要，之后VS里的VMWare Debug插件需要用到这个共享。如果能在虚拟机里访问这个路径，那就说明设置成功了。到此，虚拟机上的设置完毕。</p>
<p><img src="/Uploads/vmdebug04_201204211017195960.PNG" alt="" width="437" height="191" /></p>
<p>第四步：在VS的工具栏上找到VMWare插件，打开设置界面。</p>
<p><img src="/Uploads/vmdebug05_201204211017244164.PNG" alt="" width="704" height="507" /></p>
<p>我们需要指定的有：</p>
<ol>
<li>Virtual Machine：指定为我们当前正在运行的那个虚拟机</li>
<li>Guest Command（重要）：指定为刚才配置的路径，即\\vmware-host\Shared Folders\Debug\VMDebugTest.exe。注意不要直接输入，要点右边的小箭头，选择run guest command才能设置成功。</li>
<li>Shared Folders：和刚才配置共享一样，指定为Debug文件夹，指向的是E:\DotNetProjects\VMDebugTest\VMDebugTest\bin\Debug</li>
</ol>
<p>其他选项默认应该都指定好了，如果有误，大家可以自己改一下。</p>
<p>然后，我们就可以启动调试了，有图有真相：</p>
<p><img src="/Uploads/vmdebug06_201204211017282697.PNG" alt="" width="698" height="452" /></p>]]></description><pubDate>Sat, 21 Apr 2012 10:20:15 +0800</pubDate></item><item><title>刚进IT公司的大学生需要掌握的技能与术语</title><link>http://wyjexplorer.cn/Home/View/1D05F33977031BBA.html</link><description><![CDATA[<p>进Infosys实习已经一年了，还有几个月就可以毕业转正了。在这一年里，我目睹了很多刚进公司的大学生蛋疼的事情，现在的大学生们，不管哪个大学的，好多人都没什么有实践经验，根本配不来环境，装个软件也会搞砸，如果没有熟人带一下，估计就跪了，做事一点也不像个计算机专业，专业，专业！！的学生，呵呵。我是看在眼里，疼在蛋上。我不是在炫耀我有多牛逼，我只是觉得现在的大学，和大学生们，真该好好反省一下了。下面切入正题：</p>
<p>本文不会探讨操作细节，只是列出一个提纲供大家检索。当然不是每个公司的情况都一样的，我下面说的都是我在Infosys的体会。</p>
<p><strong>必要技能：</strong></p>
<p>1.使用远程桌面</p>
<p>公司管理服务器，一般都不会要你自己上机操作，用的都是远程桌面。这是Windows自带的功能，分为客户端和服务端。服务器只要打开了这个服务，你就可以用远程桌面客户端连接上去了（开始、运行、mstsc）。使用很简单，没什么好说。但你一定也要会配置服务端。</p>
<p>2.开发环境的安装和配置</p>
<p>这个是最基本的技能了，如果连电脑都不会装，还说自己搞IT就太可笑了。给大家的建议是，在自己电脑上装点虚拟机，不同环境都去试试。另外，还要熟练掌握Windows的使用，包括服务器系统，如何配置防火墙、组策略等等。</p>
<p>3.用Outlook发邮件</p>
<p>学会发邮件、抄送、安排会议、日历等常用功能。</p>
<p>4.使用Live Meeting</p>
<p>公司开会用的软件，因为开会的人不总是在一起的。</p>
<p>5.安装和使用虚拟机</p>
<p>去熟悉一下几款常用的虚拟机软件：VMWare, Virtual Box, Microsoft Virtual PC。开发和测试经常用到的。</p>
<p>6.使用IP电话</p>
<p>你可能需要和公司内部或客户打电话交流，并且使用的可能不是一般的电话。所以你需要了解IP电话的操作方法。</p>
<p>7.使用公司内部系统</p>
<p>这个一般都会有人培训。</p>
<p>8.快速熟悉开发框架的能力</p>
<p>公司不是秀自己算法能力的地方，公司讲究开发效率，所以通常会用框架，可能是自己做的，也可能是公共的。并且，你是没有选择余地的，你会被要求使用框架，而不是什么都自己写以突出自己的牛逼。所以快速适应框架的能力是必要的。</p>
<p>9.表达能力</p>
<p>语言组织和表达能力。你技术可以牛逼，但如果不懂得交流，那永远只有电脑睬你。</p>
<p><strong>术语：</strong></p>
<p>AD：Active Directory，就是Windows域，用来管理公司网络中的帐号，这些帐号称为域帐号，平时开机就用这个帐号登录，并且内网发邮件、使用内部系统一般都用它。</p>
<p>OC：Office Communicator，微软的局域网聊天软件，很垃圾的软件，还没QQ好。</p>
<p>CC：抄送。</p>
<p>PFA：Please find attachment，看一下附件。</p>
<p>ASAP：As soon as possible。</p>
<p>PING：ping someone的意思是在OC上喊某人。</p>
<p>如有不足，欢迎补充，如有意见，欢迎拍砖。</p>]]></description><pubDate>Fri, 20 Apr 2012 10:48:01 +0800</pubDate></item><item><title>VS2010类模板的修改</title><link>http://wyjexplorer.cn/Home/View/A8B07CF7C48A298C.html</link><description><![CDATA[<p>在公司里写程序，往往都有规定的代码模板，比如要求每个类都有注释，说明开发者是谁，类的功能，以及其他信息。如果每次建一个类，手工去复制这些信息很麻烦，也容易遗漏。我们可以直接修改VS2010创建类的时候所用的模板，帮我们加上这些信息。</p>
<p>VS的模板位于这个路径：[你的VS安装目录]\Common7\IDE\ItemTemplatesCache<br />C# Class的模板在 CSharp\Code\[你安装的VS语言版本代码]\Class.zip</p>
<p>比如我的机器上，64位环境，英文版VS(1033)，则我可以找到这个位置：<br />C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ItemTemplatesCache\CSharp\Code\<strong>1033</strong>\Class.zip</p>
<p>我们修改这个压缩包里的Class.cs，并保存。重启VS后，就可以生效了。</p>
<p>我的模板如下：加了注释片段、把using语句挪到namespace下、默认把类声明为public。大家可以按照自己的需求改。</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">/*********************************************************
 * Developer：Edi Wang
 * Create Time：$time$
 * Description：
 * 
 * Update History：
 * 
 * *******************************************************/

namespace $rootnamespace$
{
	using System;
	using System.Collections.Generic;
	$if$ ($targetframeworkversion$ >= 3.5)using System.Linq;
	$endif$using System.Text;
	
	public class $safeitemrootname$
	{
	
	}
}</pre>
<p>效果如下： </p>
<p><img src="/Uploads/vscstemplate_201204131434512165.PNG" alt="" width="501" height="366" /></p>]]></description><pubDate>Fri, 13 Apr 2012 14:35:11 +0800</pubDate></item><item><title>SQL Server 2012 Express 安装图解</title><link>http://wyjexplorer.cn/Home/View/6206245B896D6CDE.html</link><description><![CDATA[<p>前段时间微软发布了最新最犀利的SQL Server 2012，我第一时间下载回来尝鲜。在3台机器上实验安装了一下，都没有出问题。安装过程和以往类似，写这篇文章的目的是帮助刚接触SQL Server的初学者入门。高手请直接飘过。</p>
<p>首先，安装SQL Server需要注意的是它的版本。微软最新发布的是SQL Server 2012，但目前使用比较广泛的是2008版。对于初学者来说，安装哪个都一样。不过SQL Server 2008或2012都分别包含两种版本。超大的那个，4个多G的，是给企业用的。几百M的是给学生和开发者用的免费版，也就是Express版，它可以从微软的网站上直接下载。本文讲解的是SQL Server 2012 Express（似乎只有Windows7以上版本可以安装），读者可以寻找下面两个连接去下载：</p>
<p><a href="http://wwwco1vip.microsoft.com/downloads/zh-cn/details.aspx?FamilyID=c3a54822-f858-494a-9d74-b811e29179e7" target="_blank">http://wwwco1vip.microsoft.com/downloads/zh-cn/details.aspx?FamilyID=c3a54822-f858-494a-9d74-b811e29179e7</a></p>
<p>1. 先下载安装SSMS，它是用来管理SQL Server的图形化界面（注意一定要先装这个）</p>
<p>64位操作系统：CHS\x64\SQLManagementStudio_x64_CHS.exe</p>
<p>32位操作系统：CHS\x86\SQLManagementStudio_x86_CHS.exe</p>
<p>2. 下载安装SQL Server 2012</p>
<p>64位操作系统：CHS\x64\SQLEXPR_x64_CHS.exe</p>
<p>32位操作系统：CHS\x86\SQLEXPR_x86_CHS.exe</p>
<p>如果你不知道自己的系统是几位的，可以看下计算机属性，比如我自己的是64位系统：</p>
<p><img src="/Uploads/sql2012setup0_201204122047190193.PNG" alt="" width="532" height="156" /></p>
<p><strong>接下来我们安装SSMS：</strong></p>
<p>64位操作系统：CHS\x64\SQLManagementStudio_x64_CHS.exe</p>
<p>32位操作系统：CHS\x86\SQLManagementStudio_x86_CHS.exe</p>
<p>启动安装程序后，选择第一项[全新SQL Server 独立安装或向现有安装添加功能]，然后勾选“我接受许可协议”，并点击下一步。</p>
<p><img src="/Uploads/sql2012setup1_201204122047231221.PNG" alt="" width="866" height="730" /></p>
<p>安装程序安装完前置文件后，会让你选择功能。这里我建议大家全选。</p>
<p><img src="/Uploads/sql2012setup2_201204122047263981.PNG" alt="" width="820" height="616" /></p>
<p>一路点击下一步，就开始安装了。</p>
<p><img src="/Uploads/sql2012setup3_201204122047291282.PNG" alt="" width="820" height="615" /></p>
<p>根据机器的硬件配置，安装时间可能不同，我的笔记本电脑上大约用了10分钟。</p>
<p><img src="/Uploads/sql2012setup4_201204122049017767.PNG" alt="" width="821" height="616" /></p>
<p><strong>然后，我们安装SQL Server 2012的核心部分</strong></p>
<p>64位操作系统：CHS\x64\SQLEXPR_x64_CHS.exe</p>
<p>32位操作系统：CHS\x86\SQLEXPR_x86_CHS.exe</p>
<p>启动安装程序后，和之前一样，选择[<strong>全新SQL Server 独立安装或向现有安装添加功能</strong>]。接受许可协议，然后一路点击下一步。在功能选择的页面里，选择“实例功能”下的所有项。</p>
<p><img src="/Uploads/sql2012setup5_201204122049043351.PNG" alt="" width="818" height="616" /></p>
<p>在实例配置中，使用默认实例。安装路径建议大家选用默认的。</p>
<p><img src="/Uploads/sql2012setup6_201204122049066127.PNG" alt="" width="820" height="615" /></p>
<p>服务器配置页面中，也使用默认配置</p>
<p><img src="/Uploads/sql2012setup7_201204122049090463.PNG" alt="" width="819" height="614" /></p>
<p>在数据库引擎配置页面中，选择“混合模式”，并给SQL管理员帐号sa设置个密码，但你一定要记住这个密码。然后把自己添加到SQL Server管理员中（也就是你的开机帐号）。你也可以加多个人。建议大家把系统管理员帐号加进去。</p>
<p><img src="/Uploads/sql2012setup8_201204122051128325.PNG" alt="" width="818" height="612" /></p>
<p>然后一路下一步，就开始安装了，稍等几分钟就安装成功了。</p>
<p>装完以后，我们可以在开始，程序中，找到SSMS。我们将用它来登录和使用SQL Server 2012。</p>
<p><img src="/Uploads/sql2012setup9_201204122051152505.PNG" alt="" width="347" height="357" /></p>
<p>登录的时候可以选Windows验证，也可以使用sa帐号，以及你之前安装的时候设置的密码来登录：</p>
<p><img src="/Uploads/sql2012setup10_201204122051189634.PNG" alt="" width="834" height="452" /></p>
<p>登录成功后，我们可以看到对象资源管理器出现了本机的系统数据库。并且执行SQL命令也没问题了。于是大功告成了！</p>
<p><img src="/Uploads/sql2012setup11_201204122051216154.PNG" alt="" width="666" height="598" /></p>]]></description><pubDate>Thu, 12 Apr 2012 20:54:18 +0800</pubDate></item><item><title>修改开机密码后SharePoint无法使用的解决办法</title><link>http://wyjexplorer.cn/Home/View/437AD7F4ED87170C.html</link><description><![CDATA[<p>公司使用的是ActiveDirectory账户，安装SharePoint用的也是自己的域帐号。但公司有定期修改密码的策略。修改密码后，机器上的SharePoint就爆了。我们需要给SharePoint也重设一个密码才能运行。</p>
<p>首先要去IIS的程序池里改密码：</p>
<p><img src="/Uploads/sppass0_201203290959109435.PNG" alt="" width="645" height="667" /></p>
<p>然后去SharePoint Central Admin里修改密码：</p>
<p><img src="/Uploads/sppass1_201203290959311611.PNG" alt="" width="473" height="336" /></p>
<p><img src="/Uploads/sppass2_201203290959382903.PNG" alt="" width="435" height="109" /></p>
<p>选择Use existing password</p>
<p><img src="/Uploads/sppass3_201203290959426896.PNG" alt="" width="293" height="264" /></p>
<p>重启一下IIS，然后试试访问80端口的站点。如果不能访问，重新执行Config向导就会好。但可能会丢失原有的站点和配置信息。请格外小心。</p>
<p><img src="/Uploads/sppass4_201203290959495536.PNG" alt="" width="356" height="398" /></p>]]></description><pubDate>Thu, 29 Mar 2012 10:02:25 +0800</pubDate></item><item><title>ASP.NET制作基于的XML导航栏</title><link>http://wyjexplorer.cn/Home/View/B1A9770CEC6D0C4C.html</link><description><![CDATA[<p>首先说明，本文为照顾刚入门的新手，有些地方可能会稍微说点基础的东西，高手可以直接忽略。</p>
<p>场景：以前做网站的时候，导航栏的链接都是写死在页面中的，这样不易与维护。于是今天写成了用XML配置的导航栏。用到了LINQ to XML。</p>
<p>先介绍一下功能：</p>
<p>储存导航栏信息的XML文件如下：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;NavigationMenu&gt;
    &lt;MenuItem Title="Shit" Link="/Fuck" OrderId ="2" Enabled="True" /&gt;
    &lt;MenuItem Title="Shitter" Link="/Fucker" OrderId ="1" Enabled="True" /&gt;
    &lt;MenuItem Title="Shitting" Link="/Fucking" OrderId ="3" Enabled="True" /&gt;
    &lt;MenuItem Title="Shitful" Link="/Fucked" OrderId ="4" Enabled="False" /&gt;
    &lt;MenuItem Title="Shitfully" Link="/Fuckly" OrderId ="5" Enabled="True" /&gt;
&lt;/NavigationMenu&gt;</pre>
<p>Title是显示名称，Link是URL，OrderId表示排序的序位，Enabled为是否启用。这个菜单将最终被解析为一个ul列表：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;ul&gt;
	&lt;li&gt;&lt;a href="/Fucker"&gt;Shitter&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="/Fuck"&gt;Shit&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="/Fucking"&gt;Shitting&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="/Fuckly"&gt;Shitfully&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</pre>
<p>然后我们来看看如何实现：</p>
<p>首先需要给菜单创建一个只包含属性的模型类，它的作用是成为对具体某一个菜单项的描述，系统中传递的将是这样一个模型：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">public class MenuItem
{
    public string Title { get; set; }
    public string Link { get; set; }
    public int OrderId { get; set; }
    public bool Enabled { get; set; }
}</pre>
<p>接下来我们要写一个从XML读取所有菜单项，并返回List&lt;MenuItem&gt;泛型集合的方法。在这个例子里，List&lt;MenuItem&gt;里放的是所有5个MenuItem对象。</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">private List&lt;MenuItem&gt; GetList()
{
    var menuPath = Server.MapPath(@"~\App_Data\Menu.xml");
    if (System.IO.File.Exists(menuPath))
    {
        XElement root = XElement.Load(menuPath);
        var menuItems = from el in root.Elements("MenuItem")
                        select new MenuItem()
                        {
                            Title = el.Attribute("Title").Value,
                            Link = el.Attribute("Link").Value,
                            OrderId = int.Parse(el.Attribute("OrderId").Value),
                            Enabled = bool.Parse(el.Attribute("Enabled").Value)
                        };

        return menuItems.ToList();
    }
    else
    {
        //throw new System.IO.FileNotFoundException();
        return null;
    }
}</pre>
<p>(由于代码插件的问题，以上代码可能有误，请下载附件里的完整demo查看)</p>
<p>这个方法里我用了LINQ to XML，这是现在.NET操作XML最方便的办法。但LINQ要求你的Framework版本至少是3.5。在这个方法中，我们首先加载了Menu.xml文件，然后查找所有MenuItem节点，并把这些节点的属性赋值给new出来的MenuItem对象。创建MenuItem对象的时候，我使用的语法叫做对象初始化器。在return语句中，我写了ToList()，这样可以确保返回值是List&lt;MenuItem&gt;类型。&nbsp;</p>
<p>值得注意的是，我并没有把判断Enabled和对OrderId排序的逻辑写在这个方法中。因为判断是否启用和排序这两个操作属于业务逻辑，与数据读取无关，所以我们分离了关注点，GetList()是趋于稳定的方法，任何业务需求的改变都不需要修改这个方法，因为它的目的很简单&mdash;&mdash;仅仅是读取数据。一个方法只做一件事情，这是一个原则。</p>
<p>接下来我们还需要写一个业务方法，从GetList()的菜单项中选择所有Enabled的菜单，并按OrderId升序排列：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">private void FetchMenuData()
{
    var menuList = GetList();
    if (null != menuList &amp;&amp; menuList.Count &gt; 0)
    {
        // 查找所有已启用的菜单，并按OrderId升序排列
        var menuView = (from item in menuList
                        where item.Enabled
                        orderby item.OrderId ascending
                        select item).ToList();

        rptMenu.DataSource = menuView;
        rptMenu.DataBind();
    }
}</pre>
<p>为了偷懒，我直接把查询结果绑给了Repeater控件。如果按照三层的思想，我不可以把显示这块写在这个业务方法里。本文不探讨分层，有兴趣的朋友可以看看《ASP.NET设计模式》这本书。</p>
<p>接下来，我们只要在页面上放一个Repeater控件，并在Page_Load的时候调用FetchMenuData()就完成了：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;ul&gt;
    &lt;asp:Repeater ID="rptMenu" runat="server"&gt;
        &lt;ItemTemplate&gt;
            &lt;li&gt;&lt;a href="&lt;%#Eval("Link")%&gt;"&gt;&lt;%#Eval("Title")%&gt;&lt;/a&gt;&lt;/li&gt;
        &lt;/ItemTemplate&gt;
    &lt;/asp:Repeater&gt;
&lt;/ul&gt;</pre>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        FetchMenuData();
    }
}</pre>
<p>有图有真相：</p>
<p><img src="/Uploads/aspnetxmlmenu_201203271029243866.PNG" alt="" width="662" height="650" />&nbsp;</p>
<p>&nbsp;附件是完整Demo，需要的朋友可以下载。</p>]]></description><pubDate>Wed, 28 Mar 2012 07:07:43 +0800</pubDate></item><item><title>LINQ语句检查空对象的问题</title><link>http://wyjexplorer.cn/Home/View/D44F795B009E20FD.html</link><description><![CDATA[<p>今天在写博客的页面集功能，根据URL去寻找Page，LINQ语句从SitePage的GetModelList()集合中获取符合条件的page，如果查询不到则跳转到404页面。代码是这样的：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">var page = (from p in optSitePage.GetModelList()
            where p.VirtualUrlPath.ToLower() == requestTitle.ToLower()
            select p).First();

if (null == page)
{
    context.Response.Redirect("/404.html");
    return;
}</pre>
<p>我故意传了个不存在的URL，结果linq语句直接报错：System.InvalidOperationException: Sequence contains no elements。查了下MSDN发现用了First()的话，如果结果集中没有元素，它是不会返回null的。改成FirstOrDefault()就好了。</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">var page = (from p in optSitePage.GetModelList()
            where p.VirtualUrlPath.ToLower() == requestTitle.ToLower()
            select p).FirstOrDefault();</pre>]]></description><pubDate>Wed, 21 Mar 2012 12:24:20 +0800</pubDate></item><item><title>JQuery制作页面上多个DIV展开收起</title><link>http://wyjexplorer.cn/Home/View/17EAF8E9D221333C.html</link><description><![CDATA[<p>不久前在公司项目里用的一个多盒子展开收起效果，写成经验之书以警后人。代码是参考了网上某高人的，但原文找不到了，向作者道歉。</p>
<p>下面是演示页面：2个DIV，点击TOG可以收起或展开盒子，并且可以控制收起和展开时TOG文本的样式。所以可以自定义为上下箭头的图片什么的，这个就自己发挥了。</p>
<p>注意，记得先引用JQuery库～</p>
<p><img src="/Uploads/togbox0_201203161337144783.PNG" alt="" width="556" height="440" /></p>
<p><img src="/Uploads/togbox1_201203161337198291.PNG" alt="" width="547" height="310" /></p>
<p>HTML Code:</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;div class="box"&gt;
	&lt;div&gt;Tasks&lt;a href="javascript:;" id="Tasks" class="toggle_div"&gt;TOG&lt;/a&gt;&lt;/div&gt;
	&lt;div id="Tasks_Content" class="hid_div"&gt;
	SharePoint 2010客户端开发身份验证，如果开发客户端运行的环境是在域环境中，那么SharePoint是采取默认认证方式，如果不是域环境中的机器，那么就需要下面的认证方法。
	&lt;/div&gt;
&lt;/div&gt;

&lt;div class="box"&gt;
	&lt;div&gt;Defects&lt;a href="javascript:;" id="Defects" class="toggle_div"&gt;TOG&lt;/a&gt;&lt;/div&gt;
	&lt;div id="Defects_Content" class="hid_div"&gt;
	开闭原则指的是一个软件实体应对对扩展开发，对修改关闭(Software entities should be open for extension, but closed for modification)。这个原则是说在设计一个模块的时候，应对使这个模块可以在不被修改的前提下被扩展，换言之，应对可以不必修改源代码的情况下 改变这个模块的行为。
	&lt;/div&gt;
&lt;/div&gt;</pre>
<p>CSS Code:</p>
<pre class="brush: css;fontsize: 100; first-line: 1; ">.box
{
	width: 256px;
	padding: 5px;
	border: 1px solid #000;
	margin: 20px;
	height: auto;
}

.title
{
	background-color: #F4F4F4;
}

.isTogged
{
	background-color: #F00;
}</pre>
<p>JQuery Code:</p>
<pre class="brush: jscript;fontsize: 100; first-line: 1; ">$(".toggle_div").click(function(){
	$("#"+this.id).toggleClass("isTogged");
	$("#"+this.id+"_Content").toggle();
	
});</pre>]]></description><pubDate>Fri, 16 Mar 2012 13:43:33 +0800</pubDate></item><item><title>在ASP.NET4中配置和使用Log4net</title><link>http://wyjexplorer.cn/Home/View/5AFD26EB3421632B.html</link><description><![CDATA[<p>最近打算更换博客的日志功能，自己写的那个日志模块弱爆了，所以拿著名的log4net试试。查了些资料，自己试了几把，终于成功了。具体方法如下：</p>
<p>首先从官网下载并解压log4net，在项目中添加log4net.dll的引用（官方包的路径是log4net-1.2.11\bin\net\4.0\release\log4net.dll）。这个dll会自动拷贝到网站的bin目录下。</p>
<p>然后在web.config里如下配置。log4net节点没有智能提示，这没关系。配置文件中的file节点是日志文件的路径，可以自己设置，我自己用的是txt文件。</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; "><configSections>
  <section name="log4net" type="System.Configuration.IgnoreSectionHandler"/>
</configSections>
<log4net>
    <appender name="FileAppender" type="log4net.Appender.FileAppender">
        <file value="./App_Data/SystemLog.txt" />
        <appendToFile value="true" />
        <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="记录时间：%date 线程ID:[%thread] 日志级别：%-5level 出错类：%logger property:[%property{NDC}] <br />错误描述：%message%newline" />
        </layout>
    </appender>
    <root>
        <level value="DEBUG" />
        <appender-ref ref="FileAppender" />
    </root>
</log4net></pre>
<p>最后，在要使用的页面的代码里加上特征标记（写在public class ....的上面）：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">[assembly: log4net.Config.XmlConfigurator(Watch = true)]</pre>
<p>这表示log4net的配置文件从web.config获取。注意不要每页都写。因为页面一般会编译在同一程序集里。</p>
<p>具体记录日志的时候首先要初始化一个接口，然后再用log对象去记录不同的日志。</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">log4net.ILog log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
log.Fatal("Fatal Error Test.");</pre>
<p>它有好几个方法，并且都有string和string,Exception两个重载，大家自己看一下就明白了～用起来还是挺方便的。目前就发现一个问题，在网站运行的时候，这个日志文件是被IIS进程锁定的，没有办法删除。</p>]]></description><pubDate>Mon, 12 Mar 2012 09:15:25 +0800</pubDate></item><item><title>网站成功升级到.NET4并更换虚拟主机服务商</title><link>http://wyjexplorer.cn/Home/View/AEBE717B420E1913.html</link><description><![CDATA[<p>首先声明本文不是枪文。</p>
<p>今天早上我又发现时代互联的主机爆了，而且连域名也一起爆了，我当时就怒了。终于，忍无可忍之下，我决定更换DNS服务器以及网站空间。国内支持.NET4的服务商很少，我一直有把网站升级到ASP.NET4的计划，毕竟4.0版生成的html更好控制。我这次用的是聚拓互联的主机，可以运行.NET4的网站，性价比不错。</p>
<p>最让我满意的是聚拓的服务态度。我刚买好空间售后的技术人员就主动加我QQ了，之后帮我解决了一些主机和域名上的问题。相比之下，之前的时代互联，出了问题需要发邮件，然后让你等个半天，再告诉你要寄材料去公司，最后也不一定能解决问题，太2了。</p>
<p>不过我的wyjexplorer.cn域名现在还在时代互联手上，我已经把DNS服务器改到dnspod上了，听说dnspod的解析服务特别牛逼。不过目前上海电信的DNS有缓存，只能暂时用<a>http://wyjexplorer.s2.jutuo.net</a> 来访问，估计等一天就好了。</p>
<p>一个上午下来，新的空间速度很快，暂时木有什么问题。现在只担心域名能不能顺利解析了。</p>
<p>另外一个比较麻烦的就是备案的迁移，这个最有中国特色的东西实在是太蛋疼了，不解释，你们懂的。</p>
<p>15:54 域名解析恢复正常。感谢<a href="https://www.dnspod.cn" target="_blank">dnspod</a>。</p>]]></description><pubDate>Sun, 11 Mar 2012 11:46:12 +0800</pubDate></item><item><title>JQuery取DIV中的值</title><link>http://wyjexplorer.cn/Home/View/C5C74BEC27D142FF.html</link><description><![CDATA[<p>首先，你需要找到这个div对象。加个class或者id是最方便的：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;div id="testdiv"&gt;fuck&lt;/div&gt;</pre>
<p>&nbsp;接下来，就可以用.text()方法来取值了：</p>
<pre class="brush: jscript;fontsize: 100; first-line: 1; ">var myval = $("#testdiv").text();
alert(myval);
</pre>
<p>.text()方法的官方API如下：</p>
<p>Unlike the <code>.html()</code> method, <code>.text()</code> can be used in both XML and HTML documents. The result of the <code>.text()</code> method is a string containing the combined text of all matched elements. (Due to variations in the HTML parsers in different browsers, the text returned may vary in newlines and other white space.)</p>
<p>&nbsp;有图有真相：</p>
<p><img src="/Uploads/jqdiv_201203101512167187.PNG" alt="" width="656" height="363" /></p>]]></description><pubDate>Sat, 10 Mar 2012 15:15:58 +0800</pubDate></item><item><title>JQuery idTabs插件根据URL参数选择Tab</title><link>http://wyjexplorer.cn/Home/View/3AC255FFB172537A.html</link><description><![CDATA[<p>我们的项目用了SunSean的idTabs，但每个tab里的控件会触发postback，或者转到其他页面再转回来，这样当前选中的tab必丢。印度同事不肯用AJAX，无奈今天加班给印度人写个demo，通过回传URL参数来选择tab。</p>
<p>为了做这件事，除了jquery库和idTabs插件，我们还需要下载一个用来搞URL的插件：jquery.url.js，传送门：<a href="https://github.com/allmarkedup/jQuery-URL-Parser">https://github.com/allmarkedup/jQuery-URL-Parser</a></p>
<p>Tab菜单的HTML代码这样写，每个tab的div自己搞定，不发出来浪费页面了：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;div class="tabmenu"&gt;
	&lt;ul&gt;
	    &lt;li&gt;&lt;a href="#idTab1"&gt;Dashboard&lt;/a&gt;&lt;/li&gt;
	    &lt;li&gt;&lt;a href="#idTab2"&gt;Tracker&lt;/a&gt;&lt;/li&gt;
	    &lt;li&gt;&lt;a href="#idTab3"&gt;Documents&lt;/a&gt;&lt;/li&gt;
	    &lt;li&gt;&lt;a href="#idTab4"&gt;Collaboration&lt;/a&gt;&lt;/li&gt;
	    &lt;li&gt;&lt;a href="#idTab5"&gt;Knowledge Mapping&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
&lt;/div&gt;</pre>
<p>注意，一定不要给ul加class=&rdquo;idTabs&rdquo;，也就是不要用SunSean官网上的无javascript的写法。</p>
<p>脚本部分这样写：</p>
<pre class="brush: jscript;fontsize: 100; first-line: 1; ">&lt;script type="text/javascript"&gt;
    $(document).ready(function () {
        var tabToSelect = jQuery.url.param("tab");
        if (null == tabToSelect || "" == tabToSelect) {
            //alert("Parameter 'tab' is null or empty\nAuto selecting idTab1");
            tabToSelect = "idTab1";
        }
        //alert("Selecting: " + tabToSelect);
        $(".tabmenu ul").idTabs(tabToSelect);
    });
&lt;/script&gt;</pre>
<p>有图有真相：</p>
<p><img src="/Uploads/idtabfuck1_201203101004197187.jpg" alt="" /></p>
<p><img src="/Uploads/idTabfuck2_201203101004229687.jpg" alt="" /></p>
<p><img src="/Uploads/idTabfuck3_201203101004264531.jpg" alt="" /></p>]]></description><pubDate>Sat, 10 Mar 2012 10:06:24 +0800</pubDate></item><item><title>ASP.NET：如何把ashx写到类库里并在页面上调用</title><link>http://wyjexplorer.cn/Home/View/52A9542B6B66CCC8.html</link><description><![CDATA[<p>最近在调整博客的架构，进一步把表现和业务分离，所以要把之前用ashx搞的那些Http Handler放到类库中。在类库中建Http Handler的操作很简单，就是添加一个普通的类，然后把之前ashx里的代码几乎一模一样贴到这个类中。但要注意命名空间和类名，因为之后我们会用到。</p>
<p>样例Handler：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">namespace EdiBlog.Core.Web.HttpHandlers
{
    using System;
    using System.Web;

    public class ExampleHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context)
        {
            // 你自己的逻辑...
        }
    }
}</pre>
<p>这个handler的逻辑不重要，你可以自己定义。关键点是实现：IsReusable及ProcessRequest这两个接口中定义的成员。</p>
<p>下面我们要去站点的web.config中注册这个handler。如果你用的是IIS7及以上版本，并用了集成模式，就要这样配置：&nbsp;</p>
<p>在system.webServer\handlers节点下添加：</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; ">&lt;add name="ExampleHandler" verb="*" path="ex.axd" type="EdiBlog.Core.Web.HttpHandlers.ExampleHandler, EdiBlog.Core" /&gt;</pre>
<p>其中，path是访问handler用的路径，并且拓展名需要在iis中注册，如果你和我一样用的是虚拟主机，并且不能自己管理IIS，请不要使用如abc这样的IIS默认不支持的拓展名。</p>
<p>type里有两个参数，第一个是handler类的完整命名，第二个是程序集的名称。</p>
<p>现在我们在网页上就可以用ex.axd来访问handler了！&nbsp;</p>]]></description><pubDate>Thu, 08 Mar 2012 16:26:15 +0800</pubDate></item><item><title>ASP.NET中处理路径的问题</title><link>http://wyjexplorer.cn/Home/View/3B2827FED26BD545.html</link><description><![CDATA[<p><strong>一、关于相对路径和绝对路径</strong></p>
<p><strong>相对路径转绝对路径</strong></p>
<p>一般，我们在ASP.NET网站中往往需要把一个相对路径转化为绝对路径。通常是用Server.MapPath()方法。比如网站根目录下有个"Uploads"文件夹，那么我们调用Server.MapPath("Uploads")就会返回这个文件夹在服务器上的绝对路径，比如D:\Web1\Uploads。</p>
<p>另一种方法是使用HttpRuntime.AppDomainAppPath，它读取的就是当前网站的运行目录。</p>
<p><strong>关于波浪线：</strong></p>
<p>如果在路径前加上波浪线“~”则表示从网站根目录出发的相对路径。这在引用图片、CSS的时候比较常用。比如“~\Images”。并且这个路径同样可以传给Server.MapPath()用来返回绝对路径。</p>
<p><strong>总是从网站跟目录出发：</strong></p>
<p>在某些场合下，比如网站使用了URL重写组件（注意，不是指MVC网站），则会引发一些路径上的问题。比如网站根目录下有个ReadBlog.aspx，而URL重写中的配置为/Blog/View/xxxx.html，这样就多了两个路径。在引用资源文件的时候会有问题。一种是在后台代码里用“~\”来获取根目录，或者用ResolveUrl()方法。但其实最高效和简洁的写法是直接使用一个“/”来表示根目录。比如:</p>
<pre class="brush: xml;fontsize: 100; first-line: 1; "><img src="/Images/shit.png" alt="" /></pre>
<p> 则不管这个标记在哪个页面下，它总能找到根目录下的Images文件夹下的shit.png。</p>
<p><strong>二、斜杠和反斜杠</strong></p>
<p>URL使用的是“/”，所以在处理URL（解析和转向）的时候，都得给用户返回“/”这个方向的斜杠。</p>
<p>Windows中使用的是“\”，因此在做IO操作，比如把用户上传的文件保存到硬盘的时候得用“\”这个方向的斜杠。</p>
<p>其实这里会有个问题，比如我要把网站的图片上传文件夹的路径做成可配置的。那我到底是在配置文件中写“\Uploads”还是“/Uploads”呢？毕竟这个常量需要同时给URL和程序去读。当然，你可以在程序里做进一步的处理，但这种做法是否妥当呢？我现在还不清楚。</p>
<p><strong>三、路径的拼接</strong></p>
<p>最简单的拼接就是两个字符串用“+”操作符拼起来。遇到已知的路径，这种做法是木有问题的。但有时候我们获取的变量并不好控制。虽然可能经过验证逻辑处理，但验证并不总是灵活的。比如这个路径：“Uploads”，它和“Uploads\”意义是一样的。但如果直接用字符串相加把这个路径和另一个拼起来，比如“2011”，显然就会有问题：前者少一个斜杠：Uploads2011，而我们需要的结果是Uploads\2011。</p>
<p align="left">这时候我们需要借助System.IO.Path类中的Combine方法来做这件事。下面两条语句返回的结果都是一样的：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">Path.Combine(@"Uploads", "2011");
Path.Combine(@"Uploads\", "2011");</pre>
<p align="left">结果都是：Uploads\2011</p>
<p align="left">注意，不要在第二个参数前加“\”，比如把第二个参数换成“\2011”，返回值就会变成“\2011”，丢失了“Uploads”。</p>]]></description><pubDate>Fri, 02 Mar 2012 12:10:28 +0800</pubDate></item><item><title>LINQ重写博客垃圾图片回收算法</title><link>http://wyjexplorer.cn/Home/View/2724E13341E85EB4.html</link><description><![CDATA[<p>本人博客后台管理模块有个功能，可以扫描图片上传文件夹下所有未被引用的博客。思路很简单，从所有Blog Model中解析出所有文章使用的图片文件名，排除站外引用，放入一个List&lt;string&gt; usedPicList。再遍历图片上传文件夹，把所有图片文件的结果加入FileInfo[] fiAllPicList。然后比较usedPicList和fiAllPicList，找出所有fiAllPicList中有，而usedPicList中木有的图片，就是未被任何文章引用的垃圾图片了。</p>
<p>原先这个比较算法是用传统方法写的，很蛋疼，用了两重循环，一个标志位才解决问题：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">List&lt;FileInfo&gt; garbagePicList = new List&lt;FileInfo&gt;();

for (int k = 0; k &lt; fiAllPicList.Length; k++)
{
    bool found = false;
    for (int l = 0; l &lt; usedPicList.Count; l++)
    {
        if (fiAllPicList[k].Name == usedPicList[l].ToString())
        {
            found = true;
        }
    }
    if (!found)
    {
        garbagePicList.Add(fiAllPicList[k]);
    }
}</pre>
<p>今天用LINQ重写了一下：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">List&lt;FileInfo&gt; garbagePicList = new List&lt;FileInfo&gt;();

var query = from pic in fiAllPicList
            where !usedPicList.Contains(pic.Name)
            select pic;

garbagePicList = query.ToList();</pre>
<p>清晰明了，碉堡了！ </p>]]></description><pubDate>Mon, 20 Feb 2012 20:40:34 +0800</pubDate></item><item><title>LINQ操作数组（交集,并集,差集,最值,平均,去重复）</title><link>http://wyjexplorer.cn/Home/View/DBD2F9D182057445.html</link><description><![CDATA[<p>数组是大学里经常拿来做算法练习的对象。一些经典算法非常有价值，考试、装逼、面试都十分有用。但现在是效率时代，编程讲究生产效率，利用LINQ，可以让程序猿避免写一些基本算法，把精力花在业务处理上。</p>
<p>下面以数组为例，展示一些常用LINQ操作。</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">static void Main(string[] args)
{
    int[] a = { 1, 2, 3, 4, 5, 6, 7 };
    int[] b = { 4, 5, 6, 7, 8, 9, 10 };
    int[] c = { 1, 2, 3, 3, 4, 1, 2, 4, 6, 1, 6, 5 };

    // 交集
    var fuck = a.Intersect(b);

    // 并集
    var shit = a.Union(b);

    // a有b没有的
    var diff1 = a.Except(b);

    // b有a没有的
    var diff2 = b.Except(a);

    var max = a.Max();
    var min = a.Min();
    var avg = a.Average();
    var dis = c.Distinct();

    Print(fuck);
    Print(shit);
    Print(diff1);
    Print(diff2);
    Console.WriteLine(max);
    Console.WriteLine(min);
    Console.WriteLine(avg);
    Print(dis);

    Console.ReadKey();
}

private static void Print(IEnumerable&lt;int&gt; list)
{
    foreach (var item in list)
    {
        Console.Write(item + " ");
    }
    Console.WriteLine();
}</pre>
<p>有图有真相:</p>
<p><img src="/Uploads/linqarr_201202201203180312.PNG" alt="" width="323" height="186" /></p>
<p>一些参考：</p>
<p><a href="http://msdn.microsoft.com/zh-cn/library/bb397894.aspx" target="_blank">http://msdn.microsoft.com/zh-cn/library/bb397894.aspx</a></p>
<p><a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.intersect.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/system.linq.enumerable.intersect.aspx</a></p>]]></description><pubDate>Mon, 20 Feb 2012 12:08:29 +0800</pubDate></item><item><title>C#多线程Singleton(单件)模式模板</title><link>http://wyjexplorer.cn/Home/View/2D6EB3D4F18FF6A1.html</link><description><![CDATA[<p>最近在研究设计模式，我会陆续总结一些实用的代码出来。</p>
<p>下面是一个C#多线程单件模式的代码模板。把T换成你自己的类型就可以使用了。其精妙之处就在于用lock语句锁定资源来避免多线程同时走入if语句去创建多个对象。</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">private static volatile T _instance = null;
private static object objLock = new Object();

private T()
{

}

public static T Instance
{
    get
    {
        if (_instance == null)
        {
            lock (objLock)
            {
                if (_instance == null)
                {
                    _instance = new T();
                }
            }
        }
        return _instance;
    }
}</pre>
<p>在必要的时候需如果要刷新当前instance，可以这样写：</p>
<pre class="brush: csharp;fontsize: 100; first-line: 1; ">public static void RefreshInstance()
{
    _instance = new T();
}</pre>]]></description><pubDate>Sun, 19 Feb 2012 18:09:57 +0800</pubDate></item></channel></rss>
