﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-道。道。道-文章分类-Learn articles</title><link>http://www.cppblog.com/eday/category/4442.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 15:19:46 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 15:19:46 GMT</pubDate><ttl>60</ttl><item><title>什么是MVC</title><link>http://www.cppblog.com/eday/articles/37416.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Wed, 28 Nov 2007 02:48:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/37416.html</guid><description><![CDATA[<span id=ArticleContent1_ArticleContent1_lblContent>&nbsp;
<div class=title>模型－视图－控制器（MVC）是Xerox　PARC在八十年代为编程语言Smalltalk－80发明的一种软件设计模式，至今已被广泛使用。最近几年被推荐为Sun公司J2EE平台的设计模式，并且受到越来越多的使用 ColdFusion 和 PHP 的开发者的欢迎。模型－视图－控制器模式是一个有用的工具箱，它有很多好处，但也有一些缺点。</div>
<div class=content>
<p>MVC如何工作</p>
<p>MVC是一个设计模式，它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件：模型、视图、控制器。它们各自处理自己的任务。</p>
<p>视图<br>视图是用户看到并与之交互的界面。对老式的Web应用程序来说，视图就是由HTML元素组成的界面，在新式的Web应用程序中，HTML依旧在视图中扮演着重要的角色，但一些新的技术已层出不穷，它们包括Macromedia　Flash和象XHTML，XML/XSL，WML等一些标识语言和Web　services.</p>
<p>如何处理应用程序的界面变得越来越有挑战性。MVC一个大的好处是它能为你的应用程序处理很多不同的视图。在视图中其实没有真正的处理发生，不管这些数据是联机存储的还是一个雇员列表，作为视图来讲，它只是作为一种输出数据并允许用户操纵的方式。</p>
<p>模型<br>模型表示企业数据和业务规则。在MVC的三个部件中，模型拥有最多的处理任务。例如它可能用象EJBs和ColdFusion　Components这样的构件对象来处理数据库。被模型返回的数据是中立的，就是说模型与数据格式无关，这样一个模型能为多个视图提供数据。由于应用于模型的代码只需写一次就可以被多个视图重用，所以减少了代码的重复性。</p>
<p>控制器<br>控制器接受用户的输入并调用模型和视图去完成用户的需求。所以当单击Web页面中的超链接和发送HTML表单时，控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求，然后用确定用哪个视图来显示模型处理返回的数据。</p>
<p>现在我们总结ＭVC的处理过程，首先控制器接收用户的请求，并决定应该调用哪个模型来进行处理，然后模型用业务逻辑来处理用户的请求并返回数据，最后控制器用相应的视图格式化模型返回的数据，并通过表示层呈现给用户。</p>
<p>为什么要使用 MVC</p>
<p>大部分Web应用程序都是用像ASP，PHP，或者CFML这样的过程化语言来创建的。它们将像数据库查询语句这样的数据层代码和像HTML这样的表示层代码混在一起。经验比较丰富的开发者会将数据从表示层分离开来，但这通常不是很容易做到的，它需要精心的计划和不断的尝试。MVC从根本上强制性的将它们分开。尽管构造MVC应用程序需要一些额外的工作，但是它给我们带来的好处是无庸质疑的。</p>
<p>首先，最重要的一点是多个视图能共享一个模型，正如我所提及的，现在需要用越来越多的方式来访问你的应用程序。对此，其中一个解决之道是使用MVC，无论你的用户想要Flash界面或是 WAP 界面；用一个模型就能处理它们。由于你已经将数据和业务规则从表示层分开，所以你可以最大化的重用你的代码了。</p>
<p>由于模型返回的数据没有进行格式化，所以同样的构件能被不同界面使用。例如，很多数据可能用HTML来表示，但是它们也有可能要用Macromedia Flash和WAP来表示。模型也有状态管理和数据持久性处理的功能，例如，基于会话的购物车和电子商务过程也能被Flash网站或者无线联网的应用程序所重用。</p>
<p>因为模型是自包含的，并且与控制器和视图相分离，所以很容易改变你的应用程序的数据层和业务规则。如果你想把你的数据库从MySQL移植到Oracle，或者改变你的基于RDBMS数据源到LDAP，只需改变你的模型即可。一旦你正确的实现了模型，不管你的数据来自数据库或是LDAP服务器，视图将会正确的显示它们。由于运用MVC的应用程序的三个部件是相互对立，改变其中一个不会影响其它两个，所以依据这种设计思想你能构造良好的松偶合的构件。</p>
<p>对我来说，控制器的也提供了一个好处，就是可以使用控制器来联接不同的模型和视图去完成用户的需求，这样控制器可以为构造应用程序提供强有力的手段。给定一些可重用的模型和视图，控制器可以根据用户的需求选择模型进行处理，然后选择视图将处理结果显示给用户。</p>
<p>MVC的缺点<br>MVC的缺点是由于它没有明确的定义，所以完全理解MVC并不是很容易。使用MVC需要精心的计划，由于它的内部原理比较复杂，所以需要花费一些时间去思考。</p>
<p>你将不得不花费相当可观的时间去考虑如何将MVC运用到你的应用程序，同时由于模型和视图要严格的分离，这样也给调试应用程序到来了一定的困难。每个构件在使用之前都需要经过彻底的测试。一旦你的构件经过了测试，你就可以毫无顾忌的重用它们了。</p>
<p>根据我个人经验，由于我们将一个应用程序分成了三个部件，所以使用MVC同时也意味着你将要管理比以前更多的文件，这一点是显而易见的。这样好像我们的工作量增加了，但是请记住这比起它所能带给我们的好处是不值一提。</p>
<p>MVC并不适合小型甚至中等规模的应用程序，花费大量时间将MVC应用到规模并不是很大的应用程序通常会得不偿失。</p>
<p>MVC是一条创建软件的好途径<br>MVC设计模式是一个很好创建软件的途径，它所提倡的一些原则，像内容和显示互相分离可能比较好理解。但是如果你要隔离模型、视图和控制器的构件，你可能需要重新思考你的应用程序，尤其是应用程序的构架方面。如果你肯接受MVC，并且有能力应付它所带来的额外的工作和复杂性，MVC将会使你的软件在健壮性，代码重用和结构方面上一个新的台阶。<br></p>
</div>
</span>
<img src ="http://www.cppblog.com/eday/aggbug/37416.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-28 10:48 <a href="http://www.cppblog.com/eday/articles/37416.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Q316675 PRB: Cannot Connect to Access Database from ASP.NET</title><link>http://www.cppblog.com/eday/articles/37298.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Mon, 26 Nov 2007 01:32:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/37298.html</guid><description><![CDATA[<div class="section">
<h2 class="subTitle" id="tocHeadRef">SYMPTOMS</h2>
<script type="text/javascript">loadTOCNode(1, 'symptoms');</script>
<div class="sbody"> An unhandled exception may occur under the following
circumstances:
<table class="list ul">
    <tbody>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">An ASP.NET worker process (Aspnet_wp.exe) runs under the
            default ASPNET account. <br>-and-<br></td>
        </tr>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">You do not enable impersonation on that application.
            <br><br>-and-<br></td>
        </tr>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">You try to connect to or write to an Access
            database.</td>
        </tr>
    </tbody>
</table>
Under these circumstances, you may receive one of the following
exceptions:
<div class="errormsg"> The Microsoft Jet database engine cannot
open the file 'C:\Nwind.mdb'. It is already opened exclusively by another user,
or you need permission to view its data. </div>
<div class="errormsg">
Operation must use an updateable query. </div>
<p class="topOfPage"><a href="http://support.microsoft.com/kb/316675/en-us#top"><br></a></p>
</div>
<h2 class="subTitle" id="tocHeadRef">CAUSE</h2>
<script type="text/javascript">loadTOCNode(1, 'cause');</script>
<div class="sbody"> Because of security concerns, the ASP.NET worker process
runs under the default ASPNET account. If you do not enable impersonation for
an application, all of the threads that run the requests for that application
run under the process account.<br><br> This problem occurs because the ASPNET
account does not have sufficient permissions to connect to or write to an
Access database.
<p class="topOfPage"><a href="http://support.microsoft.com/kb/316675/en-us#top"><br></a></p>
</div>
<h2 class="subTitle" id="tocHeadRef">RESOLUTION</h2>
<script type="text/javascript">loadTOCNode(1, 'resolution');</script>
<div class="sbody"> To work around this problem, use one of the following
methods:
<table class="list ul">
    <tbody>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">Configure the ASP.NET worker process to run under the
            SYSTEM account in the &lt;processModel&gt; section of the Machine.config
            file.</td>
        </tr>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">For security reasons, Microsoft recommends that you enable
            impersonation on your ASP.NET application. This method works if the
            impersonated user has necessary permissions to the computer and the database
            that you are accessing.</td>
        </tr>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">Grant read and write permissions for the "Everyone" group
            on the database and the database folder. This method is not safe; therefore,
            Microsoft does not recommend this method.</td>
        </tr>
    </tbody>
</table>
<p class="topOfPage"><a href="http://support.microsoft.com/kb/316675/en-us#top"><br></a></p>
</div>
<h2 class="subTitle" id="tocHeadRef">STATUS</h2>
<script type="text/javascript">loadTOCNode(1, 'status');</script>
<div class="sbody">This
behavior is by design.
<p class="topOfPage"><a href="http://support.microsoft.com/kb/316675/en-us#top"><br></a></p>
</div>
<h2 class="subTitle" id="tocHeadRef">MORE INFORMATION</h2>
<script type="text/javascript">loadTOCNode(1, 'moreinformation');</script>
<div class="sbody"> When you need unlimited users, full-time support, and ACID
transactions, Microsoft strongly recommends that you use Microsoft SQL Server
with Microsoft Internet Information Services (IIS). Although Microsoft Active
Server Pages (ASP) works with any OLE DB-compliant or ODBC-compliant database,
IIS has been extensively tested. IIS is designed to work with Microsoft SQL
Server on high transaction traffic and with unlimited users, which can occur in
an Internet scenario.<br><br><strong>Note</strong> "ACID" is an acronym for the four properties of
transaction-processing systems: Atomicity, Consistency, Isolation,
Durability.<br><br> ASP supports the use of the Microsoft Jet database engine
as a valid data source. However, Microsoft ODBC Driver for Access and Microsoft
OLE DB Provider for Jet are not intended for use with high-stress,
high-concurrency, full-time server applications (such as Web applications,
commerce applications, transactional applications, messaging servers, and so
on).
<p class="topOfPage"><a href="http://support.microsoft.com/kb/316675/en-us#top"><br></a></p>
<h3 id="tocHeadRef">Steps to reproduce the behavior</h3>
<script type="text/javascript">loadTOCNode(2, 'moreinformation');</script>
<table class="list ol">
    <tbody>
        <tr>
            <td class="number">1.</td>
            <td class="text">Create a new ASP.NET Web Application project in Microsoft
            Visual C# .NET.</td>
        </tr>
        <tr>
            <td class="number">2.</td>
            <td class="text">Add the following code to the "Declaration" section of your
            Web Form, which appears at the top of the Code window:<code></code>
            <pre class="code">using System.Data.OleDb;					</pre>
            </td>
        </tr>
        <tr>
            <td class="number">3.</td>
            <td class="text">Add the following code to the <strong>Page_Load</strong> event:<code></code>
            <pre class="code">    String myConn  ="Provider=Microsoft.JET.OLEDB.4.0;Data Source=C:\\Nwind.mdb;";<br>    String myQuery  = "Insert into Customers(CustomerID,CompanyName) Values ('aaaaa', 'aaaaa')";<br><br>    OleDbConnection cn = new OleDbConnection(myConn);<br>    cn.Open();<br>    OleDbCommand cmd = new OleDbCommand(myQuery, cn);<br>    cmd.ExecuteNonQuery();<br>    cn.close();<br>					</pre>
            </td>
        </tr>
        <tr>
            <td class="number">4.</td>
            <td class="text">Modify the connection string as appropriate for your
            environment.</td>
        </tr>
        <tr>
            <td class="number">5.</td>
            <td class="text">Compile the project.</td>
        </tr>
        <tr>
            <td class="number">6.</td>
            <td class="text">View WebForm1.aspx in your browser. Notice that you receive
            one of the above-mentioned exceptions.</td>
        </tr>
    </tbody>
</table>
<p class="topOfPage"><a href="http://support.microsoft.com/kb/316675/en-us#top"><br></a></p>
</div>
<h2 class="subTitle" id="tocHeadRef">REFERENCES</h2>
<script type="text/javascript">loadTOCNode(1, 'references');</script>
<div class="sbody">
For additional information, click the following article numbers to view the articles in the Microsoft Knowledge Base:
<div class="indent"><a href="http://support.microsoft.com/kb/306590/" class="KBlink">306590</a><span class="pLink"> (http://support.microsoft.com/kb/306590/)</span>
ASP.NET security overview
</div>
<div class="indent"><a href="http://support.microsoft.com/kb/307626/" class="KBlink">307626</a><span class="pLink"> (http://support.microsoft.com/kb/307626/)</span> ASP.NET configuration overview
</div>
For more information about the <strong>&lt;processModel&gt;</strong> section, visit the following Microsoft Developer Network (MSDN)
Web site:
<div class="indent">
&lt;processModel&gt; Section<br><a href="http://msdn2.microsoft.com/en-us/library/7w2sway1%28vs.71%29.aspx">http://msdn2.microsoft.com/en-us/library/7w2sway1(vs.71).aspx</a><span class="pLink"> (http://msdn2.microsoft.com/en-us/library/7w2sway1(vs.71).aspx)</span></div>
<p class="topOfPage"><a href="http://support.microsoft.com/kb/316675/en-us#top"><br></a></p>
</div>
</div>
<div class="appliesTo"><hr>
<h5>APPLIES TO</h5>
<table class="list">
    <tbody>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">Microsoft ADO.NET 2.0</td>
        </tr>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">Microsoft ADO.NET 1.0</td>
        </tr>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">Microsoft ASP.NET 1.0</td>
        </tr>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">Microsoft Access 2002 Standard Edition</td>
        </tr>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">Microsoft Access 2000 Standard Edition</td>
        </tr>
        <tr>
            <td class="bullet">&#8226;</td>
            <td class="text">Microsoft Office FrontPage 2003</td>
        </tr>
    </tbody>
</table>
</div>
<p class="topOfPage"><a href="http://support.microsoft.com/kb/316675/en-us#top"><br></a></p>
<div class="keywords">
<table>
    <tbody>
        <tr>
            <td class="header">
            <h5>Keywords:&nbsp;</h5>
            </td>
            <td class="text">kbtshoot kberrmsg kbnofix kbprb kbsystemdata KB316675</td>
        </tr>
    </tbody>
</table>
<p class="topOfPage"><a href="http://support.microsoft.com/kb/316675/en-us#top"><br></a></p>
</div><img src ="http://www.cppblog.com/eday/aggbug/37298.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-26 09:32 <a href="http://www.cppblog.com/eday/articles/37298.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GridView鼠标移动行变色</title><link>http://www.cppblog.com/eday/articles/37044.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 20 Nov 2007 13:36:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/37044.html</guid><description><![CDATA[<ol class=dp-c>
    <li class=alt><span><span>方法一: &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class=alt><span>在GridView的 &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class=alt><span></span><span class=keyword>protected</span><span>&nbsp;</span><span class=keyword>void</span><span>&nbsp;GridView1_RowDataBound(</span><span class=keyword>object</span><span>&nbsp;sender,&nbsp;GridViewRowEventArgs&nbsp;e) &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>if</span><span>&nbsp;(e.Row.RowType&nbsp;==&nbsp;DataControlRowType.DataRow) &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.Row.Attributes.Add(</span><span class=string>"onMouseOver"</span><span>,&nbsp;</span><span class=string>"SetNewColor(this);"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.Row.Attributes.Add(</span><span class=string>"onMouseOut"</span><span>,&nbsp;</span><span class=string>"SetOldColor(this);"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>在页面中加入 &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&lt;SCRIPT&nbsp;language=javascript&gt; &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;_oldColor; &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;SetNewColor(source) &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_oldColor=source.style.backgroundColor; &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;source.style.backgroundColor=</span><span class=string>'#666666'</span><span>; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;SetOldColor(source) &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;source.style.backgroundColor=_oldColor; &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/SCRIPT&gt; &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp; &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>方法二: &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>protected</span><span>&nbsp;</span><span class=keyword>void</span><span>&nbsp;GridView1_RowDataBound(</span><span class=keyword>object</span><span>&nbsp;sender,&nbsp;GridViewRowEventArgs&nbsp;e) &nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>if</span><span>&nbsp;(e.Row.RowType&nbsp;==&nbsp;DataControlRowType.DataRow) &nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.Row.Attributes[</span><span class=string>"onMouseOver"</span><span>]&nbsp;=&nbsp;</span><span class=string>"js.ItemOver(this)"</span><span>; &nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>在页面上加入 &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&lt;SCRIPT&nbsp;language=javascript&nbsp;type=text/javascript&gt; &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;js=</span><span class=keyword>new</span><span>&nbsp;function(){ &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>if</span><span>&nbsp;(!objbeforeItem){var&nbsp;objbeforeItem=</span><span class=keyword>null</span><span>;var&nbsp;objbeforeItembackgroundColor=</span><span class=keyword>null</span><span>;} &nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>this</span><span>.ItemOver=function(obj) &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>if</span><span>(objbeforeItem){objbeforeItem.style.backgroundColor&nbsp;=&nbsp;objbeforeItembackgroundColor;} &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;objbeforeItembackgroundColor&nbsp;=&nbsp;obj.style.backgroundColor; &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;objbeforeItem&nbsp;=&nbsp;obj; &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj.style.backgroundColor&nbsp;=&nbsp;</span><span class=string>"#fcfcfc"</span><span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class=alt><span>} &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/SCRIPT&gt; &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>方法三: &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;</span><span class=keyword>protected</span><span>&nbsp;</span><span class=keyword>void</span><span>&nbsp;GridView1_RowDataBound(</span><span class=keyword>object</span><span>&nbsp;sender,&nbsp;GridViewRowEventArgs&nbsp;e) &nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=keyword>if</span><span>&nbsp;(e.Row.RowType&nbsp;==&nbsp;DataControlRowType.DataRow) &nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment>//鼠标移动到每项时颜色交替效果 </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.Row.Attributes.Add(</span><span class=string>"OnMouseOut"</span><span>,&nbsp;</span><span class=string>"this.style.backgroundColor='White';this.style.color='#003399'"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.Row.Attributes.Add(</span><span class=string>"OnMouseOver"</span><span>,&nbsp;</span><span class=string>"this.style.backgroundColor='#6699FF';this.style.color='#8C4510'"</span><span>); &nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=comment>//设置悬浮鼠标指针形状为"小手" </span><span>&nbsp;&nbsp;</span></span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.Row.Attributes[</span><span class=string>"style"</span><span>]&nbsp;=&nbsp;</span><span class=string>"Cursor:hand"</span><span>; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li>
    <li class=alt><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
</ol>
<img src ="http://www.cppblog.com/eday/aggbug/37044.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-20 21:36 <a href="http://www.cppblog.com/eday/articles/37044.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ASP.NET2.0数据操作之母板页和站点导航</title><link>http://www.cppblog.com/eday/articles/36719.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Thu, 15 Nov 2007 13:02:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/36719.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 导言　　通常，用户友好的个性化站点都有着一致的，站点统一的页面布局和导航体系。Asp.net 2.0引入的两个新特性给我们在统一站点的页面布局和站点导航上提供了简单而有效的工具，它们是母板页和站点导航。母板页允许开发者创建统一的站点模板和指定的可编辑区域。这样，aspx页面只需要给模板页中指定的可编辑区域提供填充内容就可以了，所有在母板页中定义的其他标记将出现在所有使用了该母板页的aspx页面中。...&nbsp;&nbsp;<a href='http://www.cppblog.com/eday/articles/36719.html'>阅读全文</a><img src ="http://www.cppblog.com/eday/aggbug/36719.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-15 21:02 <a href="http://www.cppblog.com/eday/articles/36719.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ASP.NET2.0数据操作之创建业务逻辑层</title><link>http://www.cppblog.com/eday/articles/36718.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Thu, 15 Nov 2007 13:00:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/36718.html</guid><description><![CDATA[　　<strong>导言</strong> <br><br>　　本教程的<a href="http://dev.yesky.com/msdn/395/2498395.shtml" target=_blank><font color=#2b2bd5><u>第一节</u></font></a>所描述的数据访问层（Data Access Layer，以下简称为DAL）已经清晰地将表示逻辑与数据访问逻辑区分开了。不过，即使DAL将数据访问的细节从表示层中分离出来了，可它却不能处理任何的业务规则。比如说，我们可能不希望产品表中那些被标记为&#8220;停用&#8221;的产品的&#8220;分类编号&#8221;或&#8220;供应商编号&#8221;被更新；我们还可能需要应用一些资历规则，比如说我们都不希望被比自己的资历还要浅的人管理。另外一个比较常见的情况就是授权，比如说只有那些具有特殊权限的用户可以删除产品或是更改单价。<br><br>　　我们其实可以将业务逻辑层（Business Logic Layer，以下简称BLL）看作是在数据访问层和表示层之间进行数据交换的桥梁，在这个章节中，我们将讨论一下如何将这些业务规则集成到一个BLL中。需要说明的是，在一个实际的应用程序中，BLL都是以类库（Class Library）的形式来实现的，不过为了简化工程的结构，在本教程中我们将BLL实现为App_Code文件夹中的一系列的类。图一向我们展示了表示层、BLL以及DAL三者之间的结构关系。<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img height=511 src="http://dev.yesky.com/imagelist/06/30/jzzwvzgbbq7p.gif" width=184 border=0><br>图一：BLL将表示层与DAL隔开了，并且加入了业务规则</div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　第一步：创建BLL类<br><br>　　我们的BLL由4个类组成，每一个BLL类都对应DAL中的一个TableAdapter，它们都从各自的TableAdapter中得到读取、插入、修改以及删除等方法以应用合适的业务规则。<br><br>　　为了更加清晰的区分DAL和BLL的类，我们在App_Code文件夹中建立两个子文件夹，分别命名为DAL和BLL。你仅仅需要在解决方案浏览器（Solution Explorer）中右键点击App_Code文件夹，并选择新建文件夹（New Folder），就可以创建新的子文件夹了。建好了这两个文件夹之后，把第一节中所创建的类型化数据集（Typed DataSet）移到DAL文件夹中。<br><br>　　然后，在BLL文件夹中创建4个类文件。同样，你仅仅需要在解决方案浏览器（Solution Explorer）中右键点击BLL文件夹，并选择新建项目（New Item），然后在弹出的对话框中选择类模板（Class template）就可以创建新的类文件了。将这四个文件分别命名为ProductsBLL、CategoriesBLL、SuppliersBLL以及EmployeesBLL。<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img src="http://dev.yesky.com/imagelist/06/30/eaek8x8ez96s.gif" border=0><br>图二：在BLL文件夹中添加4个新的类</div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　接下来，让我们来给这些新建的类加上一些方法，简单的将第一节中的TableAdapter中的那些方法包装起来就行了。现在，这些方法将只能直接使用DAL中的那些方法，我们等会再来给他们加上一些业务逻辑。<br><br>　　注意：如果你使用的是Visual Studio 标准版或以上版本（也就是说，你不是用的Visual Web Developer），那么你还可以使用Class Designer来可视化的设计你的类。你可以在Class Designer Blog上得到关于Visual Studio的这项新功能的详细信息。<br><br>　　在ProductsBLL类中，我们一共需要为其添加7个方法：<br><br>　　&#183;GetProducts() &#8211; 返回所有的产品<br><br>　　&#183;GetProductByProductID(productID) &#8211; 返回指定ProductID的产品<br><br>　　&#183;GetProductsByCategoryID(categoryID) &#8211;返回指定分类的产品<br><br>　　&#183;GetProductsBySupplier(supplierID) &#8211;返回指定供应商的产品<br><br>　　&#183;AddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued) &#8211; 向数据库中添加一条产品信息，并返回新添加的产品的ProductID <br><br>　　&#183;UpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID) &#8211; 更新一个数据库中已经存在的产品，如果刚好更新了一条记录，则返回true，否则返回false<br><br>　　&#183;DeleteProduct(productID) &#8211; 删除指定ProductID的产品<br><br>　　ProductsBLL.cs<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>1using System;<br>2using System.Data;<br>3using System.Configuration;<br>4using System.Web;<br>5using System.Web.Security;<br>6using System.Web.UI;<br>7using System.Web.UI.WebControls;<br>8using System.Web.UI.WebControls.WebParts;<br>9using System.Web.UI.HtmlControls;<br>10using NorthwindTableAdapters;<br>11<br>12[System.ComponentModel.DataObject]<br>13public class ProductsBLL<br>14{<br>15 private ProductsTableAdapter _productsAdapter = null;<br>16 protected ProductsTableAdapter Adapter<br>17 {<br>18 get {<br>19 if (_productsAdapter == null)<br>20 _productsAdapter = new ProductsTableAdapter();<br>21<br>22 return _productsAdapter; <br>23 }<br>24 }<br>25<br>26<br>27[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]<br>28 public Northwind.ProductsDataTable GetProducts()<br>29 { <br>30 return Adapter.GetProducts();<br>31 }<br>32<br>33 [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]<br>34 public Northwind.ProductsDataTable GetProductByProductID(int productID)<br>35 {<br>36 return Adapter.GetProductByProductID(productID);<br>37 }<br>38<br>39[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]<br>40 public Northwind.ProductsDataTable GetProductsByCategoryID(int categoryID)<br>41 {<br>42 return Adapter.GetProductsByCategoryID(categoryID);<br>43 }<br>44<br>45[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]<br>46 public Northwind.ProductsDataTable GetProductsBySupplierID(int supplierID)<br>47 {<br>48 return Adapter.GetProductsBySupplierID(supplierID);<br>49 }<br>50 [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, true)]<br>51 public bool AddProduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit, <br>52 decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel, <br>53 bool discontinued)<br>54 {<br>55 // 新建一个ProductRow实例<br>56 Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();<br>57 Northwind.ProductsRow product = products.NewProductsRow();<br>58<br>59 product.ProductName = productName;<br>60 if (supplierID == null) product.SetSupplierIDNull(); else product.SupplierID = supplierID.Value;<br>61 if (categoryID == null) product.SetCategoryIDNull(); else product.CategoryID = categoryID.Value;<br>62 if (quantityPerUnit == null) product.SetQuantityPerUnitNull(); else product.QuantityPerUnit = quantityPerUnit;<br>63 if (unitPrice == null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value;<br>64 if (unitsInStock == null) product.SetUnitsInStockNull(); else product.UnitsInStock = unitsInStock.Value;<br>65 if (unitsOnOrder == null) product.SetUnitsOnOrderNull(); else product.UnitsOnOrder = unitsOnOrder.Value;<br>66 if (reorderLevel == null) product.SetReorderLevelNull(); else product.ReorderLevel = reorderLevel.Value;<br>67 product.Discontinued = discontinued;<br>68<br>69 // 添加新产品<br>70 products.AddProductsRow(product);<br>71 int rowsAffected = Adapter.Update(products);<br>72<br>73 // 如果刚好新增了一条记录，则返回true，否则返回false<br>74 return rowsAffected == 1;<br>75 }<br>76<br>77 [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)]<br>78 public bool UpdateProduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit,<br>79 decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel,<br>80 bool discontinued, int productID)<br>81 {<br>82 Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);<br>83 if (products.Count == 0)<br>84 // 没有找到匹配的记录，返回false<br>85 return false;<br>86<br>87 Northwind.ProductsRow product = products[0];<br>88<br>89 product.ProductName = productName;<br>90 if (supplierID == null) product.SetSupplierIDNull(); else product.SupplierID = supplierID.Value;<br>91 if (categoryID == null) product.SetCategoryIDNull(); else product.CategoryID = categoryID.Value;<br>92 if (quantityPerUnit == null) product.SetQuantityPerUnitNull(); else product.QuantityPerUnit = quantityPerUnit;<br>93 if (unitPrice == null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value;<br>94 if (unitsInStock == null) product.SetUnitsInStockNull(); else product.UnitsInStock = unitsInStock.Value;<br>95 if (unitsOnOrder == null) product.SetUnitsOnOrderNull(); else product.UnitsOnOrder = unitsOnOrder.Value;<br>96 if (reorderLevel == null) product.SetReorderLevelNull(); else product.ReorderLevel = reorderLevel.Value;<br>97 product.Discontinued = discontinued;<br>98<br>99 // 更新产品记录<br>100 int rowsAffected = Adapter.Update(product);<br>101<br>102 // 如果刚好更新了一条记录，则返回true，否则返回false<br>103 return rowsAffected == 1;<br>104 }<br>105<br>106 [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Delete, true)]<br>107 public bool DeleteProduct(int productID)<br>108 {<br>109 int rowsAffected = Adapter.Delete(productID);<br>110<br>111 // 如果刚好删除了一条记录，则返回true，否则返回false<br>112 return rowsAffected == 1;<br>113 }<br>114}<br>115</td>
        </tr>
    </tbody>
</table>
<br>　　GetProducts、GetProductByProductID、GetProductsByCategoryID以及 GetProductBySuppliersID等方法都仅仅是简简单单的直接调用DAL中的方法来返回数据。不过在有的情况下，我们还可能需要给它们实现一些业务规则（比如说授权规则，不同的用户或不用角色应该可以看到不同的数据），现在我们简单的将它们做成这样就可以了。那么，对于这些方法来说，BLL仅仅是作为表示层与DAL之间的代理。<br><br>　　AddProduct和UpdateProduct这两个方法都使用参数中的那些产品信息去添加或是更新一条产品记录。由于Product表中有许多字段都允许空值（CategoryID、SupplierID、UnitPrice&#8230;&#8230;等等），所以AddProduct和UpdateProduct中相应的参数就使用nullable types。Nullable types是.NET 2.0中新提供的一种用于标明一个值类型是否可以为空的技术。在C#中，你可以在一个允许为空的值类型后面加上一个问号（比如，int x;）。关于Nullable Types的详细信息，你可以参考C# Programming Guide。<br><br>　　由于插入、修改和删除可能不会影响任何行，所以这三种方法均返回一个bool值用于表示操作是否成功。比如说，页面开发人员使用一个并不存在的ProductID去调用DeleteProduct，很显然，提交给数据库的DELETE语句将不会有任何作用，所以DeleteProduct会返回false。<br><br>　　注意：当我们在添加或更新一个产品的详细信息时，都是接受由产品信息组成的一个标量列表，而不是直接接受一个ProductsRow实例。因为ProductsRow是继承于ADO.NET的DataRow，而DataRow没有默认的无参构造函数，为了创建一个ProductsRow的实例，我们必须先创建一个ProductsDataTable的实例，然后调用它的NewProductRow方法（就像我们在AddProduct方法中所做的那样）。不过，当我在使用ObjectDataSource来插入或更新时，这样做的缺点就会暴露出来了。简单的讲，ObjectDataSource会试图为输入的参数创建一个实例，如果BLL方法希望得到一个ProductsRow，那么ObjectDataSource就将会试图去创建一个，不过很显然，这样的操作一定会失败，因为没有一个默认的无参构造函数。这个问题的详细信息，可以在ASP.NET论坛的以下两个帖子中找到: Updating ObjectDataSources with Strongly-Typed DataSets、Problem With ObjectDataSource and Strongly-Typed DataSet。<br><br>　　之后，在AddProduct和UpdateProduct中，我们创建了一个ProductsRow实例，并将传入的参数赋值给它。当给一个DataRow的DataColumns赋值时，各种字段级的有效性验证都有可能会被触发。因此，我们应该手工的验证一下传入的参数以保证传递给BLL方法的数据是有效的。不幸的是，Visual Studio生成的强类型数据集（strongly-typed DataRow）并没有使用nullable values。要表明DataRow中的一个DataColumn可以接受空值，我们就必须得使用SetColumnNameNull方法。<br><br>　　在UpdateProduct中，我们先使用GetProductByProductID(productID)方法将需要更新的产品信息读取出来。这样做好像没有什么必要，不过我们将在之后的关于并发优化（Optimistic concurrency）的课程中证明这个额外的操作是有它的作用的。并发优化是一种保证两个用户同时操作一个数据而不会发生冲突的技术。获取整条记录同时也可以使创建一个仅更新DataRow的一部分列的方法更加容易，我们可以在SuppliersBLL类中找到这样的例子。<br><br>　　最后，注意我们在ProductsBLL类上面加上了DataObject 标签（就是在类声明语句的上面的[System.ComponentModel.DataObject]），各方法上面还有DataObjectMethodAttribute 标签。DataObject标签把这个类标记为可以绑定到一个ObjectDataSource控件，而DataObjectMethodAttribute则说明了这个方法的目的。我们将在后面的教程中看到，ASP.NET 2.0的ObjectDataSource使从一个类中访问数据更加容易。为了ObjectDataSource向导能够对现有的类进行合适的筛选，在类列表中默认仅显示标记为DataObject的类。当然，其实ProductsBLL类就算没有这个标签也可以工作，但是加上它可以使我们在ObjectDataSource向导中的操作更加轻松和心情愉快。<br>　　<strong>添加其他的类</strong><br><br>　　完成了ProductsBLL类之后，我们还要添加一些为categories、suppliers和employees服务的类。让我们花点时间来创建下面的类，根据上面的例子来做就是了：<br><br>　　&#183; CategoriesBLL.cs<br><br>　　　o GetCategories()<br><br>　　　o GetCategoryByCategoryID(categoryID) <br><br>　　&#183; SuppliersBLL.cs<br><br>　　　o GetSuppliers()<br><br>　　　o GetSupplierBySupplierID(supplierID)<br><br>　　　o GetSuppliersByCountry(country)<br><br>　　　o UpdateSupplierAddress(supplierID, address, city, country)<br><br>　　&#183; EmployeesBLL.cs<br><br>　　　o GetEmployees()<br><br>　　　o GetEmployeeByEmployeeID(employeeID)<br><br>　　　o GetEmployeesByManager(managerID)<br><br>　　SuppliersBLL类中的UpdateSupplierAddress方法是一个值得注意的东西。这个方法提供了一个仅仅更新供应商地址信息的接口。它首先根据指定的SupplierID读出一个SupplierDataRow(使用GetSupplierBySupplierID方法)，设置其关于地址的所有属性，然后调用SupplierDataTable的Update方法。UpdateSupplierAddress方法的代码如下所示：<br><br>　　 UpdateSupplierAddress<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>1[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)]<br>2public bool UpdateSupplierAddress(int supplierID, string address, string city, string country)<br>3{<br>4 Northwind.SuppliersDataTable suppliers = Adapter.GetSupplierBySupplierID(supplierID);<br>5 if (suppliers.Count == 0)<br>6 // 没有找到匹配的项，返回false<br>7 return false;<br>8 else<br>9 {<br>10 Northwind.SuppliersRow supplier = suppliers[0];<br>11<br>12 if (address == null) supplier.SetAddressNull(); else supplier.Address = address;<br>13 if (city == null) supplier.SetCityNull(); else supplier.City = city;<br>14 if (country == null) supplier.SetCountryNull(); else supplier.Country = country;<br>15<br>16 // 更新供应商的关于地址的信息<br>17 int rowsAffected = Adapter.Update(supplier);<br>18<br>19 // 如果刚好更新了一条记录，则返回true，否则返回false<br>20 return rowsAffected == 1;<br>21 }<br>22}<br>23</td>
        </tr>
    </tbody>
</table>
<br>　　可以从页面顶部的链接处下载BLL类的完整代码。<br><br>　　第二步：通过BLL类访问类型化数据集<br><br>　　在本教程的第一节中，我们给出了直接使用类型化数据集的例子，不过在我们添加了BLL类之后，表示层就可以通过BLL来工作了。在本教程的第一节中的AllProducts.aspx的例子中，ProductsTableAdapter用于将产品列表绑定到GridView上，代码如下所示：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>1 ProductsTableAdapter productsAdapter = new ProductsTableAdapter();<br>2 GridView1.DataSource = productsAdapter.GetProducts();<br>3 GridView1.DataBind();</td>
        </tr>
    </tbody>
</table>
<br>　　要使用新的BLL类，我们所需要做的仅仅是简单的修改一下第一行代码。用ProductBLL对象来代替 ProductsTableAdapter即可：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>1 ProductsBLL productLogic = new ProductsBLL();<br>2 GridView1.DataSource = productLogic.GetProducts();<br>3 GridView1.DataBind();</td>
        </tr>
    </tbody>
</table>
<br>　　BLL类也可以通过使用ObjectDataSource来清晰明了的访问（就像类型化数据集一样）。我们将在接下来的教程中详细的讨论ObjectDataSource。<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td height=17>
            <div align=center><span style="COLOR: red"><img height=393 src="http://dev.yesky.com/imagelist/06/30/e4l9f61v4g20.gif" width=550 border=0></span><br>图三：GridView中显示的产品列表</div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　第三步：给DataRow添加字段级验证<br><br>　　字段级验证是指在插入或更新时检查业务对象所涉及到的所有属性值。拿产品来举个例，某些字段级的验证规则如下所示：<br><br>　　&#183; ProductName字段不得超过40个字符<br><br>　　&#183; QuantityPerUnit字段不得超过20个字符<br><br>　　&#183; ProductID、ProductName以及Discontinued字段是必填的，而其他字段则是可填可不填的<br><br>　　&#183; UnitPrice、UnitsInStock、UnitsOnOrder以及ReorderLevel字段不得小于0<br><br>　　这些规则可以或者说是应该在数据库层被描述出来。ProductName和QuantityPerUnit字段上的字符数限制可以通过Products表中相应列的数据类型来实现（分别为nvarchar(40) and nvarchar(20)）。字段&#8220;是否必填&#8221;可以通过将数据库中表的相应列设置为&#8220;允许为NULL&#8221;来实现。为了保证UnitPrice、UnitsInStock、UnitsOnOrder以及ReorderLevel字段的值不小于0，可以分别在它们的相应列上加一个约束。<br><br>　　除了在数据库中应用了这些规则之外，它们同时也将被其应用在DataSet上。事实上，字段长度和是否允许为空等信息已经被应用到了各DataTable的DataColumn集合中。我们可以在数据集设计器（DataSet Designer）中看到已经存在的字段级验证，从某个DataTable中选择一个字段，然后在属性窗口中就可以找到了。如图四所示，ProductDataTable中的QuantityPerUnit字段允许空值并且最大长度为20各字符。如果我们试图给某个ProductsDataRow的QuantityPerUnit属性设置一个长度大于20个字符的字符串，将会有一个ArgumentException被抛出。<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img height=506 src="http://dev.yesky.com/imagelist/06/30/1p6d0woi5d6f.gif" width=550 border=0><br>图四：DataColumn提供了基本的字段级验证</div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　不幸的是，我们不能通过属性窗口指定一个边界检查，比如UnitPrice的值不能小于0。为了提供这样的字段级验证，我们需要为DataTable的ColumnChanging事件建立一个Event Handler。正如上一节教程中所提到的那样，由类型化数据集创建的DataSet、DataTable还有DataRow对象可以通过partial类来进行扩展。使用这个技术，我们可以为ProductDataTable创建一个ColumnChanging的Event Handler。我们先在App_Code文件夹中新建一个名为ProductsDataTable.ColumnChanging.cs的类文件，如下图所示。<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img src="http://dev.yesky.com/imagelist/06/30/7ku3g39h9iu8.gif" border=0><br>图五：在App_Code文件夹中添加新类</div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　然后，给ColumnChanging事件创建一个Event handler，以保证UnitPrice、UnitsInStock、UnitsOnOrder以及ReorderLevel字段的值不小于0。如果这些列的值超出范围就抛出一个ArgumentException。<br><br>　　ProductsDataTable.ColumnChanging.cs<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>1public partial class Northwind<br>2{<br>3 public partial class ProductsDataTable<br>4 {<br>5 public override void BeginInit()<br>6 {<br>7 this.ColumnChanging += ValidateColumn;<br>8 }<br>9<br>10 void ValidateColumn(object sender, DataColumnChangeEventArgs e)<br>11 {<br>12 if(e.Column.Equals(this.UnitPriceColumn))<br>13 {<br>14 if(!Convert.IsDBNull(e.ProposedValue) &amp;&amp; (decimal)e.ProposedValue &lt; 0)<br>15 {<br>16 throw new ArgumentException("UnitPrice cannot be less than zero", "UnitPrice");<br>17 }<br>18 }<br>19 else if (e.Column.Equals(this.UnitsInStockColumn) ||<br>20 e.Column.Equals(this.UnitsOnOrderColumn) ||<br>21 e.Column.Equals(this.ReorderLevelColumn))<br>22 {<br>23 if (!Convert.IsDBNull(e.ProposedValue) &amp;&amp; (short)e.ProposedValue &lt; 0)<br>24 {<br>25 throw new ArgumentException(string.Format("{0} cannot be less than zero", e.Column.ColumnName), e.Column.ColumnName);<br>26 }<br>27 }<br>28 }<br>29 }<br>30}</td>
        </tr>
    </tbody>
</table>
<br>　　第四步：给BLL类添加业务规则<br><br>　　除了字段级的验证，可能还有一些不能在单个列中表示的包含不同实体或概念的更高级的业务规则，比如：<br><br>　　&#183; 如果一个产品被标记为&#8220;停用&#8221;，那么它的单价就不能被修改<br><br>　　&#183; 一个雇员的居住地必须与他（她）的主管的居住地相同<br><br>　　&#183; 如果某个产品是某供应商唯一提供的产品，那么这个产品就不能被标记为&#8220;停用&#8221;<br><br>　　BLL类应该保证始终都验证应用程序的业务规则。这些验证可以直接的添加到应用他们的方法中。<br><br>　　想象一下，我们的业务规则表明了如果一个产品是给定的供应商的唯一产品，那么它就不能被标记为&#8220;停用&#8221;。也就是说，如果产品X是我们从供应商Y处购买的唯一一个产品，那么我们就不能将X标记为停用；然而，如果供应商Y提供给我们的一共有3样产品，分别是A、B和C，那么我们可以将其中任何一个或者三个全部都标记为&#8220;停用&#8221;。挺奇怪的业务规则，是吧？但是商业上的规则通常就是跟我们平常的感觉不太一样。 <br><br>　　要在UpdateProducts方法中应用这个业务规则，那么我们就应该先检查Discontinued是否被设置为true。假如是这样的话，那么我们应该先调用GetProductsBySupplierID来看看我们从这个供应商处一共购买了多少产品。如果我们仅仅从这个供应商处购买了这一个产品，那么我们就抛出一个ApplicationException。<br><br>　　UpdateProduct<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>1public bool UpdateProduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit,<br>2 decimal unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel,<br>3 bool discontinued, int productID)<br>4{<br>5 Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);<br>6 if (products.Count == 0)<br>7 // 没有找到匹配项，返回false<br>8 return false;<br>9<br>10 Northwind.ProductsRow product = products[0];<br>11<br>12 // 业务规则检查 &#8211; 不能停用某供应商所提供的唯一一个产品<br>13 if (discontinued)<br>14 {<br>15 // 获取我们从这个供应商处获得的所有产品<br>16 Northwind.ProductsDataTable productsBySupplier = Adapter.GetProductsBySupplierID(product.SupplierID);<br>17<br>18 if (productsBySupplier.Count == 1)<br>19 // 这是我们从这个供应商处获得的唯一一个产品<br>20 throw new ApplicationException("You cannot mark a product as discontinued if its the only product purchased from a supplier");<br>21 }<br>22<br>23 product.ProductName = productName;<br>24 if (supplierID == null) product.SetSupplierIDNull(); else product.SupplierID = supplierID.Value;<br>25 if (categoryID == null) product.SetCategoryIDNull(); else product.CategoryID = categoryID.Value;<br>26 if (quantityPerUnit == null) product.SetQuantityPerUnitNull(); else product.QuantityPerUnit = quantityPerUnit;<br>27 if (unitPrice == null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value;<br>28 if (unitsInStock == null) product.SetUnitsInStockNull(); else product.UnitsInStock = unitsInStock.Value;<br>29 if (unitsOnOrder == null) product.SetUnitsOnOrderNull(); else product.UnitsOnOrder = unitsOnOrder.Value;<br>30 if (reorderLevel == null) product.SetReorderLevelNull(); else product.ReorderLevel = reorderLevel.Value;<br>31 product.Discontinued = discontinued;<br>32<br>33 // 更新产品记录<br>34 int rowsAffected = Adapter.Update(product);<br>35<br>36 // 如果刚好更新了一条记录，则返回true，否则返回false<br>37 return rowsAffected == 1;<br>38}<br>39</td>
        </tr>
    </tbody>
</table>
<br>　　<strong>在表示层中响应验证错误</strong><br><br>　　当我们从表示层中调用BLL时，我们可以决定是否要处理某个可能会被抛出的异常或者让它直接抛给ASP.NET（这样将会引发HttpApplication的出错事件）。在使用BLL的时候，如果要以编程的方式处理一个异常，我们可以使用try...catch块，就像下面的示例一样：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>1 ProductsBLL productLogic = new ProductsBLL();<br>2 <br>3 // 更新ProductID为1的产品信息<br>4 try<br>5 {<br>6 // 这个操作将会失败，因为我们试图使用一个小于0的UnitPrice<br>7 productLogic.UpdateProduct("Scott's Tea", 1, 1, null, -14m, 10, null, null, false, 1);<br>8 }<br>9 catch (ArgumentException ae)<br>10 {<br>11 Response.Write("There was a problem: " + ae.Message);<br>12 }</td>
        </tr>
    </tbody>
</table>
<br>　　我们将在后面的教程中看到，当通过一个数据Web控件（data Web Control）来进行插入、修改或删除操作数据时，处理从BLL中抛出的异常可以直接在一个Event Handler中进行，而不需要使用try&#8230;catch块来包装代码。<br><br>　　<strong>总结</strong><br><br>　　一个具有良好架构的应用程序都拥有清晰的层次结构，每一个层次都封装了一个特定的角色。在本教程的第一篇中，我们用类型化数据集创建了一个数据访问层；这一篇中，我们又建立了一个业务逻辑层，它由App_Code中一系列的类构成，并调用DAL中相应的方法。BLL为我们的应用程序实现了字段级和业务级的逻辑。除了创建一个独立的BLL，就像我们在本节中所做的那样，另外一个选择是使用partial类来扩展TableAdapter中的方法。然而，使用这个技术并不能使我们可以重写已经存在的方法，也不能将我们的DAL和BLL分开得足够清晰。<br><br>　　完成了DAL和BLL之后，我们就准备开始处理表示层了。在下一个教程中，我们将简单的介绍一些数据访问的主题，并为整个教程定义一个一致的页面呈现。
<img src ="http://www.cppblog.com/eday/aggbug/36718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-15 21:00 <a href="http://www.cppblog.com/eday/articles/36718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ASP.NET2.0数据操作之创建数据访问层</title><link>http://www.cppblog.com/eday/articles/36711.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Thu, 15 Nov 2007 12:37:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/36711.html</guid><description><![CDATA[<strong>导言 <br><br></strong>　　作为web开发人员，我们的生活围绕着数据操作。我们建立数据库来存储数据，写编码来访问和修改数据，设计网页来采集和汇总数据。本文是研究在ASP.NET 2.0中实现这些常见的数据访问模式之技术的长篇系列教程的第一篇。我们将从创建一个软件框架开始，这个框架的组成部分包括一个使用强类型的DataSet的数据访问层(DAL)，一个实施用户定义的业务规则的业务逻辑层(BLL)，以及一个由共享页面布局的ASP.NET网页组成的表现层。在打下这个后端的基础工作之后，我们将开始转向报表，示范如何显示，汇总，采集，和验证web 应用的数据。这些教程旨在简明扼要，使用了许多屏幕截图，提供了按步就 班(step-by-step)的指导，带你经历这个开发过程。每个教程都有C# 版和VB版，并且附有涉及的完整的编码的下载。(这第一个教程比较长，但以后其他的教程将以更容易消化的篇幅推出。)<br><br>　　在这些教程中，我们将使用置于App_Data 目录内的微 软SQL Server 2005 Express版的Northwind数据库。除了数据库文件外，App_Data目录还带有用于创建数据库的SQL脚本，万一你想使用别的数据库版本的话。如果你愿意的话，你也可以直接从微软下载这些脚本。如果你使用别的SQL Server版本的Northwind数据库的话，你需要更新Web.config文件中的NORTHWNDConnectionString设置。本教程中的web应用是个基于文件系统的网站项目，是使用Visual Studio 2005 专业版建立起来的。但是，所有的教程都可以在Visual Studio 2005的免费版本Visual Web Developer中运行。 <br><br>　　在这个教程里，我们将从头开始，先创建一个数据访问层(DAL)，然后在第二个教程里创建一个业务逻辑层(BLL)，在第三个教程里设计页面布局和导航。以后的教程将建立在这三个教程的基础之上。在第一个教程里，我们要讨论的内容多多，所以，请打开Visual Studio，让我们动起手来！ <br><br>　　<strong>第一步：创建一个Web项目，配置数据库连接 </strong><br><br>　　在我们开始创建数据访问层(DAL)之前，我们首先需要创建一个网站，以及建立一个数据库。我们从创建一个基于文件系统的ASP.NET 网站开始。次序如下，打开文件(File)菜单，选择新的网站 (New Web Site)，系统会显示一个新网站对话框，选择ASP.NET网站模板(Web Site template)，设置定 位(Location)列表的选项为文件系统( File System)，然后选这一个放置这个网站的文件夹，然后选择编程语 言为C#。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/8m354c64mp0d.png"><br><strong>图 1: 创建一个基于文件系统的网站</strong><br><br>　　Visual Studio会为你生成一个新的网站，同时生成一个名为Default.aspx的网页，和一 个App_Data文件夹。<br><br>　　网站生成之后，下一步是在Visual Studio的服务器资源管理器(Server Explorer)里为你的数据库添加一个引 用(reference)。把一个数据库添加到服务器资源管理器之后，你就能在Visual Studio环境里添加数据表，存 储过程，视图等等。你也能查看数据库里的数据，手工或用查询生成器(Query Builder)的图形界面建立你自己的查询语句。此外，当我们为DAL创建强类型的DataSet时，我们需要把Visual Studio指向作为DataSet数据源的目标数据库。虽然我们可以在适当时候提供所昀敳獴搨 ???oЁ涉及的数据库连接信息，但假如我们预 先在服务器资源管理器里注册这些数据库的话，Visual Studio会自动把这些数据库填充到一个下拉列表中去 。<br><br>　　把Northwind数据库添加到服务器资源管理器中去的步骤取决于你想使用放置在App_Data文件夹 里的SQL Server 2005 Express 版本数据库，还是你想使用已经建立好了的SQL Server 2000或2005 数据库服 务器。 <br><br><strong>　　使用置于App_Data文件夹中的数据库</strong><br><br>　　如果你没有可连接的SQL Server 2000 或2005服务器，或者你就是想避免给数据库服务器添加数据库，你可以使用SQL Server 2005 Express版的Northwind数据库，该数据库位于下载源码中的App_Data文件夹里(NORTHWND.MDF)。 <br><br>　　置于App_Data文件夹里的数据库会被自动添加到服务器资源管理器中。假设你已经在你的机器上安装了SQL Server 2005 Express版本，那么你应该在服务器资源管理器中看到一个名为NORTHWND.MDF的节点，你可以将这个节点扩展开来，浏览其中的数据表，视图，存储过程等等 (参考图2)。 <br><br>　　App_Data文件夹还可以放置微软的Access.mdb数据库文件，跟SQL Server 的数 据库文件类似，这些Access文件会被自动地添加到服务器资源管理器中。如果你不想用任何SQL Server数据库，那么你总归可以下载微软Access版本的Northwind 数据库文件，然后将其放置于App_Data文件夹中。但记住，Access数据库没有SQL Server那么多功能，而且它并不是设计来在网站情形下使用的。此外，在后面几个教程里将用到Access数据库不支持的数据库层次的功能。 <br><br>　　连接到微软SQL Server 2000或2005数据库服务器中的数据库 <br><br>　　或者，你也可以连接到安装在数据库服务器上的Northwind数据库。假如数据库服务器上尚未安装Northwind数据库的话，你首先必须运行本教程下载文件中的安装脚本来把数据库添加到数据库服务器上去，或者你也可以从微软网站上<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46a0-8da2-eebc53a68034&amp;DisplayLang=en"><font color=#000000>直接下载SQL Server 2000的Northwind数据库以及安装脚本</font></a>。 <br><br>　　安装数据库完毕之后，去Visual Studio中的服务器资源管理器，在数据连接(Data Connections)节点上按右鼠标，选择&#8220;添加连接(Add Connection)&#8221;。如果你看不到服务器资源管理器，去菜单&#8220;查看(View)&#8221;点击 &#8220;服务器资源管理器&#8221;，或者按组合键Ctrl+Alt+S来打开服务器资源管理器。这会打开添加连接的对话框，在这上面，你可以设置需要连接的服务器，认证信息，以及数据库名字。在你成功配置数据库连接信息，按OK按钮之后，数据库就会被添加成数据连接节点之下的一个节点。然后，你就可以扩展数据库节点来浏览数据表，视图，存储过程等等。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/8cytg4udcz24.png"><br><strong>图 2: 添加一个到你的数据库服务器上的Northwind数据库的连接</strong><br><br>　　<strong>第二步：创建一个数据访问层 </strong><br><br>　　与数据打交道时，一种做法是把跟数据相关的逻辑直接放在表现层中(在一个web应用里，ASP.NET网页构成了表现层)。其形式一般是在ASP.NET 网页的编码部分写ADO.NET 编码或者在标识符部 分使用SqlDataSource控件。在这两种形式里，这种做法都把数据访问逻辑与表现层紧密耦合起来了。但推荐 的做法是，把数据访问逻辑从表现层分离开来。这个分开的层被称作是数据访问层，简写为DAL，一般是通过 一个单独的类库项目来实现的。这种分层框架的好处在很多文献里都有阐述(详见本教程最后的&#8220;附加读物&#8221;里 的资源)，在本系列中我们将采用这种方法。 <br><br>　　跟底层数据源相关的所有编码，譬如建立到数据库的连接，发出SELECT，INSERT ，UPDATE，和DELETE命令等的编码，都应该放置在DAL中。表现层不应该包含对 这些数据访问编码的任何引用，而应该调用DAL中的编码来作所有的数据访问请求。数据访问层包含访问底层数据库数据的方法。譬如，Northwind数据库中，有Products和Categories两个表，它们记录了可供销售的产品以及这些产品 所属的分类。在我们的DAL中，我们将有下面这样的方法：
<ul>
    <li>GetCategories(), 返回所有分类的信息
    <li>GetProducts(), 返回所有产品的信息
    <li>GetProductsByCategoryID(<em>categoryID</em>), 返回属于指定分类的所有产品的信 息
    <li>GetProductByProductID(<em>productID</em>), 返回指定产品的信息 </li>
</ul>
　　这些方法，被调用后，将连接到数据库，发出合适的查询，然后返回结果。我们如何返回这些结果是很重要的 。这些方法可以直接返回数据库查询填充的DataSet 或者DataReader ，但理想的办法是把这些结果以<em>强类 型对象</em>的形式返回。一个强类型的对象，其schema是编译时严格定义好的，而相比之下，弱类型的对象， 其schema在运行时之前是未知的。 <br><br>　　譬如，DataReader和普通的DataSet是弱类型对象，因为它们的schema是被用来填充它们的数据库查询返回的字段来定义的。要访问弱类型DataTable中的一个特定字段，我们需要用这样的句法：<em>DataTable</em>.Rows[<em>index</em>] ["<em>columnName</em>"]。这个例子中的DataTable的弱类型性质表现在于，我们需要通过一个字符串或序号索引来访问字段名称。而在另一个方面，一个强类型的DataTable，它的所有的字段都是通过属性的形式来实现的 ，访问的编码就会象这样：<em>DataTable</em>.Rows[<em>index</em>].<em>columnName</em>。 <br><br>　　要返回强类型对象，开发人员可以创建自定义业务对象，或者使用强类型的DataSet。开发人员实现的业务对 象类，其属性往往是对相应的底层数据表的字段的映射。而一个强类型的DataSet，则是Visual Studio基于数 据库schema为你生成的一个类，其成员的类型都是由这个schema决定的。强类型的DataSet本身，是由继承 于ADO.NET中DataSet，DataTable，和DataRow类的子类组成的。除了强类型的DataTable外，强类型的DataSet现在还包括TableAdapter类，这些类包含了填充DataSet中的DataTable和把 DataTable的改动传回数据库的各种方法。<br><br><strong>　　</strong>在这些教程的架构里，我们将使用强类型的DataSet。图3示范说明了使用强类型的DataSet之应用程序的不 同层间的流程(workflow)。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/i5o86hzyo7xi.png"><br><strong>图 3: 把所有的数据访问编码委托给DAL</strong><br><br>　　<strong>创建强类型的DataSet和Table Adapter </strong><br><br>　　我们开始创建我们的DAL，先给我们的项目添加一个强类型的DataSet。做法如下，在昀敳獴搨 ???oЁ解决方案管理器里的项目 节点上按右鼠标，选择&#8220;添加新项(Add a New Item)&#8221;。在模板列单里选择DataSet，将其命名 为Northwind.xsd。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/7a82y404873d.png"><br><strong>图 4: 给你的项目添加一个新的DataSet</strong><br><br>　　在点击&#8220;添加(Add)&#8221;按钮后，Visual Studio会问我们是否将DataSet添加到App_Code文件夹中，选择&#8220;Yes&#8221; 。然后Visual Studio会显示强类型的DataSet的设计器，同时会启动TableAdapter配置向导，允许你给你的强 类型DataSet添加第一个TableAdapter。 <br><br>　　强类型的DataSet 起了强类型对象的集合的作用，它由强类型DataTable实例组成，每个强类型DataTable又进 而由强类型的DataRow实例组成。我们将为这个教程系列要用到的每个数据表建立一个对应的强类型DataTable 。让我们开始吧，先为Products表建立一个DataTable。<br><br>　　记住，强类型的DataTable并不包括如何访问对应底层的数据表的任何信息。要获取用来填充DataTable的数据 ，我们使用TableAdapter类，它提供了数据访问层的功能。对于我们的Products DataTable， 相应的TableAdapter 类将包 括GetProducts()和GetProductByCategoryID(<em>categoryID</em>)等方法，而我 们将在表现层调用这些方法。DataTable的作用是在分层间传输数据。 <br><br>　　TableAdapter配置向导首先要你选择使用哪个数据库。下拉框里列出了服务器资源管理器内的那些数据库。如 果你预先没有把Northwind数据库添加到服务器资源管理器里去的话，这时你可以点击新连接按钮来添加。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/42o5nx9w7mv6.png"><br><strong>图 5: 在下拉框里选择Northwind数据库</strong><br><br>　　选择好数据库后，按&#8220;下一步&#8221;按钮，向导会问你是否想在Web.config文件里存放连接字符串。 将连接字符串存放在Web.config文件里，你可以避免把连接字符串硬写在TableAdapter类的编 码中，如果将来连接字符串信息改动的话，这种做法会极大地简化要做的编码改动。如果你选择在配置文件存 放连接字符串，连接字符串将被置放于＜connectionStrings＞段落中，这个段落可以被<a href="http://aspnet.4guysfromrolla.com/articles/021506-1.aspx"><u><font color=#0066cc>加密</font></u></a>来提高安全，也可以通过IIS 图形界面管理工具中的新的ASP.NET 2.0属性页来修改。当然这个工具更适于管理员。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/e17a00ynp8b8.png"><br><strong>图6: 在Web.config中存放连接字符串</strong><br><br>　　接下来，我们需要定义第一个强类型的DataTable的schema，同时为用来填充强类型DataSet的TableAdapter类 提供第一个方法。这两步可以通过建立一个返回对应于DataTable的数据表的字段的查询同时完成。在向导的 最后，我们将为这个查询对应的方法命名。完成后，这个方法可以在表现层调用，它会执行设置好的查询，进 而填充一个强类型的DataTable。 <br><br>　　开始定义SQL查询之前，我们必须首先选择我们想要TableAdapter执行查询的方式。我们可以直接用ad-hoc的SQL语句，或建立一个新的存储过程，或使用现存的存储过程。在这些教程里，我们将使用ad-hoc的SQL语句。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/x3ro8z4n63w8.png"><br><strong>图 7: 用SQL语句查询数据</strong><br><br>　　至此，我们可以手工输入SQL查询。当生成TableAdapter的第一个方法时，你一般想要让你的查询返回那些需 要在对应的DataTable中存放的字段。我们可以建立一个从Products表里返回所有字段，所有数 据行的查询来达到我们的目的： <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/192xb17lv3yn.png"><br><strong>图 8: 在文本框里输入SQL查询</strong><br><br>　　或者，我们可以使用查询生成器(Query Builder)，用图形界面来构造查询，如图9所示。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/v4pgchfysk7b.png"><br><strong>图 9: 通过查询编辑器生成查询</strong><br><br>　　在生成查询之后，在移到下一屏之前，点击&#8220;高级选项(Advanced Options)&#8221;按钮。在网站项目里，在默认 情形下，&#8220;生成插入，更新，删除语句&#8221;是唯一已被选中的选项。如果你在类库项目或Windows项目里运行这个 向导的话，&#8220;采用优化的并发控制(optimistic concurrency)&#8221;选项也会被选中。现在先别选&#8220;采用优化的并发 控制&#8221;这个选项。在以后的教程里我们会详细讨论优化的并发控制。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/y8aa8v6fbw4b.png"><br><strong>图 10: 只选&#8220;生成插入，更新和删除语句&#8221;这个选项</strong><br><br>　　在核实高级选项后，按&#8220;下一步(Next)&#8221;按钮转到最后一屏。在这里，配置向导会问我们要给TableAdapter选择添加什么方法。填充数据有两种模式： <br>
<ul>
    <li><strong>填充DataTable</strong> &#8211; 这个做法会生成一个方法，该方法接受一个DataTable的参数，基于查询的结果 填充这个DataTable。譬如，ADO.NET的DataAdapter类就是在它的Fill()方法中实现这个模式的 。
    <li><strong>返回DataTable</strong> &#8211; 这个做法会生成一个方法，该方法会创建并填充一个DataTable，然后将 其作为方法的返回值。</li>
</ul>
<br>　　你可以让TableAdapter实现其中一个模式或者同时实现两个模式。你也可以重新命名这里提供的这些方法。让 我们对两个复选框的选项不做改动，虽然我们在这些教程里只需要使用后面这个模式。同时，让我们把那个很 一般性的GetData方法名改成GetProducts。 <br><br>　　这最后一个复选框，&#8220;生成DB直接方法(GenerateDBDirectMethods)&#8221;，如果选了的话，会为TableAdapter自动生 成<cod昀敳獴搨 ???oЁE>Insert()，Update()，和Delete()方法。如果你不选这个选项 的话，所有的更新都需要通过TableAdapter唯一的Update()方法来实现，该方法接受一个强类型的DataSet，或者一个DataTable，或者单个DataRow，或者一个DataRow数组。(假如你 在图9所示的高级属性里把&#8220;生成添加，更新和删除语句&#8221;的选项去掉的话，这个复选框是不起作用的)。让我们 保留这个复选框的选项。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/3nv9vk9k7nx1.png"><br><strong>图 11: 把方法名字从 GetData 改成 GetProducts</strong><br><br>　　按&#8220;完成&#8221;按钮结束向导。在向导关闭后，我们回到DataSet设计器中，它会显示我们刚创建的DataTable。你可 以看到Products DataTable的字段列单(ProductID, ProductName 等)，还有ProductsTableAdapter的Fill()和GetProducts()方法 。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/7q93329q026z.png"><br><strong>图 12: Products DataTable和ProductsTableAdapter被添加到强类 型DataSet中</strong><br><br>　　至此，我们生成了含有单一DataTable类(Northwind.Products)的强类型DataSet以及一个含 有GetProducts()方法的强类 型DataAdapter类(NorthwindTableAdapters.ProductsTableAdapter)。通过这些对象可以用下 列编码来获取所有产品的列单： <br>
<div><br>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>C#</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>NorthwindTableAdapters.ProductsTableAdapter
            productsAdapter = new
            NorthwindTableAdapters.ProductsTableAdapter();
            Northwind.ProductsDataTable products;
            products = productsAdapter.GetProducts();
            foreach (Northwind.ProductsRow productRow in products)
            Response.Write("Product: " +
            productRow.ProductName + "＜br /＞");
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br>　　这段编码不要求我们写一行的跟数据访问有关的编码。我们不需要生成任何ADO.NET类的实例，我们不需要 指明任何连接字符串，任何SQL查询语句，或者任何存储过程。TableAdapter为我们提供了底层的数据访问编 码！ <br><br>　　这个例子里的每个对象都是强类型的，允许Visual Studio提供IntelliSense帮助以及编译时类型检查。最棒 的是，从TableAdapter 返回的DataTable可以直接绑定到ASP.NET数据Web 控件上去，这样的控件包 括GridView，DetailsView，DropDownList，CheckBoxList，以及另外几个控件。下面这个例子示范只要 在Page_Load事件处理函数里添加短短的三行编码就能将从GetProducts()方法返 回的DataTable绑定到一个GridView上去。 <br><br><strong><u>　　AllProducts.aspx</u></strong><br><br>
<div id=ctl00_CenterContent_syn2>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>ASP.NET</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>＜%@ Page Language="C#"
            AutoEventWireup="true" CodeFile="AllProducts.aspx.cs"
            Inherits="AllProducts" %＞
            ＜!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
            Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"＞
            ＜html xmlns="http://www.w3.org/1999/xhtml" ＞
            ＜head runat="server"＞
            ＜title＞View All Products in a GridView＜/title＞
            ＜link href="Styles.css"
            rel="stylesheet"
            type="text/css"
            /＞
            ＜/head＞
            ＜body＞
            ＜form id="form1" runat="server"＞
            ＜div＞
            ＜h1＞
            All Products＜/h1＞
            ＜p＞
            ＜asp:GridView ID="GridView1" runat="server"
            CssClass="DataWebControlStyle"＞
            ＜HeaderStyle CssClass="HeaderStyle" /＞
            ＜AlternatingRowStyle CssClass="AlternatingRowStyle" /＞
            ＜/asp:GridView＞
            &amp;nbsp;＜/p＞
            ＜/div＞
            ＜/form＞
            ＜/body＞
            ＜/html＞
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br><strong><u>　　AllProducts.aspx.cs</u></strong><br><br>
<div id=ctl00_CenterContent_syn3>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>C#</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>using System;
            using System.Data;
            using System.Configuration;
            using System.Collections;
            using System.Web;
            using System.Web.Security;
            using System.Web.UI;
            using System.Web.UI.WebControls;
            using System.Web.UI.WebControls.WebParts;
            using System.Web.UI.HtmlControls;
            using NorthwindTableAdapters;
            public partial class
            AllProducts : System.Web.UI.Page
            {
            protected void
            Page_Load(object sender, EventArgs e)
            {
            ProductsTableAdapter productsAdapter = new
            ProductsTableAdapter();
            GridView1.DataSource = productsAdapter.GetProducts();
            GridView1.DataBind();
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br><img alt="" src="http://dev.yesky.com/imagelist/06/29/423srhk9651x.png"><br><strong>图 13: 显示在GridView里的产品列单</strong><br><br>　　这个例子要求我们在ASP.NET网页的Page_Load事件处理函数里，写三行编码。在以后的教程里，我们将讨 论使用ObjectDataSource，用声明的方式来从DAL中获取数据。用ObjectDataSource的话，我们一行编码都不 用写，而且还能得到分页和排序支持呢！<br><br>　　<strong>第三步：给数据访问层添加参数化的方法</strong> <br><br>　　至此，ProductsTableAdapter只有一个方法，GetProducts()，它返回数据库里的所有产品。能够操作所有的产品当然有用，但很多时候我们想要获取关于一个指定产品的信息，或者属于某个特 定分类的所有产品。要想给我们的数据访问层添加这样的功能，我们可以给TableAdapter添加参数化的方法。 <br><br>　　让我们来添加一个GetProductsByCategoryID(<em>categoryID</em>)方法。为给DAL添加新的 方法，让我们回到DataSet设计器，在ProductsTableAdapter上按右鼠标，然后选择&#8220;添加查 询(Add Query)&#8221;。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/vdw77u3lrz98.png"><br><strong>图 14: 在TableAdapter上按右鼠标，选择&#8220;添加查询&#8221;</strong><br><br>　　向导首先会问我们是否要通过一个ad-hoc SQL语句还是生成一个新存储过程或者使用现有存储过程来访问 数据库。让我们还是选择使用SQL 语句。接着，向导会问我们使用什么类型的SQL查询。因为我们想返回属于 指定分类的所有产品，我们需要写一个返回数据行的SELECT语句。<br><br><a href="http://www.asp.net/learn/dataaccess/images/01fig15cs.png"><img alt="" src="http://dev.yesky.com/imagelist/06/29/zsa80isso8s6.png" border=0></a><br><strong>图 15: 选择生成一个返回数据行的SELECT语句</strong><br><br>　　下一步是定义用于访问数据的SQL查询语句。因为我们只想返回属于指定分类的那些产品，我重 用GetProducts()里的SELECT语句，但添加了一个WHERE 子 句：WHERE CategoryID = @CategoryID。其中的@CategoryID参数 向TableAdapter配置向导表示我们正在生成的方法将需要一个对应类(即，可为null-nullable的整数)的输入 参数。<br><br><a href="http://www.asp.net/learn/dataaccess/images/01fig16cs.png"><img alt="" src="http://dev.yesky.com/imagelist/06/29/g27geuu747w7.png" border=0></a><br><strong>图 16: 输入一个只返回指定分类的产品的查询</strong><br><br>　　在最后一步，我们可以选择使用何种数据访问模式，还可以定制生成的方法的名字。对应于Fill 模式，让我们把名字改成FillByCategoryID，对返回DataTable模式的方法(Get<em>X</em>方法)，让我们来用GetProductsByCategoryID这个名字。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/0xa58575aaof.png"><br><strong>图 17: 为TableAdapter的方法选择名字</strong><br><br>　　在结束向导后，DataSet设计器包含了这些新的TableAdapter的方法。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/xn351kv5hmko.png"><br><strong>图18: 通过分类来查询产品</strong><br><br>　　花点时间用同样的手法添加一个GetProductByProductID(<em>productID</em>) 方法。<br><br>　　这些参数化的查询可以在DataSet设计器里直接测试。在TableAdapter中的方法上按右鼠标，然后选择&#8220;预 览数据(Preview Data)&#8221;。接着，输入对应参数的值，然后按&#8220;预览(Preview)&#8221;。</a> <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/8u08omzg7i4f.png"><br><strong>图19: 属于饮料(Beverages)类的那些产品列单</strong><br><br>　　通过我们的DAL中的GetProductsByCategoryID(<em>categoryID</em>)方法，我们就能设计一 个ASP.NET网页来显示属于指定分类的那些产品。下面这个例子显示了属于Beverages(饮 料)类(CategoryID=1)的所有产品。<br><br><strong><u>　　Beverages.aspx</u></strong><br><br>
<div id=ctl00_CenterContent_syn4>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>ASP.NET</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>＜%@ Page Language="C#"
            AutoEventWireup="true" CodeFile="Beverages.aspx.cs"
            Inherits="Beverages" %＞
            ＜!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
            Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"＞
            ＜html xmlns="http://www.w3.org/1999/xhtml" ＞
            ＜head runat="server"＞
            ＜title＞Untitled Page＜/title＞
            ＜link href="Styles.css"
            rel="stylesheet"
            type="text/css"
            /＞
            ＜/head＞
            ＜body＞
            ＜form id="form1" runat="server"＞
            ＜div＞
            ＜h1＞Beverages＜/h1＞
            ＜p＞
            ＜asp:GridView ID="GridView1" runat="server"
            CssClass="DataWebControlStyle"＞
            ＜HeaderStyle CssClass="HeaderStyle" /＞
            ＜AlternatingRowStyle CssClass="AlternatingRowStyle" /＞
            ＜/asp:GridView＞
            &amp;nbsp;＜/p＞
            ＜/div＞
            ＜/form＞
            ＜/body＞
            ＜/html＞
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br><strong><u>　　Beverages.aspx.cs</u></strong><br><br>
<div id=ctl00_CenterContent_syn5>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>C#</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>using System;
            using System.Data;
            using System.Configuration;
            using System.Collections;
            using System.Web;
            using System.Web.Security;
            using System.Web.UI;
            using System.Web.UI.WebControls;
            using System.Web.UI.WebControls.WebParts;
            using System.Web.UI.HtmlControls;
            using NorthwindTableAdapters;
            public partial class
            Beverages : System.Web.UI.Page
            {
            protected void
            Page_Load(object sender, EventArgs e)
            {
            ProductsTableAdapter productsAdapter = new
            ProductsTableAdapter();
            GridView1.DataSource =
            productsAdapter.GetProductsByCategoryID(1);
            GridView1.DataBind();
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br><img alt="" src="http://dev.yesky.com/imagelist/06/29/v6qczp08eeb6.png" border=0><br><strong>图 20: 属于Beverages(饮料)类的所有产品显示</strong><br><br>　　<strong>第四步：插入，更新和删除数据 </strong><br><br>　　常用的插入，更新和删除数据的模式有两种。第一种模式，我称之为DB直接模式，涉及的方法被调用时，会向数据库里发出一个INSERT， 或UPDATE，或DELETE命令，这个命令只对单个数据库记录做操作。象这样的方法一般接受一系列对应于插入，更新或删除的值的标量参数(譬如整数，字符串，布尔值，日期时间等)。譬如，用这个模式来操作Products表的话，删除方法会接受一个整数参数，代表所需要删除的记录的ProductID，而插入方法则会接受一个对应于ProductName的字符串，对应 于UnitPrice的decimal值，对应于UnitsOnStock的整数等等。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/8yt40ucj7o02.png"><br><strong>图 21: 每个插入，更新，和删除请求都被立刻发送到数据库</strong><br><br>　　另外一个模式，我称之为批更新模式，可以在一个方法调用里更新整个DataSet，或者整个DataTable，或 者一个DataRow集合。在这个模式里，开发人员在一个DataTable中删除，插入，修改DataRow，然后把这 些DataRow或整个DataTable传给一个更新方法。然后这个方法会轮循传入的DataRow们，通过DataRow的RowState属 性属性来决定这些DataRow是否被改动过，或是新记录，或是被删除的记录，然后为每个记录发出合适的 数据库命令。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/9w1g9oo5015d.png"><br><strong>图 22: 在Update 方法调用之后，所有的变动都与数据库同步了</strong><br><br>　　在默认情形下，TableAdapter采用批更新模式，但也支持DB直接模式。因为我们在创建我们的TableAdapter时的高级选项中选择了&#8220;生成插入，更新，和删除语句&#8221; 这个选项，ProductsTableAdapter 包含了一个 Update()方法，该方法实现了批 更新模式。具体地说，TableAdapter包含了一个Update()&lt;昀敳獴搨 ???oЁCODE&gt; 方法，可以传入一个强类型 的DataSet，或者一个强类型的DataTable，或者一个和多个DataRow。假如你在一开始创建TableAdapter时的选项中没有清除&#8220;生成DB直接方法(GenerateDBDirectMethods)&#8221;复选框的话，DB直接模 式也会通过Insert()，Update()和Delete()方法来实现。<br><br>　　这两种数据修改模式都使用 了TableAdapter的InsertCommand，UpdateCommand, 和DeleteCommand属性来向数据库发出对应 的INSERT，UPDATE和DELETE命令。你可以在DataSet设计器里点击TableAdapter，然后在属性窗口查看和改 动InsertCommand，UpdateCommand, 和DeleteCommand属性。(确 认你选择了TableAdapter，并且ProductsTableAdapter对象是属性窗口中下拉框里被选中的项) <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/4v673eg00y83.png"><br><strong>图23: TableAdapter包含InsertCommand，UpdateCommand, 和DeleteCommand等属性</strong><br><br>　　想查看或改动这些数据库命令的属性的话，点击CommandText子属性，这会启动对应的查询 生成器。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/5o58eq0q4492.png"><br><strong>图 24: 在查询生成器里配置插入，更新，删除语句</strong><br><br>　　下面的编码例子示范了如何使用批更新模式来把没被终止的，且库存等于或少于25个单元的产品的价格加 倍：<br><br>
<div id=ctl00_CenterContent_syn6>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>C#</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>NorthwindTableAdapters.ProductsTableAdapter
            productsAdapter =
            new NorthwindTableAdapters.ProductsTableAdapter();
            // For each product, double its price if it is not discontinued
            and
            // there are 25 items in stock or less
            Northwind.ProductsDataTable products = productsAdapter.GetProducts();
            foreach (Northwind.ProductsRow product in products)
            if (!product.Discontinued &amp;&amp; product.UnitsInStock
            ＜= 25)
            product.UnitPrice *= 2;
            // Update the products
            productsAdapter.Update(products);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br>　　下面的编码示范如何使用DB直接模式删除一个产品，更新一个产品，然后添加一个新的产品：<br><br>
<div id=ctl00_CenterContent_syn7>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>C#</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>NorthwindTableAdapters.ProductsTableAdapter
            productsAdapter = new
            NorthwindTableAdapters.ProductsTableAdapter();
            // Delete the product with ProductID 3
            productsAdapter.Delete(3);
            // Update Chai (ProductID of 1), setting the UnitsOnOrder to
            15
            productsAdapter.Update("Chai", 1, 1, "10 boxes x 20 bags",
            18.0m, 39, 15, 10, false, 1);
            // Add a new product
            productsAdapter.Insert("New Product", 1, 1,
            "12 tins per carton", 14.95m, 15, 0, 10, false);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
　　<strong>创建自定义的插入，更新，删除方法 </strong><br><br>　　用DB直接法生成的Insert(), Update(),和Delete()方法有时 候会感觉有点不方便，特别是当数据表有许多字段的时候。看一下前面这个编码例子，没有IntelliSense的帮 助的话，不是很清楚Products表的哪个字段对 应Update()和Insert()方法中的哪个输入参数。有时候我们只要更新一到二个字 段或者需要一个自定义的Insert()方法，这个方法需要返回刚插入的记录 的IDENTITY(自增)的字段值。<br><br>　　要创建这样的自定义方法，回到DataSet设计器。在TableAdapter上按右鼠标，选择&#8220;添加查询&#8221;，然后回 到TableAdapter配置向导。在第二屏上，我们可以指明要生成的查询的类型。让我们生成一个添加新 的product(产品)记录，然后返回新添加记录的ProductID值的方法。因此，选择生成一个插 入(INSERT)型查询。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/56lk17yzv112.png"><br><strong>图25: 创建一个给Products表添加新记录的方法</strong><br><br>　　下一个屏显示InsertCommand的CommandText属性。在查询语句后面，增添一 个SELECT SCOPE_IDENTITY()的查询，这查询将返回当前同一个操作范围内插 入IDENTITY字段的最后那个identity 值。(详见技术文档中关 于SCOPE_IDENTITY()的内容以及为什么你应该使用SCOPE_IDENTITY()而不是 @@IDENTITY)。确认在添加SELECT语句前，你在INSERT语句后面添一个分号 。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/28334ad3qff8.png"><br><strong>图26: 增添查询返回SCOPE_IDENTITY()值</strong><br><br>　　最后，把这个新方法命名为InsertProduct。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/p0xfk4r40o5a.png"><br><strong>图 27:放方法名字设成InsertProduct </strong><br><br>　　当你返回DataSet设计器时，你将看到ProductsTableAdapter多了一个新的方 法，InsertProduct。如果对应Products表的每个字段，这个新的方法没有对应的参数的话，非常可能的原因是，你忘了给INSERT语句的结尾添加一个分号(semi-colon)。重新配 置InsertProduct方法，确认在INSERT和SELECT语句间有个分号。 <br><br>　　在默认情形下，插入方法调用的是非查询(non-query)方法，意即，他们只返回受影响的记录数。但是，我们想要让InsertProduct方法返回一个查询返回的值，而不是受影响的记录数。这可以把InsertProduct方法的ExecuteMode属性改 成Scalar(标量)来实现。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/j0755xpk3wk7.png"><br><strong>图 28:把ExecuteMode属性改成Scalar</strong><br><br>　　下面的编码示范如何使用这个新的InsertProduct方法:<br><br>
<div id=ctl00_CenterContent_syn8>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>C#</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>NorthwindTableAdapters.ProductsTableAdapter
            productsAdapter = new
            NorthwindTableAdapters.ProductsTableAdapter();
            // Add a new product
            int new_productID =
            Convert.ToInt32(productsAdapter.InsertProduct("New
            Product", 1, 1, "12 tins per carton",
            14.95m, 10, 0, 10, false));
            // On second thought, delete the product
            productsAdapter.Delete(new_productID);
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
　　<strong>第五步：完成数据访问层</strong> <br><br>　　注意，ProductsTableAdapters类从Products表中返回的 是CategoryID和SupplierID的值，但并不包括Categories表 的CategoryName字段和Suppliers表的CompanyName字段，尽管当 我们显示产品信息时，这些很可能是我们想要显示的字段。我们可以扩充TableAdapter的起始方 法GetProducts()来包含CategoryName和CompanyName字段的值， 这方法进而会更新强类型的DataTable来包括这些新的字段。 <br><br>　　但这会造成一个问题，因为TableAdapter的插入，更新，删除数据的方法是基于这个起始方法的，幸运的是， 自动生成的插入，更新，删除方法并不会受SELECT子句中的子查询的影响。如果我们注意把 对Categories和Suppliers的查询添加成子查询，而不是用JOIN语 句的话，我们可以避免重做这些修改数据的方法。在ProductsTableAdapter中的GetProducts()方法上按右鼠标，选择&#8220;配置&#8221;，然后，把SELECT子句改成：<br><br>
<div id=ctl00_CenterContent_syn9>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>SQL</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre><a style="COLOR: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;siteid=us%2Fdev&amp;p=1&amp;nq=NEW&amp;qu=SELECT&amp;IntlSearch=&amp;boolean=PHRASE&amp;ig=01&amp;i=09&amp;i=99">SELECT</a>     ProductID, ProductName, SupplierID, CategoryID,
            QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
            (<a style="COLOR: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;siteid=us%2Fdev&amp;p=1&amp;nq=NEW&amp;qu=SELECT&amp;IntlSearch=&amp;boolean=PHRASE&amp;ig=01&amp;i=09&amp;i=99">SELECT</a> CategoryName <a style="COLOR: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;siteid=us%2Fdev&amp;p=1&amp;nq=NEW&amp;qu=FROM&amp;IntlSearch=&amp;boolean=PHRASE&amp;ig=01&amp;i=09&amp;i=99">FROM</a> Categories
            <a style="COLOR: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;siteid=us%2Fdev&amp;p=1&amp;nq=NEW&amp;qu=WHERE&amp;IntlSearch=&amp;boolean=PHRASE&amp;ig=01&amp;i=09&amp;i=99">WHERE</a> Categories.CategoryID = Products.CategoryID) <a style="COLOR: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;siteid=us%2Fdev&amp;p=1&amp;nq=NEW&amp;qu=as&amp;IntlSearch=&amp;boolean=PHRASE&amp;ig=01&amp;i=09&amp;i=99">as</a> CategoryName,
            (<a style="COLOR: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;siteid=us%2Fdev&amp;p=1&amp;nq=NEW&amp;qu=SELECT&amp;IntlSearch=&amp;boolean=PHRASE&amp;ig=01&amp;i=09&amp;i=99">SELECT</a> CompanyName <a style="COLOR: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;siteid=us%2Fdev&amp;p=1&amp;nq=NEW&amp;qu=FROM&amp;IntlSearch=&amp;boolean=PHRASE&amp;ig=01&amp;i=09&amp;i=99">FROM</a> Suppliers
            <a style="COLOR: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;siteid=us%2Fdev&amp;p=1&amp;nq=NEW&amp;qu=WHERE&amp;IntlSearch=&amp;boolean=PHRASE&amp;ig=01&amp;i=09&amp;i=99">WHERE</a> Suppliers.SupplierID = Products.SupplierID) <a style="COLOR: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;siteid=us%2Fdev&amp;p=1&amp;nq=NEW&amp;qu=as&amp;IntlSearch=&amp;boolean=PHRASE&amp;ig=01&amp;i=09&amp;i=99">as</a> SupplierName
            <a style="COLOR: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;siteid=us%2Fdev&amp;p=1&amp;nq=NEW&amp;qu=FROM&amp;IntlSearch=&amp;boolean=PHRASE&amp;ig=01&amp;i=09&amp;i=99">FROM</a>         Products
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br><img alt="" src="http://dev.yesky.com/imagelist/06/29/48wjthe86el6.png"><br><strong>图29: 更新GetProducts()方法的SELECT语句</strong><br><br>　　在更新GetProducts()方法使用这个新查询语句之后，对应的DataTable将包含2个新字段，CategoryName和SupplierName。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/g2wp9oe31842.png"><br><strong>图30: Products DataTable多了2个新字段</strong><br><br>　　花点时间把GetProductsByCategoryID(<em>categoryID</em>)方法中的SELECT 子句也更新一下。 <br><br>　　如果你使用JOIN句法更新GetProducts()中的SELECT语句的话 ，DataSet设计器不能使用DB直接模式自动生成插入，更新，以及删除数据库记录的方法。你必须手工生成这 些方法，就象本教程早先时候我们对InsertProduct方法的做法一样。此外，你必须手工提供 InsertCommand，UpdateCommand和DeleteCommand属性值，假如你 想使用批更新模式的话。<br>　　<strong>添加其他的TableAdapter</strong> <br><br>　　到目前为止，我们只讨论了针对单个数据表的单个TableAdapter。但是，Northwind数据库里含有我们需要在 我们的web应用中使用的几个相关的表。一个强类型的DataSet可以包含多个相关的DataTable。因此，为了完 成我们的DAL，我们需要为这些我们将来要用到的数据表添加相应的DataTable。步骤如下，打开 DataSet设计 器，在设计器上按右鼠标，选择&#8220;添加/TableAdapter&#8221;。这会生成一个新的DataTable和TableAdapter，然后我 们早先讨论过的配置向导会指引你完成配置。<br><br>　　花上几分钟，创建对应于下列查询的TableAdapter及其方法。注意，ProductsTableAdapter的查询中包含了用以获取每个产品的分类和供应商名字的子查询。另外，如果你是随着教程在做的话，你已经添加过ProductsTableAdapter类 的GetProducts()和GetProductsByCategoryID(<em>categoryID</em>)方法了。 <br>
<ul>
    <li><strong><u>ProductsTableAdapter</u></strong>
    <ul>
        <li><strong>GetProducts</strong>:<br><br>SELECT ProductID, ProductName, SupplierID, CategoryID, <br>QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, <br>ReorderLevel, Discontinued , (SELECT CategoryName FROM <br>Categories WHERE Categories.CategoryID = <br>Products.ProductID) as CategoryName, (SELECT CompanyName <br>FROM Suppliers WHERE Suppliers.SupplierID = <br>Products.SupplierID) as SupplierName<br>FROM Products<br>
        <li><strong>GetProductsByCategoryID</strong>:<br><br>SELECT ProductID, ProductName, SupplierID, CategoryID, <br>QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, <br>ReorderLevel, Discontinued , (SELECT CategoryName FROM <br>Categories WHERE Categories.CategoryID = <br>Products.ProductID) as CategoryName, <br>(SELECT CompanyName FROM Suppliers WHERE <br>Suppliers.SupplierID = Products.SupplierID) as SupplierName<br>FROM Products<br>WHERE CategoryID = @CategoryID<br>
        <li><strong>GetProductsBySupplierID<br><br></strong>SELECT ProductID, ProductName, SupplierID, CategoryID, <br>QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, <br>ReorderLevel, Discontinued , <br>(SELECT CategoryName FROM Categories WHERE <br>Categories.CategoryID = Products.ProductID) <br>as CategoryName, (SELECT CompanyName FROM Suppliers <br>WHERE Suppliers.SupplierID = Products.SupplierID) <br>as SupplierName<br>FROM Products<br>WHERE SupplierID = @SupplierID<br>
        <li><strong>GetProductByProductID<br><br></strong>SELECT ProductID, ProductName, SupplierID, CategoryID, <br>QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, <br>ReorderLevel, Discontinued , (SELECT CategoryName <br>FROM Categories WHERE Categories.CategoryID = <br>Products.ProductID) as CategoryName, <br>(SELECT CompanyName FROM Suppliers <br>WHERE Suppliers.SupplierID = Products.SupplierID) <br>as SupplierName<br>FROM Products<br>WHERE ProductID = @ProductID<strong><br><br></strong></li>
    </ul>
    <li><strong><u>CategoriesTableAdapter</u></strong>
    <ul>
        <li><strong>GetCategories<br><br></strong>SELECT CategoryID, CategoryName, Description<br>FROM Categories<strong><br></strong>
        <li><strong>GetCategoryByCategoryID<br><br></strong>SELECT CategoryID, CategoryName, Description<br>FROM Categories<br>WHERE CategoryID = @CategoryID<strong><br><br></strong></li>
    </ul>
    <li><strong><u>SuppliersTableAdapter</u></strong>
    <ul>
        <li><strong>GetSuppliers<br><br></strong>SELECT SupplierID, CompanyName, Address, City, <br>Country, Phone<br>FROM Suppliers<strong><br></strong>
        <li><strong>GetSuppliersByCountry<br><br></strong>SELECT SupplierID, CompanyName, Address, <br>City, Country, Phone<br>FROM Suppliers<br>WHERE Country = @Country<strong><br></strong>
        <li><strong>GetSupplierBySupplierID<br><br></strong>SELECT SupplierID, CompanyName, Address, <br>City, Country, Phone<br>FROM Suppliers<br>WHERE SupplierID = @SupplierID<br><strong><br></strong></li>
    </ul>
    <li><strong><u>EmployeesTableAdapter</u></strong>
    <ul>
        <li><strong>GetEmployees<br><br></strong>SELECT EmployeeID, LastName, FirstName, <br>Title, HireDate, ReportsTo, Country<br>FROM Employees<strong><br></strong>
        <li><strong>GetEmployeesByManager<br><br></strong>SELECT EmployeeID, LastName, FirstName, <br>Title, HireDate, ReportsTo, Country<br>FROM Employees<br>WHERE ReportsTo = @ManagerID<strong><br></strong>
        <li><strong>GetEmployeeByEmployeeID<br><br></strong>SELECT ployeeID, LastName, FirstName, <br>Title, HireDate, ReportsTo, Country<br>FROM Employees<br>WHERE EmployeeID = @EmployeeID<strong><br></strong></li>
    </ul>
    </li>
</ul>
<br><img alt="" src="http://dev.yesky.com/imagelist/06/29/5ez35fm1q2r3.png" border=0><br><strong>图31:添加了四个TableAdapter后的DataSet设计器</strong><br>　　<strong>给DAL添加定制编码</strong> <br><br>　　添加到强类型DataSet中的TableAdapter和DataTable是在一个XML Schema定义文 件(Northwind.xsd)中定义的。你可以在解决方案资源管理器里在Northwind.xsd 文件上按右鼠标，选择&#8220;查看编码(View Code)&#8221;，打开这个Schema文件来查看其中内容。<br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/73zu5nu77ww9.png"><br><strong>图32：Northwinds强类型DataSet的XML Schema定义文件</strong><br><br>　　这个schema信息在设计时编译之后会被翻译成C#或Visual Basic 编码，或者如果有必要的话，会在运行时 翻译，然后你就能在调试器里单步遍历执行。想查看这些自动生成的编码的话，在类视图里，展 开TableAdapter 类或者强类型的DataSet 类。如果在屏幕上看不到类视图的话，在&#8220;查看&#8221;(View)菜单里选择&#8220; 类视图&#8221;，或者按键组合Ctrl+Shift+C。在类视图里，你能看到强类型的DataSet类和TableAdapter类的属性，方法和事件。想看某个特定的方法的编码话，在类视图双击对应方法的名字或者在方法上按右鼠标，选 择&#8220;移至定义区(Go To Definition)&#8221;。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/85tbfr486s1v.png"><br><strong>图33：在类视图里选择&#8220;移至定义区(Go To Definition)&#8221;，查看自动生成的编码</strong><br><br>　　虽然自动生成的编码省时省力，但这样的编码往往是非常通用化的(generic)，为满足一个应用程序特有的需 求需要做些定制。但扩展自动生成的编码的风险在于，如果生成这些编码的工具决定该是重新生成这些编码的 时候了，则会把你定制的编码冲掉。使用.NET 2.0中的一个新的部分(partial)类的概念，很容易将一个类的 定义分写在几个文件里。这允许我们给自动生成的类添加我们自己的方法，属性，和事件，而不用担心Visual Studio会冲掉我们的定制编码。 <br><br>　　为示范如何定制DAL起见，让我们来给SuppliersRow 添加一个GetProducts()方法。这 个SuppliersRow类代表了Suppliers表的个别记录，每个供应商(supplier)可以 提供0个到多个产品，所以GetProducts()将返回指定的供应商的这些产品。做法如 下，在App_Code文件夹里添加一个新的类文件，将其命名为SuppliersRow.cs， 然后在其中添加下列编码： <br><br>
<div 0>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>C#</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>using System;
            using System.Data;
            using NorthwindTableAdapters;
            public partial class
            Northwind
            {
            public partial class
            SuppliersRow
            {
            public Northwind.ProductsDataTable GetProducts()
            {
            ProductsTableAdapter productsAdapter =
            new ProductsTableAdapter();
            return
            productsAdapter.GetProductsBySupplierID(this.SupplierID);
            }
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br>　　这个部分(partial)类指示编译器在编译Northwind.SuppliersRow类时，应该包含我们刚定义的这个GetProducts()方法。如果你编译你的项目，然后返回类视图，你就会看到GetProducts()已被列为Northwind.SuppliersRow的一个方法。 <br><br><img alt="" src="http://dev.yesky.com/imagelist/06/29/ecx4yx29ayyx.png"><br><strong>图34: GetProducts()方法成为Northwind.SuppliersRow类的一部 分</strong><br><br>　　GetProducts()方法现在就能用来枚举一个指定供应商的产品列单，如下列编码所示：<br><br>
<div 1>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>C#</td>
        </tr>
        <tr>
            <td>
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%" width="98%">
            <pre>NorthwindTableAdapters.SuppliersTableAdapter
            suppliersAdapter = new
            NorthwindTableAdapters.SuppliersTableAdapter();
            // Get all of the suppliers
            Northwind.SuppliersDataTable suppliers =
            suppliersAdapter.GetSuppliers();
            // Enumerate the suppliers
            foreach (Northwind.SuppliersRow supplier in suppliers)
            {
            Response.Write("Supplier: " +
            supplier.CompanyName);
            Response.Write("＜ul＞");
            // List the products for this supplier
            Northwind.ProductsDataTable products = supplier.GetProducts();
            foreach (Northwind.ProductsRow product in products)
            Response.Write("＜li＞" +
            product.ProductName + "＜/li＞");
            Response.Write("＜/ul＞＜p＞&amp;nbsp;＜/p＞");
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br>　　This data can also be displayed in any of ASP.NET's data Web controls. The following page uses a GridView control with two fields:数据也可以在任何一种ASP.NET的Web控件中显示。下面这个网页 使用了含有2个字段的GridView 控件：<br>
<ul>
    <li>一个BoundField用以显示每个供应商的名字,
    <li>另一个TemplateField，包含了一个BulletedList控件，用来绑定针对每个供应商调用 的GetProducts()方法返回的结果 </li>
</ul>
　　我们将在以后的教程里讨论怎样来显示这样的主/从(master-detail)报表。在这里，这个例子的目的是用 来示范如何使用添加到Northwind.SuppliersRow类中的自定义的方法的。<br><br><strong><u>SuppliersAndProducts.aspx</u></strong><br>
<div 2>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>ASP.NET</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            23
            24
            25
            26
            27
            28
            29
            30
            31
            32
            33
            34
            35
            36
            37
            38
            39
            40
            41
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>＜%@ Page Language="C#"
            AutoEventWireup="true" CodeFile="SuppliersAndProducts.aspx.cs"
            Inherits="SuppliersAndProducts" %＞
            ＜!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
            Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"＞
            ＜html xmlns="http://www.w3.org/1999/xhtml" ＞
            ＜head runat="server"＞
            ＜title＞Untitled Page＜/title＞
            ＜link href="Styles.css"
            rel="stylesheet"
            type="text/css"
            /＞
            ＜/head＞
            ＜body＞
            ＜form id="form1" runat="server"＞
            ＜div＞
            ＜h1＞
            Suppliers and Their Products＜/h1＞
            ＜p＞
            ＜asp:GridView ID="GridView1" runat="server"
            AutoGenerateColumns="False"
            CssClass="DataWebControlStyle"＞
            ＜HeaderStyle CssClass="HeaderStyle" /＞
            ＜AlternatingRowStyle CssClass="AlternatingRowStyle" /＞
            ＜Columns＞
            ＜asp:BoundField DataField="CompanyName"
            HeaderText="Supplier" /＞
            ＜asp:TemplateField HeaderText="Products"＞
            ＜ItemTemplate＞
            ＜asp:BulletedList ID="BulletedList1"
            runat="server" DataSource="＜%#
            ((Northwind.SuppliersRow)((System.Data.DataRowView)
            Container.DataItem).Row).GetProducts() %＞"
            DataTextField="ProductName"＞
            ＜/asp:BulletedList＞
            ＜/ItemTemplate＞
            ＜/asp:TemplateField＞
            ＜/Columns＞
            ＜/asp:GridView＞
            &amp;nbsp;＜/p＞
            ＜/div＞
            ＜/form＞
            ＜/body＞
            ＜/html＞
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br><strong><u>SuppliersAndProducts.aspx.cs</u></strong><br>
<div>
<table style="WIDTH: 100%">
    <tbody>
        <tr>
            <td style="FONT-WEIGHT: bold" colSpan=2>C#</td>
        </tr>
        <tr>
            <td style="VERTICAL-ALIGN: top; WIDTH: 1%; TEXT-ALIGN: right">
            <pre>1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            </pre>
            </td>
            <td style="VERTICAL-ALIGN: top; WIDTH: 99%">
            <pre>using System;
            using System.Data;
            using System.Configuration;
            using System.Collections;
            using System.Web;
            using System.Web.Security;
            using System.Web.UI;
            using System.Web.UI.WebControls;
            using System.Web.UI.WebControls.WebParts;
            using System.Web.UI.HtmlControls;
            using NorthwindTableAdapters;
            public partial class
            SuppliersAndProducts : System.Web.UI.Page
            {
            protected void
            Page_Load(object sender, EventArgs e)
            {
            SuppliersTableAdapter suppliersAdapter = new
            SuppliersTableAdapter();
            GridView1.DataSource = suppliersAdapter.GetSuppliers();
            GridView1.DataBind();
            }
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
</div>
<br><img alt="" src="http://dev.yesky.com/imagelist/06/29/v9y83t0z164s.png"><br><strong>图 35: 供应商的公司名字列在左栏，他们的产品列在右栏</strong><br><br>　　<strong>总结</strong> <br><br>　　构造web应用时，创建DAL应该是你最先做的步骤之一，应该在你开始创建表现层之前进行。使用Visual Studio的话，创建基于强类型DataSet的DAL是个可以不写一行编码，在10到15分钟内就可完成的任务。以后的 教程将建立在这个DAL基础之上。在下一个教程里，我们将定义一堆业务规则，然后看一下如何在一个分开的 业务逻辑层里实现这些规则。 <br>
<img src ="http://www.cppblog.com/eday/aggbug/36711.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-15 20:37 <a href="http://www.cppblog.com/eday/articles/36711.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>UrlRewrite、地址映射技术</title><link>http://www.cppblog.com/eday/articles/36530.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 13 Nov 2007 11:46:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/36530.html</guid><description><![CDATA[<table cellSpacing=0 cellPadding=4 width=760 align=center border=0>
    <tbody>
        <tr>
            <td>
            <p>UrlRewrite有什么用处？ </p>
            <p>1、满足搜索引擎的要求 <br>某些搜索引擎不能支持动态页面的抓取，大量的信息就不能被潜在用户搜索到。用UrlRewrite技术你可以把 http://server/news.asp?id=111 变成 http://server/news/111.htm 这样他们就会被搜索引擎收录了。google虽然可以抓取动态页面，但是google对动态页面的评分一般低于静态页面。所以，对大量信息发布的网站，把网站地址改变成静态的绝对是值得的。 </p>
            <p>2、隐藏技术实现，提高网站的移植性 <br>每个页面都挂着鲜明的.asp/.jsp这种开发语言的标记，可以一眼让人看出你的网站使用什么语言做的。而且在改变网站的语言的时候，你需要改动大量的链接。而且，一个页面修改了扩展名，他的pagerank也会随之消失，从头开始。我们可以用UrlRewrite技术隐藏我们的实现细节，这样修改移植都很方便，而且完全不损失pagerank。 </p>
            <p>3、满足美感的要求 <br>对于追求完美主义的网站设计师，即使是网页的地址也要看起来简洁明快。形如 http://server/news.asp?channel=3&amp;id=111 的网页地址，肯定是上不了完美主义者的法眼的，用UrlRewrite技术，你可以把他变成 http://server/news/3/111.htm 。 </p>
            <p>IIS 5.0支持UrlRewrite么？ </p>
            <p>答案很简单，不支持。但是我们可以通过安装服务器扩展让IIS支持。 </p>
            <p>目前有两种产品支持IIS 5.0的UrlRewrite，isapi_rewrite 和 IIS Rewrite。 </p>
            <p>isapi_rewrite: http://www.helicontech.com/download/#isapi_rewrite <br>IIS Rewrite :http://www.qwerksoft.com/products/iisrewrite/download.asp </p>
            <p>这里只有ISAPI Rewrite的一个LITE版本是免费的，其它都是trial版本。ISAPI Rewrite Lite的版本功能。 </p>
            <p><br>我们采用isapi_rewrite Lite Version(免费版本)。 </p>
            <p><br>引用: <br>This is simplified edition of ISAPI_Rewrite. It does not support per-virtual-site configurations, proxiing, metabase monitoring and automatic cache cleanup but all other features are supported. </p>
            <p><br>所以，lite版本不支持虚拟站点配置，元数据监测和自动缓存清理。 </p>
            <p><br>metabase元数据：metabase 元数据库 指一个驻留内存的数据存储区域，其中存放着IIS的配置值。/Metabase是储存成System32\Inetsrv <br>资料夹中的Metabase.bin文件 </p>
            <p>&nbsp;</p>
            <p>如何进行UrlRewrite的设置？ </p>
            <p>isapi_rewrite利用正则表达式进行替换规则的表示。 </p>
            <p>下面是一个简单的例子，我想让我们的用户输入 http://server/test-12314.html 实际上访问的是 http://server/test.asp?id=12314 。那么我们的匹配表达式应该是 /test-([0-9]*).html 对应的格式化表达式应该为 /test.asp\?id=$1 。 </p>
            <p>进行正则表达式的编写的时候，可以利用isapi_rewrite提供的正则表达式测试工具（默认安装提供），进行调试。如下图： </p>
            <p><br>做好了匹配表达式和格式化表达式，我们可以按照下面的格式，把它们放到安装目录下的httpd.ini里面。 </p>
            <p>格式：RewriteRule 匹配表达式 格式化表达式 <br>刚才的例子：RewriteRule /test-([0-9]*).html /test.asp\?id=$1 </p>
            <p>文件保存后，不需重新启动iis即可生效。 </p>
            <p>参考资料： </p>
            <p>面向Google(Search Engine Friendly)的URL设计 <br>http://www.chedong.com/tech/google_url.html </p>
            <p>ISAPI REWRITE文档 <br>http://www.isapirewrite.com/docs/ </p>
            <p>操作实例：</p>
            <p>1.下载ISAPI_Rewrite.ISAPI_Rewrite分精简(Lite)和完全(Full)版.精简版不支持对每个虚拟主机站点进行重写,只能进行全局处理.不过对于有服务器的朋友,精简版也就够啦.精简版下载地址:http://www.helicontech.com/download/,就是那Lite Version (free)啦.</p>
            <p>2.安装.msi的文件,和装一般程序一样装就可以了,俺就装在D:\ISAPI_Rewrite.</p>
            <p><a href="http://www.easewe.com/Article/Document/%CD%F8%D5%BE%A1%A2%CD%F8%D2%B3%D6%C6%D7%F7/UrlRewrite/20056295614109.jpg" target=_blank><img title=点击在新窗口查看原始图片 style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height=213 alt="" src="http://www.cppblog.com/images/cppblog_com/eday/2991/o_20056295614109.jpg" width=357 onload="java_script_:if(this.width>500)this.width=500" border=0 src_cetemp="http://www.cppblog.com/images/cppblog_com/eday/2991/o_20056295614109.jpg"></a><br>3.接下来一步比较重要哦,看仔细喽.打开Internet 信息服务,右键,web站点属性,电ISAPI筛选器选项卡.添加筛选器,名称自己填,路径自己指定ISAPI_Rewrite.dll,然后确定.</p>
            <p><a href="http://www.easewe.com/Article/Document/%CD%F8%D5%BE%A1%A2%CD%F8%D2%B3%D6%C6%D7%F7/UrlRewrite/20056295641225.jpg" target=_blank><img title=点击在新窗口查看原始图片 style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height=387 alt="" src="http://www.cppblog.com/images/cppblog_com/eday/2991/o_20056295641225.jpg" width=500 onload="java_script_:if(this.width>500)this.width=500" border=0 src_cetemp="http://www.cppblog.com/images/cppblog_com/eday/2991/o_20056295641225.jpg"></a><br></p>
            <p>.来测试一下.新建一个1ting.asp,里面写上</p>
            <p>&nbsp;</p>
            <p>&nbsp; CODE: [Copy to clipboard]&nbsp;&nbsp; <br>&lt;%=request.querystring("inso")%&gt; <br>&nbsp;</p>
            <p><br>, </p>
            <p>效果就是执行的时候1ting.asp?inso=*浏览器显示*.</p>
            <p><a href="http://www.easewe.com/Article/Document/%CD%F8%D5%BE%A1%A2%CD%F8%D2%B3%D6%C6%D7%F7/UrlRewrite/20056295723687.jpg" target=_blank><img title=点击在新窗口查看原始图片 style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height=165 alt="" src="http://www.cppblog.com/images/cppblog_com/eday/2991/o_20056295723687.jpg" width=247 onload="java_script_:if(this.width>500)this.width=500" border=0 src_cetemp="http://www.cppblog.com/images/cppblog_com/eday/2991/o_20056295723687.jpg"></a></p>
            <p><br>5.这一步很重要哦,开始添加rewrite规则.正则,好头痛,幸亏这个例子比较简单.<br>找到ISAPI_Rewrite目录,把httpd.ini的只读属性去掉,打开编辑.我们要把1ting.asp?inso=im286映射成为1ting-im286.html这样的类型,需要在httpd.ini里加上这么一行:</p>
            <p>&nbsp;</p>
            <p>&nbsp; CODE: [Copy to clipboard]&nbsp;&nbsp; <br>RewriteRule /1ting-([0-9,a-z]*).html /1ting.asp\?inso=$1 <br>&nbsp;</p>
            <p><br>,保存.</p>
            <p><a href="http://www.easewe.com/Article/Document/%CD%F8%D5%BE%A1%A2%CD%F8%D2%B3%D6%C6%D7%F7/UrlRewrite/20056295749394.jpg" target=_blank><img title=点击在新窗口查看原始图片 style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height=166 alt="" src="http://www.cppblog.com/images/cppblog_com/eday/2991/o_20056295749394.jpg" width=500 onload="java_script_:if(this.width>500)this.width=500" border=0 src_cetemp="http://www.cppblog.com/images/cppblog_com/eday/2991/o_20056295749394.jpg"></a></p>
            <p><a href="http://www.easewe.com/Article/Document/%CD%F8%D5%BE%A1%A2%CD%F8%D2%B3%D6%C6%D7%F7/UrlRewrite/2005629588932.jpg" target=_blank><img title=点击在新窗口查看原始图片 style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" height=226 alt="" src="http://www.cppblog.com/images/cppblog_com/eday/2991/o_2005629588932.jpg" width=248 onload="java_script_:if(this.width>500)this.width=500" border=0 src_cetemp="http://www.cppblog.com/images/cppblog_com/eday/2991/o_2005629588932.jpg"></a></p>
            </td>
        </tr>
    </tbody>
</table>
<!--end-->
<p>&nbsp;</p>
<img src ="http://www.cppblog.com/eday/aggbug/36530.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-13 19:46 <a href="http://www.cppblog.com/eday/articles/36530.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用强名称程序集避免“DLL地狱”</title><link>http://www.cppblog.com/eday/articles/36529.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 13 Nov 2007 11:38:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/36529.html</guid><description><![CDATA[为Microsoft .NET框架创建应用程序时，你获得的最大的一个承诺就是能避免所谓的<a href="http://news.com.com/2100-1012-991466.html" target=_target><u><font color=#0066cc>DLL地狱</font></u></a>。它是指当一个组件更新后，可能会中断依赖于它的其他应用程序。然而，为了理解这个承诺，开发者需要熟悉&#8220;强名称&#8221;（Strong Names）的概念与实现。本文将引导你理解强名称在托管代码中的应用。<br>
<h5>为什么要使用强名称<br></h5>
<p>在讨论强名称的好处之前，先来看看它的定义。强名称由用于标识一个程序集的信息构成，其中包括程序集的文本名称、分为4部分的版本号、区域性信息（如果有的话）、一个公钥以及一个数字签名。这些信息存储在程序集的清单（manifest）中。清单包含了程序集的元数据，并嵌入程序集的某个文件中。</p>
<div align=center>
<hr align=center width="100%" SIZE=1>
</div>
<p align=left><strong>注意</strong><br>大多数程序集（比如使用Visual Studio .NET创建的那些）都是单文件程序集，也就是只有一个.exe或者.dll文件。在这种情况下，清单直接嵌入单文件程序集中。但是，你可用&#8220;程序集生成工具&#8221;（Al.exe）来创建多文件程序集。 </p>
<div align=center>
<hr align=center width="100%" SIZE=1>
</div>
<p><br>在程序集中包括一个强名称后，公共语言运行库（CLR）可保证具有相同强名称的两个程序集在任何方面都是完全一致的。换言之，强名称为CLR提供了一个程序集的惟一性标识。除此之外，添加一个强名称还可确保二进制完整性，因为CLR可在程序集加载时执行验证，判断它自从编译以来是否被篡改过。</p>
<p>在两种主要的情况下，开发者应为一个程序集包括强名称：</p>
<ul type=disc>
    <li><strong>共享程序集。</strong>通过包括强名称，程序集在安装到&#8220;全局程序集缓存&#8221;（GAC）之后，就由同一台机器上运行的多个应用程序共享。这种代码共享模型与非托管世界中使用的模型刚好相反。在非托管世界中，COM组件一旦编译并在系统注册表中注册，就自动共享。
    <li><strong>Serviced Component。</strong>一个.NET类要想使用企业服务（COM+服务），比如分布式事务处理和对象池等等，那么包含类（称为Serviced Component，因为它从EnterpriseServices.ServicedComponent类继承）的程序集必须有一个强名称。有了强名称后，企业服务才能保证加载正确的程序集。企业服务（DLLHost.exe）容纳的进程中所运行的Serviced Component应放到GAC中；相反，作为库应用程序在调用者的进程中运行的那些ServicedComponent则不必这样做。 </li>
</ul>
<p>在第一种情况下（共享程序集放到GAC中），主要的优点包括： <br><br><strong>单一部署</strong><br>由于同一台机器上的所有应用程序都从GAC加载共享程序集，所以不需要为每个应用程序都部署程序集。这有别于.NET框架默认的&#8220;私有程序集&#8221;，它必须随同每个应用程序来部署。</p>
<p><strong>绕过验证</strong><br>如前所述，强名称允许CLR的类加载器验证程序集自编译后便没有被篡改过。将程序集放到GAC中，只有在程序集首次放入GAC时才会执行验证，而不是应用程序每次加载它时都执行验证，这有助于提升性能。</p>
<p><strong>减少工作量</strong><br>如果多个应用程序引用同一个共享程序集，所有应用程序都从相同的位置加载程序集。因此，操作系统在所有应用程序中共享程序集的代码页，这减少了内存占用。<br><br><strong>集中更新</strong><br>程序集部署到GAC后，就可集中部署修正内容。虽然应用程序默认使用程序当初编译时的版本，而且GAC允许相同程序集的多个版本并存，但只需在machine.config文件中添加一个版本策略，即可强迫机器上的所有应用程序使用新版本，而不是使用旧版本。除此之外，一旦程序集包含强名称，其他代码就可指定：只有来自具有特定强名称的一个程序集中的代码才能调用自己。例如，为一个类添加StrongNameIdentityPermissionAttribute后，就可确保只有具有指定强名称的调用者才能创建这个类的实例，如<strong><a href="http://builder.com.com/utils/sidebar.jhtml?id=u00220030624dlx01.htm&amp;index=1" target=_target><u><font color=#800080>清单A</font></u></a></strong>所示。这个例子指定了PublicKey属性，所以凡是使用与这个公钥配对的私钥签署的任何程序集，都允许实例化Products类。<br><br></p>
<h5>要注意的问题<br></h5>
<p>虽然强名称提供了许多好处，包括允许代码共享，并允许托管代码使用企业服务等，但开发者需要注意以下问题：<br><br><strong>调用私有程序集</strong><br>假如一个共享程序集试图从私有程序集加载一个类型，CLR会引发一个异常，因为共享程序集只能引用其他共享程序集。正是因为存在这个限制，所以避免了DLL冲突。<br></p>
<p><strong>受信任的程序集</strong><br>强名称虽然引入了&#8220;身份&#8221;的概念，但没有包括&#8220;信任&#8221;机制。例如，使用强名称签署的一个程序集虽然能保证版本兼容性，但不能保证要加载的程序集来自Quilogy。为了用Authenticode数字签名来签署程序集，开发者要使用.NET框架配套提供的命令行实用程序Signcode.exe。程序集使用Authenticode签名进行签署之后，管理员就可创建相应的策略，利用<a href="http://builder.com.com/article.jhtml?id=u00220030402dlx01.htm">代码访问安全性（CAS）机制</a>，允许它下载到用户的机器上并进行加载。签名将成为CLR的类加载器所使用的身份凭证的一部分，用于判断程序集是否应该加载。<br><br><strong>安装问题</strong><br>具有强名称的程序集通常放在GAC中，假如应用程序必须将程序集安装到GAC中，安装过程就必然会复杂一些。幸好，用Visual Studio .NET创建的Windows Installer项目可将程序集自动安装到GAC中。此外，开发者还可使用命令行实用程序Gacutil.exe。<br><br><strong>部署问题</strong><br>与安装密切相关的就是部署问题。.NET框架应用程序最大的一个好处在于，它们可采取一种XCOPY方式来部署。也就是说，应用程序的目录可直接移动到另一台机器，而不必注册组件。然而，如果使用了共享程序集，这一过程就没那么简单了，因为当应用程序部署到另一台机器时，共享程序集也必须安装到GAC中。</p>
<h5>强名称的用法<br></h5>
<p>要为程序集创建一个强名称，开发者可使用程序集创建工具（Al.exe），或将System.Reflection命名空间中的属性包括到自己的代码中。但是，首先必须准备好一对公钥和私钥，以便用它们来签署程序集。在准备生成强名称的那台机器上，可用一个文件来包含这个密钥对，或者将其放到&#8220;加密服务提供程序&#8221;（CSP）内的某个密钥容器中（最终放到注册表中）。<br></p>
<p>要想在文件中创建密钥对，可使用.NET框架提供的&#8220;强名称&#8221;实用程序（Sn.exe）。例如，要创建名为keyfile.dat的一个文件，并在其中包括新的密钥对，可以像下面这样运行实用程序：</p>
<p><font color=#0066ff>Sn.exe &#8211;k keyfile.dat</font></p>
<p>随后，程序集生成工具可利用这个密钥文件来生成强名称：</p>
<p><font color=#0066ff>Al.exe /out:AtomicData.dll /keyfile:keyfile.dat</font><br><br>利用程序集生成工具的开关选项，你可指定使用一个特定的CSP及密钥容器。更常见的情况是，开发者可从AssemblyInfo.vb（或.cs）文件中选用某个属性，包括AssemblyKeyFileAttribute、<font color=#0066ff>AssemblyKeyNameAttribute或者AssemblyDelaySignAttribute：<br>&lt;Assembly: AssemblyKeyFile("keyfile.dat")&gt;<br>&lt;Assembly: AssemblyVersion("1.0.0.*")&gt;</font><br><br>在本例中，包含密钥对的文件将在编译时访问，以创建强名称并将其放到程序集清单中。另外，开发者可使用AssemblyKeyNameAttribute来指定用于存储密钥对的容器的名称。</p>
<p>这里展示的技术适用于小公司或者个人开发。在大型企业中，用于签署代码的密钥对往往会被严密看守。在这种情况下，开发者一般只能访问公钥，私钥只掌握在少数几个受信任的人的手中。但是，开发期间对公钥的访问仍是至关重要的，因为引用&#8220;强名称程序集&#8221;的任何程序集都必须在自己的清单（manifest）里包含公钥。为了确保开发过程的顺利进行，.NET框架也支持推迟签署或部分签署。<br><br>&#8220;部分签署&#8221;是指在编译时，在程序集清单中为完整的强名称签名保留空间。签名可在以后的某个时间添加。同时，其他程序集仍可引用强名称程序集。为了实现&#8220;推迟签署&#8221;，AssemblyInfo文件可包括AssemblyDelaySign属性，并向构造函数传递True。这意味着AssemblyKeyFile中引用的密钥文件只包含公钥（可使用Sn.exe工具的一个开关来完成）。<br><br>如果程序集是部分签署的，它的验证功能也必须关闭。这是由于部分构造的强名称是无效的，不能通过前面说过的二进制完整性检查。要绕过验证，请使用Sn.exe工具的<em>&#8211;Vr</em>开关：<br><br><font color=#0066ff>Sn.exe &#8211;Vr AtomicData.dll</font><br><br>在以后某个时候，可将程序集拿给掌握着私钥的人，由其使用<em>&#8211;R</em>开关来签署强名称：<br></p>
<p><font color=#0066ff>sn.exe &#8211;R AtomicData.dll keyfile.dat</font><br><br></p>
<h5>小结<br></h5>
<p>为程序集创建一个强名称，并利用全局程序集缓存（GAC），开发者就可与机器上的其他应用程序共享程序集。另外，还可访问包括分布式事务处理和对象池在内的&#8220;企业服务&#8221;。但是，创建强名称和使用GAC之后，编译时和部署时必须进行更多的工作。开发者应仔细考虑对于自己创建的程序集来说，创建一个强名称是否划算。</p>
<img src ="http://www.cppblog.com/eday/aggbug/36529.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-13 19:38 <a href="http://www.cppblog.com/eday/articles/36529.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ASP.net 网站和WebApplication区别</title><link>http://www.cppblog.com/eday/articles/36525.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 13 Nov 2007 10:48:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/36525.html</guid><description><![CDATA[WebApplication编程模型的优点： <br><br>●网站编译速度快，使用了增量编译模式，仅仅只有文件被修改后，这部分才会被增量编译进去。 <br><br>●生成的程序集 <br>WebSite：生成随机的程序集名，需要通过插件WebDeployment才可以生成单一程序集 <br>WebApplication：可以指定网站项目生成单一程序集，因为是独立的程序集，所以和其他项目一样可以指定应用程序集的名字、版本、输出位置等信息 <br><br>●可以将网站拆分成多个项目以方便管理 <br><br>●可以从项目中和源代码管理中排除一个文件 <br><br>●方便的支持VSTS的Team&nbsp;Build方便每日构建 <br><br>●更强大的代码检查功能，并且检查策略受源代码控制 <br><br>●可以对编译前后进行自己规定的处理 <br><br>●对App_GlobalResources&nbsp;的Resource强类支持（网上说的，还没有了解过） <br><br>●直接升级使用VS2003构建的大型系统 <br><br>&nbsp; <br><br>WebSite编程模型的优点： <br><br>●动态编译该页面，马上可以看到效果，不用编译整个站点（主要优势） <br><br>●同上，可以使错误的部分和使用的部分不相干扰（可以要求只有编译通过才能签入） <br><br>●可以每个页面生成一个程序集（一般不会采用这种方式） <br><br>●可以把一个目录当做一个Web应用来处理，直接复制文件就可以发布，不需要项目文件（适合小站点） <br><br>●可以把页面也编译到程序集中（应该用不到，而且WebApplication也可以通过WebDeployment插件来实现） <br><br><br>两种编程模型的互相转换： <br><br>VS2005&nbsp;SP1内置了转换程序，可以非常方便的从WebSite转换到WebApplication <br>只需要复制文件，右键执行&#8220;转换为Web应用程序&#8221;即可。 <br><br>未查到有专门的反向转换工具，但比较后发现如果转换也非常简单。 <br>删除所有*.designer.cs <br>将*.aspx、*.ascx、*.master页面文件中的&nbsp;Codebehind="******.aspx.cs"&nbsp;批量替换成&nbsp;CodeFile="******.aspx.cs" <br><br>这样就可以转换回来了<br><br>
<table style="MARGIN: auto auto auto 4.65pt; WIDTH: 509pt; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 width=679 border=0>
    <tbody>
        <tr style="HEIGHT: 14.25pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: silver 0% 50%; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 85pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" vAlign=top width=113>
            <div align=center><span style="FONT-SIZE: 9pt"><strong>Scenario</strong></span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); BACKGROUND: silver 0% 50%; PADDING-BOTTOM: 0cm; WIDTH: 185pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" vAlign=top width=247>
            <div align=center><span style="FONT-SIZE: 9pt"><strong>Web Application Project</strong></span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); BACKGROUND: silver 0% 50%; PADDING-BOTTOM: 0cm; WIDTH: 239pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" vAlign=top width=319>
            <div align=center><span style="FONT-SIZE: 9pt"><strong>Web Site Project</strong></span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 67.5pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 85pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 67.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=113>
            <div align=left><span style="FONT-SIZE: 9pt">Project definition</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 185pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 67.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=247>
            <div align=left><span style="FONT-SIZE: 9pt">跟</span><span style="FONT-SIZE: 9pt"> Visual Studio .NET 2003 </span><span style="FONT-SIZE: 9pt">类似，由于项目文件的存在，只有被项目文件所引用的文件才会在</span><span style="FONT-SIZE: 9pt">Solution Explorer</span><span style="FONT-SIZE: 9pt">中出现。而且只有这些文件才会被编译。可以很容易的把一个</span><span style="FONT-SIZE: 9pt">ASP.NET</span><span style="FONT-SIZE: 9pt">应用拆分成多个</span><span style="FONT-SIZE: 9pt">Visual Studio</span><span style="FONT-SIZE: 9pt">项目。可以很容易的从项目中和源代码管理中排除一个文件。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt"></span>&nbsp;</div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 239pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 67.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=319>
            <div align=left><span style="FONT-SIZE: 9pt">一个目录结构就是一个</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">项目。没有项目文件存在。这个目录下的所有文件，都被作为项目的一部分而存在。<br>我们实际部署的一个网站，部署上当然不会有任何项目文件存在，如果你想对这个网站进行修改，用这种编程模型就非常适合。我们根本不用在乎这个</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">站点中，那些文件属于哪个项目。</span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 135pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 85pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 135pt; BACKGROUND-COLOR: transparent" vAlign=top width=113>
            <div align=left><span style="FONT-SIZE: 9pt">编译和生成</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 185pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 135pt; BACKGROUND-COLOR: transparent" vAlign=top width=247>
            <div align=left><span style="FONT-SIZE: 9pt">跟</span><span style="FONT-SIZE: 9pt">Visual Studio .NET 2003</span><span style="FONT-SIZE: 9pt">的</span><span style="FONT-SIZE: 9pt">Web</span><span style="FONT-SIZE: 9pt">应用项目编译模式几乎一样。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">项目中的所有的</span><span style="FONT-SIZE: 9pt">code-behind </span><span style="FONT-SIZE: 9pt">类文件和独立类文件都被编译成一个独立应用程序集。这个应用程序集被放在</span><span style="FONT-SIZE: 9pt">Bin</span><span style="FONT-SIZE: 9pt">目录下。因为是一个独立的应用程序集，你能够指定应用程序集的名字、版本、输出位置等信息。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">例如：</span><span style="FONT-SIZE: 9pt">Model-View-Controller (MVC) </span><span style="FONT-SIZE: 9pt">模式就可以在这里很好的被使用。因为它允许在</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">页面和</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">用户控件中引用一个独立的类。</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 239pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 135pt; BACKGROUND-COLOR: transparent" vAlign=top width=319>
            <div align=left><span>编译（<strong>Build</strong></span><span style="FONT-SIZE: 9pt">）命令仅仅是测试这个</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">站点是否编译正确，调试一个</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">站点项目的时候，是通过依赖你的源代码文件，</span><span style="FONT-SIZE: 9pt">ASP.net</span><span style="FONT-SIZE: 9pt">进行动态编译页面和类来实现的。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">预编译站点和动态编译站点用的是同一个</span><span style="FONT-SIZE: 9pt"> compilation semantics </span><span style="FONT-SIZE: 9pt">，你可以通过预编译来提高站点的性能。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">ASP.net </span><span style="FONT-SIZE: 9pt">动态编译系统提供了两种模型：默认的</span><span style="FONT-SIZE: 9pt">batch</span>&nbsp;<span style="FONT-SIZE: 9pt">编译模型和</span><span style="FONT-SIZE: 9pt">fixed-names </span><span style="FONT-SIZE: 9pt">编译模型。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">batch</span>&nbsp;<span style="FONT-SIZE: 9pt">编译模型中，被编译成多个应用程序集（典型的是每一个目录被编译成一个）。这时候你看应用程序集，很难对应上是哪个目录。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">fixed-names </span><span style="FONT-SIZE: 9pt">编译模型中，网站的每个页面或者每个用户控件被编译成一个应用程序集。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt"></span>&nbsp;</div>
            </td>
        </tr>
        <tr style="HEIGHT: 135pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 85pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 135pt; BACKGROUND-COLOR: transparent" vAlign=top width=113>
            <div align=left><span style="FONT-SIZE: 9pt">Iterative <br>development</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 185pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 135pt; BACKGROUND-COLOR: transparent" vAlign=top width=247>
            <div align=left><span style="FONT-SIZE: 9pt">调试或者运行</span><span style="FONT-SIZE: 9pt">Web</span><span style="FONT-SIZE: 9pt">页面的时候，你必须全部编译整个</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">项目。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">编译整个</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">项目通常比较快，因为</span><span style="FONT-SIZE: 9pt">Visual Studio</span><span style="FONT-SIZE: 9pt">使用了增量编译模式，仅仅只有文件被修改后，这部分才会被增量编译进去。</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 239pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 135pt; BACKGROUND-COLOR: transparent" vAlign=top width=319>
            <div align=left><span style="FONT-SIZE: 9pt">你可以配置</span><span style="FONT-SIZE: 9pt">Visual Studio 2005</span><span style="FONT-SIZE: 9pt">的编译属性：编译整个站点、编译一个指定页面、或者什么都不作。在最后一种情况下，当你运行一个</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">站点的时候，</span><span style="FONT-SIZE: 9pt">Visual Studio </span><span style="FONT-SIZE: 9pt">仅打开一个浏览器，并访问当前或者起始页，当这个请求被发送后，</span><span style="FONT-SIZE: 9pt">ASP.net </span><span style="FONT-SIZE: 9pt">才开始动态编译。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">这种模式下，页面被动态编译或者被编译成不同应用程序集，所以如果你调试或者运行一个页面的时候，不需要整个项目被编译通过。有错误的部分跟你使用的部分可以互不干扰。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">默认情况下，当你运行或调试任何</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">页的时候，</span><span style="FONT-SIZE: 9pt">Visual Studio</span><span style="FONT-SIZE: 9pt">完全编译</span><span style="FONT-SIZE: 9pt">Web Site</span><span style="FONT-SIZE: 9pt">项目。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">这么做可以看到编译时的所有错误。但是，在开发进程中，完全编译整个站点会是相当慢的。所以推荐你在开发调试中，只编译当前页。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt"></span>&nbsp;</div>
            </td>
        </tr>
        <tr style="HEIGHT: 146.25pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 85pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 146.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=113>
            <div align=left><span style="FONT-SIZE: 9pt">部署</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 185pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 146.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=247>
            <div align=left><span style="FONT-SIZE: 9pt">因为所有的类文件被编译成一个应用程序集，当你部署的时候，只需要把这个应用程序集和</span><span style="FONT-SIZE: 9pt"> .aspx</span><span style="FONT-SIZE: 9pt">文件、</span><span style="FONT-SIZE: 9pt">.ascx</span><span style="FONT-SIZE: 9pt">文件以及其它静态内容文件一起部署。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">这种模型下，</span><span style="FONT-SIZE: 9pt">.aspx </span><span style="FONT-SIZE: 9pt">文件将不被编译，当浏览器访问这个页面的时候，才会被动态编译。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">不过，如果你使用</span><span style="FONT-SIZE: 9pt">Web Deployment Projects (</span><span style="FONT-SIZE: 9pt">一个</span><span style="FONT-SIZE: 9pt">Visual Studio 2005</span><span style="FONT-SIZE: 9pt">的插件，没有被默认包含到</span><span style="FONT-SIZE: 9pt">VS2005</span><span style="FONT-SIZE: 9pt">中</span><span style="FONT-SIZE: 9pt">),</span><span style="FONT-SIZE: 9pt">你就可以把</span><span style="FONT-SIZE: 9pt"> .aspx </span><span style="FONT-SIZE: 9pt">文件也编译进入一个应用程序集中。&nbsp;</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">如果你只修改了小小的一行代码，你也需要把整个项目的所有代码都编译，并且发布包含所有代码的这个应用程序集。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt"></span>&nbsp;</div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 239pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 146.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=319>
            <div align=left><span style="FONT-SIZE: 9pt">使用</span><span style="FONT-SIZE: 9pt">Visual Studio </span><span style="FONT-SIZE: 9pt">的</span><span style="FONT-SIZE: 9pt"> <strong>Publish Website</strong> </span><span style="FONT-SIZE: 9pt">命令，你可以把</span><span style="FONT-SIZE: 9pt">.aspx </span><span style="FONT-SIZE: 9pt">文件</span><span style="FONT-SIZE: 9pt">和</span><span style="FONT-SIZE: 9pt"> code-behind </span><span style="FONT-SIZE: 9pt">文件编译成应用程序集，所以你看到的编译后的</span><span style="FONT-SIZE: 9pt"> .aspx </span><span>文件头发生了变化。（注意：<strong>Build </strong></span><span style="FONT-SIZE: 9pt">命令并不会给你可部署的应用程序集）</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">最新版本的</span><span style="FONT-SIZE: 9pt"> Publish </span><span style="FONT-SIZE: 9pt">将支持仅编译</span><span style="FONT-SIZE: 9pt"> code-behind </span><span style="FONT-SIZE: 9pt">文件，这样部署的时候，将不改变</span><span style="FONT-SIZE: 9pt"> .aspx </span><span style="FONT-SIZE: 9pt">文件。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">默认是在</span><span style="FONT-SIZE: 9pt">Bin</span><span style="FONT-SIZE: 9pt">目录下预编译成几个应用程序集，典型的是一个目录对应一个应用程序集。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">fixed-names </span><span style="FONT-SIZE: 9pt">部署选项可以让每一个</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">页面或者每个</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">用户控件创建一个应用程序集，这样每个页面都有一个可部署的应用程序集。但是，</span><span style="FONT-SIZE: 9pt">fixed-names </span><span style="FONT-SIZE: 9pt">部署选项会增多应用程序集的个数，而且实际内存使用也会增大。</span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 90pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 85pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 90pt; BACKGROUND-COLOR: transparent" vAlign=top width=113>
            <div align=left><span style="FONT-SIZE: 9pt">从</span><span style="FONT-SIZE: 9pt">Visual Studio .NET 2003</span><span style="FONT-SIZE: 9pt">升级</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 185pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 90pt; BACKGROUND-COLOR: transparent" vAlign=top width=247>
            <div align=left><span style="FONT-SIZE: 9pt">因为跟</span><span style="FONT-SIZE: 9pt">VS2003</span><span style="FONT-SIZE: 9pt">采用了一样的</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">项目开发模型，升级是非常非常简单的。</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 239pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 90pt; BACKGROUND-COLOR: transparent" vAlign=top width=319>
            <div align=left><span style="FONT-SIZE: 9pt">Web site </span><span style="FONT-SIZE: 9pt">项目的编译选项不同导致了它跟</span><span style="FONT-SIZE: 9pt">Visual Studio .NET 2003WEB</span><span style="FONT-SIZE: 9pt">项目的极大不同。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">虽然微软提供了一个转换向导，但是如果你的项目如果是一个复杂的</span><span style="FONT-SIZE: 9pt">VS2003</span><span style="FONT-SIZE: 9pt">项目，使用这个转换向导后，你还需要对照转换手册，做很多工作。</span></div>
            <div align=left><span style="FONT-SIZE: 9pt">如果你要从</span><span style="FONT-SIZE: 9pt">VS2003</span><span style="FONT-SIZE: 9pt">升级，建议不要用这种</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">站点开发模版。而是使用</span><span style="FONT-SIZE: 9pt">Web application </span><span style="FONT-SIZE: 9pt">项目。</span></div>
            </td>
        </tr>
    </tbody>
</table>
<div>&nbsp;</div>
<div align=left><span style="FONT-SIZE: 9pt">选择何种</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">编程模型</span></div>
<div>&nbsp;</div>
<p>&nbsp;</p>
<table style="MARGIN: auto auto auto 4.65pt; WIDTH: 510pt; BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 width=680 border=0>
    <tbody>
        <tr style="HEIGHT: 14.25pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: silver 0% 50%; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>Option or Task</strong></span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); BACKGROUND: silver 0% 50%; PADDING-BOTTOM: 0cm; WIDTH: 147pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" vAlign=top width=196>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>Web Application Projects</strong></span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); BACKGROUND: silver 0% 50%; PADDING-BOTTOM: 0cm; WIDTH: 115.5pt; PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial" vAlign=top width=154>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>Web Site Projects</strong></span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 22.5pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">你有一个大型的</span><span style="FONT-SIZE: 9pt">Visual Studio .NET 2003 Web</span><span style="FONT-SIZE: 9pt">应用需要迁移到</span><span style="FONT-SIZE: 9pt">VS2005</span><span style="FONT-SIZE: 9pt">。</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 147pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=196>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>&#8730;</strong></span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 115.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=154>
            <div align=left><span style="FONT-SIZE: 9pt">　</span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 33.75pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 33.75pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">喜欢使用</span><span style="FONT-SIZE: 9pt"> single-page code </span><span style="FONT-SIZE: 9pt">模型来开发网站页面。而不是使用</span><span style="FONT-SIZE: 9pt">code-behind </span><span style="FONT-SIZE: 9pt">模型来编写网站页面</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 147pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 33.75pt; BACKGROUND-COLOR: transparent" vAlign=top width=196>
            <div align=left><span style="FONT-SIZE: 9pt">　</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 115.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 33.75pt; BACKGROUND-COLOR: transparent" vAlign=top width=154>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>&#8730;</strong></span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 14.25pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">喜欢采用下面的方式编写网站：</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 147pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=196 rowSpan=3>
            <div align=left><span style="FONT-SIZE: 9pt">　</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 115.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=154 rowSpan=3>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>&#8730;</strong></span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 33.75pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 33.75pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">在编写页面时候，为了可以快速的看到编写效果，动态编译该页面，马上可以看到效果，不用编译整个站点。</span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 22.5pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">（就是说，只需要保存文件，然后在浏览器中刷新一下，就可以看到自己刚刚做的效果）</span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 14.25pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">需要控制编译后应用程序集的名字</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 147pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=196>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>&#8730;</strong></span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 115.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=154>
            <div align=left><span style="FONT-SIZE: 9pt">　</span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 14.25pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">需要每个页面产生一个应用程序集</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 147pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=196>
            <div align=left><span style="FONT-SIZE: 9pt">　</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 115.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=154>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>&#8730;</strong></span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 22.5pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">页面或者</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">用户控件中需要使用到单独的类。</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 147pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=196>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>&#8730;</strong></span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 115.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=154>
            <div align=left><span style="FONT-SIZE: 9pt">　</span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 14.25pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">需要使用多个</span><span style="FONT-SIZE: 9pt">Project</span><span style="FONT-SIZE: 9pt">来构建一个</span><span style="FONT-SIZE: 9pt">Web</span><span style="FONT-SIZE: 9pt">应用。</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 147pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=196>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>&#8730;</strong></span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 115.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 14.25pt; BACKGROUND-COLOR: transparent" vAlign=top width=154>
            <div align=left><span style="FONT-SIZE: 9pt">　</span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 22.5pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">需要处理</span><span style="FONT-SIZE: 9pt">pre-build </span><span style="FONT-SIZE: 9pt">和</span><span style="FONT-SIZE: 9pt"> post-build </span><span style="FONT-SIZE: 9pt">事件（编译前后需要有自己额外的处理）</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 147pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=196>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>&#8730;</strong></span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 115.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=154>
            <div align=left><span style="FONT-SIZE: 9pt">　</span></div>
            </td>
        </tr>
        <tr style="HEIGHT: 22.5pt">
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0cm; BORDER-LEFT: windowtext 1pt solid; WIDTH: 247.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=330>
            <div align=left><span style="FONT-SIZE: 9pt">希望把一个目录当作一个</span><span style="FONT-SIZE: 9pt">WEB</span><span style="FONT-SIZE: 9pt">应用来处理，而不需要新建一个</span><span style="FONT-SIZE: 9pt">Project </span><span style="FONT-SIZE: 9pt">文件。</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 147pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=196>
            <div align=left><span style="FONT-SIZE: 9pt">　</span></div>
            </td>
            <td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; PADDING-LEFT: 5.4pt; BORDER-LEFT-COLOR: rgb(236,233,216); PADDING-BOTTOM: 0cm; WIDTH: 115.5pt; BORDER-TOP-COLOR: rgb(236,233,216); PADDING-TOP: 0cm; BORDER-BOTTOM: windowtext 1pt solid; HEIGHT: 22.5pt; BACKGROUND-COLOR: transparent" vAlign=top width=154>
            <div align=left><span style="FONT-SIZE: 9pt"><strong>&#8730;</strong></span></div>
            </td>
        </tr>
    </tbody>
</table>
&nbsp;<br><br>
<img src ="http://www.cppblog.com/eday/aggbug/36525.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-13 18:48 <a href="http://www.cppblog.com/eday/articles/36525.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>系统管理员如何防范黑客攻击</title><link>http://www.cppblog.com/eday/articles/36516.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 13 Nov 2007 08:19:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/36516.html</guid><description><![CDATA[管理员应首先作到以下几点：<br>　　1.对重要数据和资料完全进行备份，并将备份所用的存储设备单独放置，而不是连在互联网上，这是网站或系统遭到恶意攻击后最好的解救方法。<br>　　2.特别重要的网站要做到24小时有网络管理员值班，并采取技术措施循环检查系统日志，以及动态IP的变化。<br>　　3.无人值守网站时，关闭一切连在互联网上的供工作人员使用的电脑终端设备，因为绝大多数黑客攻击时往往都是从这些防范薄弱的电脑终端侵入，从中找到网站或系统的弱点，进而取得管理员或用户密码，并夺取网站管理的超级权限，借此转攻网站系统内的其他机器。<br>　　4.检查所有用户口令，特别是管理员的超级权限口令，尽量作到使口令中同时含有数字，大小写字母，符号等，因为口令的组合多，解码将是相当困难的，而且口令长度不得小于8位；另外，还要经常去有关的安全站点下载系统补丁程序，尽可能地将系统的漏洞补上。<br><br>一.网站被攻击的几种方式<br>　　想成功抵制住黑客的攻击,我们必须从互联网,报刊杂志和有关的技术资料上了解关于黑客的一些详细情况。一份基于网络安全的报告调查称:在互联网上大约有20%的单位曾被黑客侵入；约40%的单位没有安装防火墙（Firewall）；不少于30%的黑客入侵事件是在未能正确安装防火墙的情况下发生的。一般来说，黑客入侵网站常用这样的几种方式：<br>●Data Diddling-------------未经授权删除档案，更改其资料（15.5%)<br>●Scanner-------------利用工具寻找暗门漏洞(15.8%)<br>●Sniffer--------------监听加密之封包(11.2%)<br>●Denial of Service-------------使其系统瘫痪（16.2%)<br>●IP Spoofing---------------冒充系统内网络的IP地址(12.4%)<br>●Other------------其他(13.9%)<br>　　黑客为什么这么容易进入系统?为什么那些安装了防火墙的系统一样会被黑客入侵呢?最主要的原因有:<br>●系统本身就存在有许多漏洞(暗门)<br>●以往黑客多是单枪匹马,但现在由于互联网的普及,使得黑客之间的联络更加方便,从而往往采取\"结伙抢劫\"的入侵方式.据说美国有一家称作\"大屠杀2600(Genocide 2600)\"的黑客组织,现拥有150多万成员.他们扎根在美国西北部和阿拉斯加地区,并开始向东海岸地区扩展.他们来自各行各业,年龄从14岁到52岁.<br>●Internet上有许多现成的黑客工具软件,例如\"Rootkit\",\"Satan\"等,这些程序成为黑客方便好用的工具;<br>●以错误的方式安装防火墙.<br>二.防范黑客攻击的措施<br>　　1.选用安全的口令<br>　　根据十几个黑客软件的工作原理,参照口令破译的难易程度,以破解需要的时间为排序指标,这里列出了常见的采用危险口令的方式:用户名(帐号)作为口令;用户名(帐号)的变换形式作为口令;使用生日作为口令;常用的英文单词作为口令;5位或5位以下的字符作为口令.<br>　　因此,我们在设置口令时应该遵循以下原则:<br>　　●口令应该包括大小写字母,有控制符更好;<br>　　●口令不要太常规;<br>　　●应保守口令秘密并经常改变口令.最糟糕的口令是具有明显特征的口令,不要循环使用旧的口令;　<br>　　●至少每九十天把所有的口令改变一次,对于那些具有高安全特权的口令更应该经常地改变.<br>　　●应把所有的缺省都从系统中去掉,如果服务器是有某个服务公司建立的，要注意找出类似GUEST,MANAGER,SERVICE等的口令并立即改变这些口令;<br>　　●如果接收到两个错误的口令就应断开系统连接<br>　　●应及时取消调离或停止工作的雇员的帐号以及无用的帐号;<br>　　●在验证过程中,口令不得以明文方式传输;<br>　　●口令不得以明文方式存放在系统中,确保口令以加密的形式写在硬盘上并包含口令的文件是只读的;<br>　　●用户输入的明口令,在内存逗留的时间尽可能缩短,用后及时销毁;<br>　　●一次身份验证只限于当次登录(login),其寿命于会话长度相等;<br>　　●除用户输入口令准备登录外,网络中的其他验证过程对用户是透明的.<br>　　我们之所以如此强调口令设置的重要性,是因为关于网站安全调查的结果表明;超过80%的安全侵犯都是由于人民选用了拙劣的口令而导致的.这样,我们可以推断，80%的入侵可以通过选择好的口令来阻止.<br>　　2.实施存取控制<br>　　存取控制规定何种主体对何种具有何种操作权力.存取控制是内部网络安全理论的重要方面,它包括人员权限,数据标识,权限控制,控制类型,风险分析等内容.3.保证数据的完整性<br>　　完整性是在数据处理过程中,在原来数据和现行数据之间保持完全一致的证明手段.一般常用数字签名和数据加密算法来保证.<br>　　4.确保数据的安全<br>　　通过加密算法对数据处理过程进行加密,并采用数字签名及认证来确保数据的安全.<br>　　5.使用安全的服务器系统<br>　　如今可以选择的服务器系统是很多的:UNIX,WindowsNT,Novell,Intranet等,但是关键服务器最好使用UNIX系统.　　<br>　　6.谨慎开放缺乏安全保障的应用和端口<br>　　7.定期分析系统日志<br>　　这类分析工具在UNIX中随处可见.NT Server的用户现在可以利用Intrusion Detection公司的Kane Secu-<br>　　rity Analyst(KSA)来进行这项工作.欲了解更多的细节可查看地址为http;//www.intmsion.com的网站.<br>　　8.不断完善服务器系统的安全性能<br>　　很多服务器系统都被发现有不少漏洞,服务商会不断在网上发布系统的补丁.为了保证系统的安全性,应随时关注这些信息,及时完善自己的系统.<br>　　9.排除人为因素<br>　　再完善的安全体制,没有足够的安全意识和技术人员经常维护,安全性将大打折扣.<br>　　10.进行动态站点监控<br>　　及时发现网络遭受攻击情况并加以防范,避免对网络造成任何损失.<br>　　11.攻击自己的站点<br>　　测试网络安全的最好方法是自己尝试进攻自己的系统,并且不是做一次,而是定期地做,最好能在入侵者发现安全漏洞之前自己先发现.如果我们从Inernet上下载一个口令攻击程序并利用它,这可能会更有利于我们的口令选择.如果能在入侵者之前自己已经发现不好的或易猜测的口令,这是再好不过的了.<br>　　12.请第三方评估机构或专家来完成网络安全的评估<br>　　这样做的好处是能对自己所的环境有个更加清醒的认识,把未来可能的风险降到最小.<br>　　13.谨慎利用共享软件<br>　　许多程序员为了测试和调试的方便,都在他们看起来无害的软件中藏有后门,秘诀和陷阱,发布软件时却忘了去掉他们.对于共享软件和免费软件,一定要彻底地检测他们.如果不这样做，可能会损失惨重.<br>　　14.做好数据的备份工作<br>　　这是非常关键的一个步骤,有了完整的数据备份,我们在遭到攻击或系统出现故障时才可能迅速恢复我们的系统.<br>　　15.主动防御<br>　　我们也可以使用自己喜欢的搜索引擎来寻找口令攻击软件和黑客攻击软件,并在自己的网络上利用他们来寻找可能包含系统信息的文件.这样我们也许能够发现某些我们还未察觉到的安全风险.<br><br>　　相关软件的站点推荐如下:<br>　　<a href="http://www-genome.wi.mit.edu/www/faqs/wwwsecurity-faq.txt" target=_blank><u><font color=#0066cc>http://www-genome.wi.mit.edu/www/faqs/wwwsecurity-faq.txt</font></u></a><br>　　<a href="http://www.cerf.net/~paulp/cgi-security" target=_blank><u><font color=#0066cc>http://www.cerf.net/~paulp/cgi-security</font></u></a><br>　　<a href="http://theory.lcs.mit.edu/~revest/cryptsecurity.html" target=_blank><u><font color=#0066cc>http://theory.lcs.mit.edu/~revest/cryptsecurity.html</font></u></a><br>　　<a href="ftp://ftp.netcom.com/pub/qwerty" target=_blank><u><font color=#0066cc>ftp://ftp.netcom.com/pub/qwerty</font></u></a><br>　　<a href="http://www.pay.uq.oz.au/~ftp/crypto" target=_blank><u><font color=#0066cc>http://www.pay.uq.oz.au/~ftp/crypto</font></u></a><br>　　<a href="http://www.umr.edu/~cgiwrap" target=_blank><u><font color=#0066cc>http://www.umr.edu/~cgiwrap</font></u></a><br>　　SSL文档:<a href="http://home.netscape.com/info/SSL.html" target=_blank><u><font color=#0066cc>http://home.netscape.com/info/SSL.html</font></u></a><br>　　附加文档:<a href="http://home.mcom.com/newsref/ref/internet-security.html" target=_blank><u><font color=#0066cc>http://home.mcom.com/newsref/ref/internet-security.html</font></u></a><br>　　库下载:<a href="ftp://ftp.psy.uq.oz.au/pub/crypto/ssl" target=_blank><u><font color=#0066cc>ftp://ftp.psy.uq.oz.au/pub/crypto/ssl</font></u></a><br>　　PGP简介:<a href="http://web.mit.edu/network/pgpform.html" target=_blank><u><font color=#0066cc>http://web.mit.edu/network/pgpform.html</font></u></a><br>　　欧洲版本:<a href="ftp://ftp.infomatik.uni-hamburg.de/virus/crpt/pgp/tools" target=_blank><u><font color=#0066cc>ftp://ftp.infomatik.uni-hamburg.de/virus/crpt/pgp/tools</font></u></a><br>　　公共密钥加密:<a href="http://word.std.com/~franl/crypto/crypto.html" target=_blank><u><font color=#0066cc>http://word.std.com/~franl/crypto/crypto.html</font></u></a><br>　　RSA加密专利公司:<a href="http://www.rsa.com.faq/" target=_blank><u><font color=#0066cc>http://www.rsa.com.faq</font></u></a>　<br>　　16.使用防火墙<br>　　防火墙正在成为控制对网络系统访问的非常流行的方法.事实上,在Intrnet上的WEB网站中,超过三分之一的WEB网站都是由某种形式的防火墙加以保护,这是对黑客防范最严,安全性较强的一种方式,任何关键性的服务器,都建议放在防火墙之后.任何对关键服务器的访问都必须通过代理服务器,这虽然降低了服务器的交互能力,但为了安全,这点牺牲是值得的.<br>　　但是,防火墙也存在以下局限性:　<br>●防火墙不能防范不经由防火墙的攻击.如果内部网用户与Internet服务提供商建立直接的SLIP或PPP连接,则绕过防火墙系统所提供的安全保护.<br>●防火墙不能防范认为因素的攻击.<br>●防火墙不能防止受病毒感染的软件或文件的传输.<br>●防火墙不能防止数据驱动式的攻击,当有些表面看来无害的数据邮寄或拷贝到内部网的主机上并执行时,可能会发生数据驱动式的攻击.<br>　　对此,提出以下几点建议:<br>　　⑴对敏感性页面不允许缓存;<br>　　⑵不要打开未知者发来的邮件附件;<br>　　⑶不要使用微软的安全系统;<br>　　⑷不要迷信防火墙.
<img src ="http://www.cppblog.com/eday/aggbug/36516.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-13 16:19 <a href="http://www.cppblog.com/eday/articles/36516.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>搜索原理之中文分词</title><link>http://www.cppblog.com/eday/articles/36214.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Fri, 09 Nov 2007 06:59:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/36214.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp; 信息的飞速增长，使搜索引擎成为人们查找信息的首选工具，Google、百度、中国搜索等大型搜索引擎一直是人们讨论的话题。随着搜索市场价值的不断增加，越来越多的公司开发出自己的搜索引擎，阿里巴巴的商机搜索、8848的购物搜索等也陆续面世，自然，搜索引擎技术也成为技术人员关注的热点。<br>
<p>&nbsp;&nbsp;&nbsp; 搜索引擎技术的研究，国外比中国要早近十年，从最早的Archie，到后来的Excite，以及altvista、overture、google等搜索引擎面世，搜索引擎发展至今，已经有十几年的历史，而国内开始研究搜索引擎是在上世纪末本世纪初。在许多领域，都是国外的产品和技术一统天下，特别是当某种技术在国外研究多年而国内才开始的情况下。例如操作系统、字处理软件、浏览器等等，但搜索引擎却是个例外。虽然在国外搜索引擎技术早就开始研究，但在国内还是陆续涌现出优秀的搜索引擎，像百度（<a href="http://www.baidu.com/"><font color=#800080><u>http://www.baidu.com</u></font></a>）、中搜（<a href="http://www.zhongsou.com/"><u><font color=#0066cc>http://www.zhongsou.com</font></u></a>）等。目前在中文搜索引擎领域，国内的搜索引擎已经和国外的搜索引擎效果上相差不远。之所以能形成这样的局面，有一个重要的原因就在于中文和英文两种语言自身的书写方式不同，这其中对于计算机涉及的技术就是中文分词。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <strong>什么是中文分词</strong></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 众所周知，英文是以词为单位的，词和词之间是靠空格隔开，而中文是以字为单位，句子中所有的字连起来才能描述一个意思。例如，英文句子I am a student，用中文则为：&#8220;我是一个学生&#8221;。计算机可以很简单通过空格知道student是一个单词，但是不能很容易明白&#8220;学&#8221;、&#8220;生&#8221;两个字合起来才表示一个词。把中文的汉字序列切分成有意义的词，就是中文分词，有些人也称为切词。我是一个学生，分词的结果是：我 是 一个 学生。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <strong>中文分词和搜索引擎</strong></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 中文分词到底对搜索引擎有多大影响？对于搜索引擎来说，最重要的并不是找到所有结果，因为在上百亿的网页中找到所有结果没有太多的意义，没有人能看得完，最重要的是把最相关的结果排在最前面，这也称为相关度排序。中文分词的准确与否，常常直接影响到对搜索结果的相关度排序。笔者最近替朋友找一些关于日本和服的资料，在搜索引擎上输入&#8220;和服&#8221;，得到的结果就发现了很多问题。下面就以这个例子来说明分词对搜索结果的影响，在现有三个中文搜索引擎上做测试，测试方法是直接在Google（<a href="http://www.google.com/"><u><font color=#800080>http://www.google.com</font></u></a>）、百度（<a href="http://www.baidu.com/"><font color=#800080><u>http://www.baidu.com</u></font></a>）、中搜（<a href="http://www.zhongsou.com/"><u><font color=#0066cc>http://www.zhongsou.com</font></u></a>）上以&#8220;和服&#8221;为关键词进行搜索：</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <u>在Google上输入&#8220;和服&#8221;搜索所有中文简体网页，总共结果507,000条，前20条结果中有14条与和服一点关系都没有。在第一页就有以下错误：</u></p>
<br>
<p>&nbsp;&nbsp;&nbsp; &#8220;通信信息报：瑞星以技术和服务开拓网络安全市场&#8221;</p>
<br>
<p>&nbsp;&nbsp;&nbsp; &#8220;使用纯HTML的通用数据管理和服务- 开发者- ZDNet ...&#8221;</p>
<br>
<p>&nbsp;&nbsp;&nbsp; &#8220;陈慧琳《心口不一》化妆和服装自己包办&#8221;</p>
<br>
<p>&nbsp;&nbsp;&nbsp; &#8220;::外交部：中国境外领事保护和服务指南(2003年版) ...&#8221;</p>
<br>
<p>&nbsp;&nbsp;&nbsp; &#8220;产品和服务&#8221;</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 等等。第一页只有三篇是真正在讲&#8220;和服&#8221;的结果。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <u>在百度上输入&#8220;和服&#8221;搜索网页，总共结果为287,000条，前20条结果中有6条与和服一点关系都没有。在第一页有以下错误：</u></p>
<br>
<p>&nbsp;&nbsp;&nbsp; &#8220;福建省晋江市恒和服装有限公司系独资企业&#8221;</p>
<br>
<p>&nbsp;&nbsp;&nbsp; &#8220;关于商品和服务实行明码标价的规定&#8221;</p>
<br>
<p>&nbsp;&nbsp;&nbsp; &#8220;青岛东和服装设备&#8221;</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <u>在中搜上输入&#8220;和服&#8221;搜索网页，总共结果为26,917条，前20条结果都是与和服相关的网页。</u></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 这次搜索引擎结果中的错误，就是由于分词的不准确所造成的。通过笔者的了解，Google的中文分词技术采用的是美国一家名叫Basis Technology（<a href="http://www.basistech.com/"><u><font color=#0066cc>http://www.basistech.com</font></u></a>）的公司提供的中文分词技术，百度使用的是自己公司开发的分词技术，中搜使用的是国内海量科技（<font color=#800080>http://www.hylanda.com</font>）提供的分词技术。由此可见，中文分词的准确度，对搜索引擎结果相关性和准确性有相当大的关系。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <strong>中文分词技术</strong></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 中文分词技术属于自然语言处理技术范畴，对于一句话，人可以通过自己的知识来明白哪些是词，哪些不是词，但如何让计算机也能理解？其处理过程就是分词算法。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 现有的分词算法可分为三大类：基于字符串匹配的分词方法、基于理解的分词方法和基于统计的分词方法。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <u>1、基于字符串匹配的分词方法</u></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 这种方法又叫做机械分词方法，它是按照一定的策略将待分析的汉字串与一个&#8220;充分大的&#8221;机器词典中的词条进行配，若在词典中找到某个字符串，则匹配成功（识别出一个词）。按照扫描方向的不同，串匹配分词方法可以分为正向匹配和逆向匹配；按照不同长度优先匹配的情况，可以分为最大（最长）匹配和最小（最短）匹配；按照是否与词性标注过程相结合，又可以分为单纯分词方法和分词与标注相结合的一体化方法。常用的几种机械分词方法如下：</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 1）正向最大匹配法（由左到右的方向）；</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 2）逆向最大匹配法（由右到左的方向）；</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 3）最少切分（使每一句中切出的词数最小）。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 还可以将上述各种方法相互组合，例如，可以将正向最大匹配方法和逆向最大匹配方法结合起来构成双向匹配法。由于汉语单字成词的特点，正向最小匹配和逆向最小匹配一般很少使用。一般说来，逆向匹配的切分精度略高于正向匹配，遇到的歧义现象也较少。统计结果表明，单纯使用正向最大匹配的错误率为1/169，单纯使用逆向最大匹配的错误率为1/245。但这种精度还远远不能满足实际的需要。实际使用的分词系统，都是把机械分词作为一种初分手段，还需通过利用各种其它的语言信息来进一步提高切分的准确率。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 一种方法是改进扫描方式，称为特征扫描或标志切分，优先在待分析字符串中识别和切分出一些带有明显特征的词，以这些词作为断点，可将原字符串分为较小的串再来进机械分词，从而减少匹配的错误率。另一种方法是将分词和词类标注结合起来，利用丰富的词类信息对分词决策提供帮助，并且在标注过程中又反过来对分词结果进行检验、调整，从而极大地提高切分的准确率。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 对于机械分词方法，可以建立一个一般的模型，在这方面有专业的学术论文，这里不做详细论述。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <u>2、基于理解的分词方法</u></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 这种分词方法是通过让计算机模拟人对句子的理解，达到识别词的效果。其基本思想就是在分词的同时进行句法、语义分析，利用句法信息和语义信息来处理歧义现象。它通常包括三个部分：分词子系统、句法语义子系统、总控部分。在总控部分的协调下，分词子系统可以获得有关词、句子等的句法和语义信息来对分词歧义进行判断，即它模拟了人对句子的理解过程。这种分词方法需要使用大量的语言知识和信息。由于汉语语言知识的笼统、复杂性，难以将各种语言信息组织成机器可直接读取的形式，因此目前基于理解的分词系统还处在试验阶段。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <u>3、基于统计的分词方法</u></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 从形式上看，词是稳定的字的组合，因此在上下文中，相邻的字同时出现的次数越多，就越有可能构成一个词。因此字与字相邻共现的频率或概率能够较好的反映成词的可信度。可以对语料中相邻共现的各个字的组合的频度进行统计，计算它们的互现信息。定义两个字的互现信息，计算两个汉字X、Y的相邻共现概率。互现信息体现了汉字之间结合关系的紧密程度。当紧密程度高于某一个阈值时，便可认为此字组可能构成了一个词。这种方法只需对语料中的字组频度进行统计，不需要切分词典，因而又叫做无词典分词法或统计取词方法。但这种方法也有一定的局限性，会经常抽出一些共现频度高、但并不是词的常用字组，例如&#8220;这一&#8221;、&#8220;之一&#8221;、&#8220;有的&#8221;、&#8220;我的&#8221;、&#8220;许多的&#8221;等，并且对常用词的识别精度差，时空开销大。实际应用的统计分词系统都要使用一部基本的分词词典（常用词词典）进行串匹配分词，同时使用统计方法识别一些新的词，即将串频统计和串匹配结合起来，既发挥匹配分词切分速度快、效率高的特点，又利用了无词典分词结合上下文识别生词、自动消除歧义的优点。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 到底哪种分词算法的准确度更高，目前并无定论。对于任何一个成熟的分词系统来说，不可能单独依靠某一种算法来实现，都需要综合不同的算法。笔者了解，海量科技的分词算法就采用&#8220;复方分词法&#8221;，所谓复方，相当于用中药中的复方概念，即用不同的药才综合起来去医治疾病，同样，对于中文词的识别，需要多种算法来处理不同的问题。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <strong>分词中的难题</strong></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 有了成熟的分词算法，是否就能容易的解决中文分词的问题呢？事实远非如此。中文是一种十分复杂的语言，让计算机理解中文语言更是困难。在中文分词过程中，有两大难题一直没有完全突破。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <u>1、歧义识别</u></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 歧义是指同样的一句话，可能有两种或者更多的切分方法。例如：表面的，因为&#8220;表面&#8221;和&#8220;面的&#8221;都是词，那么这个短语就可以分成&#8220;表面 的&#8221;和&#8220;表 面的&#8221;。这种称为交叉歧义。像这种交叉歧义十分常见，前面举的&#8220;和服&#8221;的例子，其实就是因为交叉歧义引起的错误。&#8220;化妆和服装&#8221;可以分成&#8220;化妆 和 服装&#8221;或者&#8220;化妆 和服 装&#8221;。由于没有人的知识去理解，计算机很难知道到底哪个方案正确。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 交叉歧义相对组合歧义来说是还算比较容易处理，组合歧义就必需根据整个句子来判断了。例如，在句子&#8220;这个门把手坏了&#8221;中，&#8220;把手&#8221;是个词，但在句子&#8220;请把手拿开&#8221;中，&#8220;把手&#8221;就不是一个词；在句子&#8220;将军任命了一名中将&#8221;中，&#8220;中将&#8221;是个词，但在句子&#8220;产量三年中将增长两倍&#8221;中，&#8220;中将&#8221;就不再是词。这些词计算机又如何去识别?</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 如果交叉歧义和组合歧义计算机都能解决的话，在歧义中还有一个难题，是真歧义。真歧义意思是给出一句话，由人去判断也不知道哪个应该是词，哪个应该不是词。例如：&#8220;乒乓球拍卖完了&#8221;，可以切分成&#8220;乒乓 球拍 卖 完 了&#8221;、也可切分成&#8220;乒乓球 拍卖 完 了&#8221;，如果没有上下文其他的句子，恐怕谁也不知道&#8220;拍卖&#8221;在这里算不算一个词。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <u>2、新词识别</u></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 新词，专业术语称为未登录词。也就是那些在字典中都没有收录过，但又确实能称为词的那些词。最典型的是人名，人可以很容易理解句子&#8220;王军虎去广州了&#8221;中，&#8220;王军虎&#8221;是个词，因为是一个人的名字，但要是让计算机去识别就困难了。如果把&#8220;王军虎&#8221;做为一个词收录到字典中去，全世界有那么多名字，而且每时每刻都有新增的人名，收录这些人名本身就是一项巨大的工程。即使这项工作可以完成，还是会存在问题，例如：在句子&#8220;王军虎头虎脑的&#8221;中，&#8220;王军虎&#8221;还能不能算词？</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 新词中除了人名以外，还有机构名、地名、产品名、商标名、简称、省略语等都是很难处理的问题，而且这些又正好是人们经常使用的词，因此对于搜索引擎来说，分词系统中的新词识别十分重要。目前新词识别准确率已经成为评价一个分词系统好坏的重要标志之一。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; <strong>中文分词的应用</strong></p>
<br>
<p>&nbsp;&nbsp;&nbsp; 目前在自然语言处理技术中，中文处理技术比西文处理技术要落后很大一段距离，许多西文的处理方法中文不能直接采用，就是因为中文必需有分词这道工序。中文分词是其他中文信息处理的基础，搜索引擎只是中文分词的一个应用。其他的比如机器翻译（MT）、语音合成、自动分类、自动摘要、自动校对等等，都需要用到分词。因为中文需要分词，可能会影响一些研究，但同时也为一些企业带来机会，因为国外的计算机处理技术要想进入中国市场，首先也是要解决中文分词问题。在中文研究方面，相比外国人来说，中国人有十分明显的优势。</p>
<br>
<p>&nbsp;&nbsp;&nbsp; 分词准确性对搜索引擎来说十分重要，但如果分词速度太慢，即使准确性再高，对于搜索引擎来说也是不可用的，因为搜索引擎需要处理数以亿计的网页，如果分词耗用的时间过长，会严重影响搜索引擎内容更新的速度。因此对于搜索引擎来说，分词的准确性和速度，二者都需要达到很高的要求。目前研究中文分词的大多是科研院校，清华、北大、中科院、北京语言学院、东北大学、IBM研究院、微软中国研究院等都有自己的研究队伍，而真正专业研究中文分词的商业公司除了海量科技以外，几乎没有了。科研院校研究的技术，大部分不能很快产品化，而一个专业公司的力量毕竟有限，看来中文分词技术要想更好的服务于更多的产品，还有很长一段路。<br></p>
<img src ="http://www.cppblog.com/eday/aggbug/36214.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-09 14:59 <a href="http://www.cppblog.com/eday/articles/36214.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为什么第一次调用WebService慢呢？</title><link>http://www.cppblog.com/eday/articles/36045.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Wed, 07 Nov 2007 07:35:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/36045.html</guid><description><![CDATA[添加Web引用的时候，WebService在客户端有一个代理，如下：
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp; [System.CodeDom.Compiler.<span style="COLOR: teal">GeneratedCodeAttribute</span>(<span style="COLOR: maroon">"System.Web.Services"</span>, <span style="COLOR: maroon">"2.0.50727.42"</span>)]</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp; [System.Diagnostics.<span style="COLOR: teal">DebuggerStepThroughAttribute</span>()]</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp; [System.ComponentModel.<span style="COLOR: teal">DesignerCategoryAttribute</span>(<span style="COLOR: maroon">"code"</span>)]</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp; [System.Web.Services.<span style="COLOR: teal">WebServiceBindingAttribute</span>(Name=<span style="COLOR: maroon">"WebService1Soap"</span>, Namespace=<span style="COLOR: maroon">"<a href="http://tempuri.org/"><u><font color=#0066cc>http://tempuri.org/</font></u></a>"</span>)</span></div>
<div style="TEXT-INDENT: 21pt"><span style="FONT-SIZE: 9pt">&nbsp; &nbsp;<span style="COLOR: blue">public</span> <span style="COLOR: blue">partial</span> <span style="COLOR: blue">class</span> <span style="COLOR: teal">WebService1</span> : System.Web.Services.Protocols.<span style="COLOR: teal">SoapHttpClientProtocol</span></span></div>
<div style="MARGIN-LEFT: 18pt">&nbsp;</div>
<div style="MARGIN-LEFT: 18pt">客户端调用WebServivce就是通过这个代理类来调用的。</div>
<div style="MARGIN-LEFT: 18pt">&nbsp;</div>
<div style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt"><span>2.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>调用WebService方法，客户端和服务器端通信是Xml，所以代理类跟Xml之间就有序列化和反序列化的过程</div>
<div style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt"><span>3.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>客户端调用WebService的过程如下</div>
<div style="MARGIN-LEFT: 42pt; TEXT-INDENT: -21pt"><span>a)<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>客户端调用代理类Hello world方法</div>
<div style="MARGIN-LEFT: 42pt"><span style="FONT-SIZE: 9pt; COLOR: blue">string</span><span style="FONT-SIZE: 9pt"> str = (<span style="COLOR: blue">new</span> Service2.<span style="COLOR: teal">WebService1</span>()).HelloWorld ();</span></div>
<div style="MARGIN-LEFT: 42pt; TEXT-INDENT: -21pt"><span>b)<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>代理类调用基类SoapHttpClientProtocal的Invoke方法</div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [System.Web.Services.Protocols.<span style="COLOR: teal">SoapDocumentMethodAttribute</span>(<span style="COLOR: maroon">"<a href="http://tempuri.org/HelloWorld0766"><u><font color=#0066cc>http://tempuri.org/HelloWorld0766</font></u></a>"</span>, RequestNamespace=<span style="COLOR: maroon">"<a href="http://tempuri.org/"><u><font color=#0066cc>http://tempuri.org/</font></u></a>"</span>, ResponseNamespace=<span style="COLOR: maroon">"<a href="http://tempuri.org/"><u><font color=#0066cc>http://tempuri.org/</font></u></a>"</span>, Use=System.Web.Services.Description.<span style="COLOR: teal">SoapBindingUse</span>.Literal, ParameterStyle=System.Web.Services.Protocols.<span style="COLOR: teal">SoapParameterStyle</span>.Wrapped)]</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">public</span> <span style="COLOR: blue">string</span> HelloWorld() {</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">object</span>[] results = <span style="COLOR: blue">this</span>.Invoke(<span style="COLOR: maroon">"HelloWorld"</span>, <span style="COLOR: blue">new</span> <span style="COLOR: blue">object</span>[0]);</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">return</span> ((<span style="COLOR: blue">string</span>)(results[0]));</span></div>
<div style="MARGIN-LEFT: 18pt"><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="MARGIN-LEFT: 42pt; TEXT-INDENT: -21pt"><span>c)<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>SoapHttpClientProtocal进行Soap序列化Soap头和方法，都是这个类自己做的，但是输入参数和返回值，是利用的XmlSerializer，输入参数要序列化，返回值要反序列化。</div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">protected</span> <span style="COLOR: blue">object</span>[] Invoke(<span style="COLOR: blue">string</span> methodName, <span style="COLOR: blue">object</span>[] parameters)</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;<span style="COLOR: teal">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</span></span><span style="FONT-SIZE: 9pt; COLOR: teal">&#8230;</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">try</span></span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; message1.SetStream(stream1);</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: blue">this</span>.Serialize(message1);//</span><span style="FONT-SIZE: 9pt; COLOR: red">注1</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt; COLOR: blue">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</span><span style="FONT-SIZE: 9pt; COLOR: blue">&#8230;</span></div>
<div style="MARGIN-LEFT: 18pt; TEXT-INDENT: 3pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; response1 = <span style="COLOR: blue">this</span>.GetWebResponse(request1);</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: teal">Stream</span> stream2 = <span style="COLOR: blue">null</span>;</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">try</span></span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stream2 = response1.GetResponseStream();</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; objArray1 = <span style="COLOR: blue">this</span>.ReadResponse(message1, response1, stream2, <span style="COLOR: blue">false</span>);//</span><span style="FONT-SIZE: 9pt; COLOR: red">注2</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="FONT-SIZE: 9pt">注1：this.Serialize中有一句参数序列化的代码如下</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; method1.parameterSerializer.Serialize(writer1, message.GetParameterValues(), <span style="COLOR: blue">null</span>, flag1 ? text2 : <span style="COLOR: blue">null</span>);</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="FONT-SIZE: 9pt">注2：this.ReadResponse中有一句返回值的反序列化的代码如下</span></div>
<div style="MARGIN-LEFT: 18pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; message.SetParameterValues((<span style="COLOR: blue">object</span>[]) method1.returnSerializer.Deserialize(reader1, flag1 ? text1 : <span style="COLOR: blue">null</span>));</span></div>
<div style="MARGIN-LEFT: 42pt; TEXT-INDENT: -21pt"><span>d)<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>XmlSerializer会缓存临时程序集，这个程序集作用是序列化和反序列化，如果缓存中没有会调用TempAssembly产生一个</div>
<div style="MARGIN-LEFT: 42pt">&nbsp;</div>
<div style="MARGIN-LEFT: 42pt"><span style="FONT-SIZE: 9pt; COLOR: red">Static</span><span style="FONT-SIZE: 9pt; COLOR: red">的缓存（就是我们每次调用慢的罪魁祸首）：</span><span style="FONT-SIZE: 9pt; COLOR: blue">private</span><span style="FONT-SIZE: 9pt"> <span style="COLOR: blue">static</span> <span style="COLOR: teal">TempAssemblyCache</span> cache;</span></div>
<div style="MARGIN-LEFT: 42pt"><span style="FONT-SIZE: 9pt">获取缓存中的程序集：<span style="COLOR: blue">this</span>.tempAssembly = <span style="COLOR: teal">XmlSerializer.cache[defaultNamespace, type];</span></span></div>
<div style="MARGIN-LEFT: 42pt"><span style="FONT-SIZE: 9pt">缓存中没有就去加载：</span><span style="FONT-SIZE: 9pt; COLOR: teal">Assembly</span><span style="FONT-SIZE: 9pt"> assembly1 = <span style="COLOR: teal">TempAssembly</span>.LoadGeneratedAssembly(type, defaultNamespace, <span style="COLOR: blue">out</span> implementation1);</span></div>
<div style="MARGIN-LEFT: 42pt"><span style="FONT-SIZE: 9pt; COLOR: red">加载没有就去产生（会生成临时文件并编译，很慢）：</span></div>
<div style="MARGIN-LEFT: 42pt"><span style="FONT-SIZE: 9pt; COLOR: blue">this</span><span style="FONT-SIZE: 9pt">.tempAssembly = <span style="COLOR: blue">new</span> <span style="COLOR: teal">TempAssembly</span>(<span style="COLOR: blue">new</span> <span style="COLOR: teal">XmlMapping</span>[] { <span style="COLOR: blue">this</span>.mapping }, assembly1, implementation1);</span></div>
<div style="MARGIN-LEFT: 42pt">&nbsp;</div>
<div style="MARGIN-LEFT: 42pt; TEXT-INDENT: -21pt"><span>e)<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>TempAssemlby这个类负责加载以及产生临时程序集</div>
<div style="MARGIN-LEFT: 42pt"><span style="FONT-SIZE: 9pt">在</span><span style="FONT-SIZE: 9pt">LoadGeneratedAssemlby</span><span style="FONT-SIZE: 9pt">方法中，有一段逻辑，就是默认去加载序列化类，这个类的命名是规则如下</span></div>
<div align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">internal</span> <span style="COLOR: blue">static</span> <span style="COLOR: blue">string</span> GetTempAssemblyName(<span style="COLOR: teal">AssemblyName</span> parent, <span style="COLOR: blue">string</span> ns)</span></div>
<div align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">return</span> (parent.Name + <span style="COLOR: maroon">".XmlSerializers"</span> + (((ns == <span style="COLOR: blue">null</span>) || (ns.Length == 0)) ? <span style="COLOR: maroon">""</span> : (<span style="COLOR: maroon">"."</span> + ns.GetHashCode())));</span></div>
<div align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;}</span></div>
<div align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="FONT-SIZE: 9pt">同时，如果加载失败会触发</span><span style="FONT-SIZE: 9pt; COLOR: teal">AppDomain</span><span style="FONT-SIZE: 9pt">.CurrentDomain.AssemblyResolve</span><span style="FONT-SIZE: 9pt">事件</span></div>
<div align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></div>
<div style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt"><span>4.<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span>结论</div>
<div style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 9pt">1）<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 9pt">WebService</span><span style="FONT-SIZE: 9pt">的序列化是调用</span><span style="FONT-SIZE: 9pt">XmlSerializer</span></div>
<div style="MARGIN-LEFT: 36pt">&nbsp;</div>
<div style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 9pt">2）<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 9pt">WebService</span><span style="FONT-SIZE: 9pt">慢，是因为产生序列化类慢，所谓的临时文件都是</span><span style="FONT-SIZE: 9pt">XmlSerializer</span><span style="FONT-SIZE: 9pt">的中间代码。可以在config文件中加入如下的配置，临时序列化的文件就不会被删除了，WinForm程序是*.exe.config，asp.net是web.config。</span></div>
<div style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 9pt"></span></div>
<div style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;configuration&gt;<br>&nbsp; &lt;system.diagnostics&gt;<br>&nbsp;&nbsp;&nbsp; &lt;switches&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;add name="XmlSerialization.Compilation" value="4"/&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/switches&gt;<br>&nbsp; &lt;/system.diagnostics&gt;<br>&lt;/configuration&gt;</span></div>
<div style="MARGIN-LEFT: 36pt">&nbsp;</div>
<div style="MARGIN-LEFT: 36pt">临时文件在C:\Documents and Settings\<font color=#0000ff>抹布</font>\Local Settings\Temp下，注意，因为名称是随机的，序列化的dll文件，并不能重用，重开进程会重新生成。</div>
<div style="MARGIN-LEFT: 36pt"></div>
<div style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 9pt">3）<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 9pt">如果自定义序列化类，可以跳过产生临时序列化的步骤，大大提高第一次加载的速度，也就是说，只要有一个</span></div>
<div style="MARGIN-LEFT: 36pt"><span style="FONT-SIZE: 9pt; COLOR: red">程序集名称</span><span style="FONT-SIZE: 9pt; COLOR: red">+</span><span style="FONT-SIZE: 9pt; COLOR: red">&#8220;</span><span style="FONT-SIZE: 9pt; COLOR: red">.XmlSerializers</span><span style="FONT-SIZE: 9pt; COLOR: red">&#8221;的序列化类存在，就不会动态生成序列化程序集了。</span></div>
<div style="MARGIN-LEFT: 36pt">&nbsp;</div>
<div style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 9pt">4）<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 9pt">在代理类上可以加</span></div>
<div style="MARGIN-LEFT: 36pt"><span style="FONT-SIZE: 9pt">[System.Xml.Serialization.<span style="COLOR: teal">XmlSerializerAssemblyAttribute</span>(AssemblyName = <span style="COLOR: maroon">"TestPerformance.XmlSerializers"</span>)]</span></div>
<div style="MARGIN-LEFT: 36pt"><span style="FONT-SIZE: 9pt">指定Xml序列化的类，这个序列化的类可以通过一个工具产生，</span></div>
<div style="MARGIN-LEFT: 36pt"><span style="FONT-SIZE: 9pt">但是根据研究TempAssemlby的LoadGeneratedAssemlby代码发现，<span style="COLOR: red">这个Attribute可以不加的</span>，只要你有一个GetTempAssemblyName返回值一样的名称的序列化类即可。</span></div>
<div style="MARGIN-LEFT: 36pt">&nbsp;</div>
<div style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 9pt">5）<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 9pt">根据加载失败会触发</span><span style="FONT-SIZE: 9pt; COLOR: teal">AppDomain</span><span style="FONT-SIZE: 9pt">.CurrentDomain.AssemblyResolve</span><span style="FONT-SIZE: 9pt">事件，可以在加载失败后动态产生序列化类，如下。</span></div>
<div style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 9pt"></span></div>
<div style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://support.microsoft.com/kb/872800/zh-cn"><u><font color=#0066cc>http://support.microsoft.com/kb/872800/zh-cn</font></u></a>，请参考这个kb</span></div>
<div style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span style="FONT-SIZE: 9pt"></span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;<span style="COLOR: blue">private</span> <span style="COLOR: blue">void</span> Form1_Load(<span style="COLOR: blue">object</span> sender, <span style="COLOR: teal">EventArgs</span> e)</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: teal">AppDomain</span>.CurrentDomain.AssemblyResolve +=</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">new</span> <span style="COLOR: teal">ResolveEventHandler</span>(MyResolveEventHandler);</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="MARGIN-LEFT: 36pt" align=left>&nbsp;</div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">static</span> <span style="COLOR: teal">Assembly</span> MyResolveEventHandler(<span style="COLOR: blue">object</span> sender, <span style="COLOR: teal">ResolveEventArgs</span> args)</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: teal">Assembly</span> a = <span style="COLOR: blue">null</span>;</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">string</span>[] arr = args.Name.Split(<span style="COLOR: blue">new</span> <span style="COLOR: blue">string</span>[] { <span style="COLOR: maroon">"."</span> }, <span style="COLOR: teal">StringSplitOptions</span>.None);</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">if</span> (args.Name.IndexOf(<span style="COLOR: maroon">"XmlSerializers"</span>) &gt;= 0)</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">if</span> (!System.IO.<span style="COLOR: teal">File</span>.Exists(args.Name + <span style="COLOR: maroon">".dll"</span>))</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PreGenNS.<span style="COLOR: teal">Pregen</span>.Generate(<span style="COLOR: blue">new</span> <span style="COLOR: blue">string</span>[] { arr[0] });</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">string</span> sSerializersDLL = args.Name + <span style="COLOR: maroon">".dll"</span>;</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">string</span> smartDeploymentHostLocation = <span style="COLOR: maroon">""</span>;</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a = <span style="COLOR: teal">Assembly</span>.LoadFrom(smartDeploymentHostLocation + sSerializersDLL);</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="MARGIN-LEFT: 36pt" align=left><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="COLOR: blue">return</span> a;</span></div>
<div style="MARGIN-LEFT: 36pt"><span style="FONT-SIZE: 9pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></div>
<div style="MARGIN-LEFT: 36pt"><span style="FONT-SIZE: 9pt"><span style="FONT-SIZE: 9pt">6）VS2005利用Release编译，会产生AssemblyName+"XmlSerializer.dll"的序列化文件，可以随着客户端一起部署，跟5这种方式不太一样，可以根据实际情况来选择。</span></span></div>
<div style="MARGIN-LEFT: 36pt"><span style="FONT-SIZE: 9pt"><span style="FONT-SIZE: 9pt"></span></span></div>
<div style="MARGIN-LEFT: 36pt"><span style="FONT-SIZE: 9pt"><span style="FONT-SIZE: 9pt">利用5这种方式，是第一次调用WebService时，动态生成序列化类；而6是在软件发布时，生成这个类，并部署到客户端。</span></span></div>
<img src ="http://www.cppblog.com/eday/aggbug/36045.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-07 15:35 <a href="http://www.cppblog.com/eday/articles/36045.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Google的API介绍</title><link>http://www.cppblog.com/eday/articles/35979.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 06 Nov 2007 11:23:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/35979.html</guid><description><![CDATA[<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">以下是</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">现有的</span><span style="FONT-SIZE: 9pt">API</span><span style="FONT-SIZE: 9pt">：</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/accounts/Authentication.html"><font face="Times New Roman" color=#0066cc size=3><u>Google Account Authentication</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google Account</span><span style="FONT-SIZE: 9pt">提供了两类验证帐号的</span><span style="FONT-SIZE: 9pt">API</span><span style="FONT-SIZE: 9pt">，</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/accounts/AuthForInstalledApps.html"><u><font color=#0066cc>ClientLogin API</font></u></a></span><span style="FONT-SIZE: 9pt">用于帮助桌面程序或手机应用程序完成验证，不过这种验证实际上是通过</span><span style="FONT-SIZE: 9pt">http form</span><span style="FONT-SIZE: 9pt">的方式来完成的。另一种</span><span style="FONT-SIZE: 9pt">API</span><span style="FONT-SIZE: 9pt">虽然仍旧是利用</span><span style="FONT-SIZE: 9pt">http</span><span style="FONT-SIZE: 9pt">方式，但</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/accounts/AuthForWebApps.html"><span style="COLOR: purple"><u>AuthSub API</u></span></a></span><span style="FONT-SIZE: 9pt">出于帮助</span><span style="FONT-SIZE: 9pt">Web</span><span style="FONT-SIZE: 9pt">用户完成登录验证的考虑，提供了一种近似于二传手的功能。登录信息填写和验证都在</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">服务器上完成，用户对是否在当前网站使用</span><span style="FONT-SIZE: 9pt">Google Account</span><span style="FONT-SIZE: 9pt">的信息进行授权。（显然，使用这类</span><span style="FONT-SIZE: 9pt">API</span><span style="FONT-SIZE: 9pt">，你使用的编程语言并没有限制）</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/adsense/"><font face="Times New Roman" color=#0066cc size=3><u>AdSense API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">AdSense API </span><span style="FONT-SIZE: 9pt">允许你将</span><span style="FONT-SIZE: 9pt">AdSense</span><span style="FONT-SIZE: 9pt">的登录功能和管理功能集成到你的</span><span style="FONT-SIZE: 9pt">blog</span><span style="FONT-SIZE: 9pt">或者主页中（当然，也可以被动的由网站管理员添加到你的</span><span style="FONT-SIZE: 9pt">blog</span><span style="FONT-SIZE: 9pt">上）。这套</span><span style="FONT-SIZE: 9pt">API</span><span style="FONT-SIZE: 9pt">提供了五种语言的实现：</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/adsense/developer/adsense_api_samples.html#java_section"><u><font color=#0066cc>Java</font></u></a>, <a href="http://code.google.com/apis/adsense/developer/adsense_api_samples.html#perl_section"><u><font color=#0066cc>Perl</font></u></a>, <a href="http://code.google.com/apis/adsense/developer/adsense_api_samples.html#python_section"><u><font color=#0066cc>Python</font></u></a>, <a href="http://code.google.com/apis/adsense/developer/adsense_api_samples.html#php_section"><u><font color=#0066cc>PHP</font></u></a> </span><span style="FONT-SIZE: 9pt">和</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/adsense/developer/adsense_api_samples.html#cs_section"><u><font color=#0066cc>.NET</font></u></a>. </span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://www.google.com/apis/adwords/"><font face="Times New Roman" color=#0066cc size=3><u>AdWords API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">AdWords API</span><span style="FONT-SIZE: 9pt">为广大投放广告的公司和第三方广告商提供了使用自己的程序管理</span><span style="FONT-SIZE: 9pt">AdWords</span><span style="FONT-SIZE: 9pt">的方式（对于需要维护成百上千个</span><span style="FONT-SIZE: 9pt">AdWords</span><span style="FONT-SIZE: 9pt">的机构来说，这难道不是福音么？）。</span><span style="FONT-SIZE: 9pt">AdWords API</span><span style="FONT-SIZE: 9pt">仅提供</span><span style="FONT-SIZE: 9pt"><a href="http://google-apility.sourceforge.net/"><u><font color=#0066cc>PHP</font></u></a>&nbsp;</span><span style="FONT-SIZE: 9pt">和</span><span style="FONT-SIZE: 9pt"> <a href="http://goog-ad-api-cli.sourceforge.net/"><u><font color=#0066cc>Java</font></u></a></span><span style="FONT-SIZE: 9pt">两种语言版本。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/ajaxsearch/"><font face="Times New Roman" color=#0066cc size=3><u>Google AJAX Search API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">AJAX</span><span style="FONT-SIZE: 9pt">搜索</span><span style="FONT-SIZE: 9pt">API </span><span style="FONT-SIZE: 9pt">为你提供了一种更好的将</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">搜索加入你的网页中的方式，使</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">搜索看起来跟你的站内搜索一样。（显然，开发者了解</span><span style="FONT-SIZE: 9pt">Javascript</span><span style="FONT-SIZE: 9pt">就好了）</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/base/"><font face="Times New Roman" color=#0066cc size=3><u>Google Base Data API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google Base data API</span><span style="FONT-SIZE: 9pt">允许用户通过编程手段完成对</span><span style="FONT-SIZE: 9pt">Google Base</span><span style="FONT-SIZE: 9pt">中数据的增删改查。（现在已经是</span><span style="FONT-SIZE: 9pt">Google Data APIs</span><span style="FONT-SIZE: 9pt">的子项目了）</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/gdata/blogger.html"><font face="Times New Roman" color=#0066cc size=3><u>Blogger Data API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Blogger data API</span><span style="FONT-SIZE: 9pt">允许你通过编程，对你</span><span style="FONT-SIZE: 9pt">blog</span><span style="FONT-SIZE: 9pt">的内容进行完全控制。</span><span style="FONT-SIZE: 9pt">（</span><span style="FONT-SIZE: 9pt">Google Data APIs</span><span style="FONT-SIZE: 9pt">的子项目）</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/gdata/calendar.html"><font face="Times New Roman" color=#0066cc size=3><u>Google Calendar Data API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google Calendar API</span><span style="FONT-SIZE: 9pt">提供了编程完全控制你的</span><span style="FONT-SIZE: 9pt">Calendar</span><span style="FONT-SIZE: 9pt">的方式。（</span><span style="FONT-SIZE: 9pt">Google Data APIs</span><span style="FONT-SIZE: 9pt">的子项目）</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/gdata/index.html"><font face="Times New Roman" color=#0066cc size=3><u>Google Data APIs</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google data APIs</span><span style="FONT-SIZE: 9pt">提供</span><span style="FONT-SIZE: 9pt">Java</span><span style="FONT-SIZE: 9pt">和</span><span style="FONT-SIZE: 9pt">C#</span><span style="FONT-SIZE: 9pt">两种编程语言接口，允许程序直接访问</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">的服务，整个过程基于</span><span style="FONT-SIZE: 9pt">Google Data APIs Protocol</span><span style="FONT-SIZE: 9pt">。使用本套</span><span style="FONT-SIZE: 9pt">API</span><span style="FONT-SIZE: 9pt">的相关项目包括：</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/gdata/blogger.html"><u><font color=#0066cc>Blogger</font></u></a>, <a href="http://code.google.com/apis/base"><u><font color=#0066cc>Google Base</font></u></a> and <a href="http://code.google.com/apis/gdata/calendar.html"><u><font color=#0066cc>Google Calendar</font></u></a> </span><span style="FONT-SIZE: 9pt">。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://desktop.google.com/developer.html"><font face="Times New Roman" color=#0066cc size=3><u>Google Desktop SDK</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google Desktop SDK</span><span style="FONT-SIZE: 9pt">为开发者将</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">桌面集成到自己的应用程序中提供了方便。</span><span style="FONT-SIZE: 9pt"> Google</span><span style="FONT-SIZE: 9pt">为大家提供了基于</span><span style="FONT-SIZE: 9pt"><a href="http://www.python.org/"><u><font color=#0066cc>Python</font></u></a></span><span style="FONT-SIZE: 9pt">的</span><span style="FONT-SIZE: 9pt"> <a href="http://sourceforge.net/projects/goog-kongulo/"><span><span><u><font color=#0066cc>例子</font></u></span></span></a></span><span style="FONT-SIZE: 9pt">。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://earth.google.com/kml/"><font face="Times New Roman" color=#0066cc size=3><u>Google Earth KML</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">KML</span><span style="FONT-SIZE: 9pt">全称是</span><span style="FONT-SIZE: 9pt">Keyhole Markup Language</span><span style="FONT-SIZE: 9pt">，是一个基于</span><span style="FONT-SIZE: 9pt">XML</span><span style="FONT-SIZE: 9pt">语法和文件格式的文件，用来描述和保存地理信息如点、线、图片、折线，并在</span><span style="FONT-SIZE: 9pt">Google Earth</span><span style="FONT-SIZE: 9pt">客户端之中显示。通常开发人员利用</span><span style="FONT-SIZE: 9pt">KML</span><span style="FONT-SIZE: 9pt">在</span><span style="FONT-SIZE: 9pt">Google Earth</span><span style="FONT-SIZE: 9pt">上添加自己所需要的东西（</span><span style="FONT-SIZE: 9pt"><a href="http://earth.google.com/kml/"><span><u><font color=#0066cc>教程和文档</font></u></span></a></span><span style="FONT-SIZE: 9pt">和</span><span style="FONT-SIZE: 9pt"><a href="http://bbs.keyhole.com/"><u><font color=#0066cc>Keyhole<span>论坛</span></font></u></a></span><span style="FONT-SIZE: 9pt">）。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://www.google.com/apis/homepage"><font face="Times New Roman" color=#0066cc size=3><u>Google Gadgets API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google Gadgets API</span><span style="FONT-SIZE: 9pt">用于为</span><span style="FONT-SIZE: 9pt">Google <a href="http://www.google.com/ig"><span style="COLOR: purple"><u>个性化主页</u></span></a></span><span style="FONT-SIZE: 9pt">添加新的模块，管理你的</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">桌面和</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">个人主页。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://gmail.google.com/support/bin/answer.py?answer=13465"><font face="Times New Roman" color=#0066cc size=3><u>Gmail Atom Feeds</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Gmail</span><span style="FONT-SIZE: 9pt">为方便用户读取收件箱和访问相关内容，提供了</span><span style="FONT-SIZE: 9pt">Atom</span><span style="FONT-SIZE: 9pt">格式的种子。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/checkout"><font face="Times New Roman" color=#0066cc size=3><u>Google Checkout API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">使用</span><span style="FONT-SIZE: 9pt">Google Checkout API</span><span style="FONT-SIZE: 9pt">，你可以很容易地将电子商务中的支付服务</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/checkout/developer/index.html#technical_introduction"><span><u><font color=#0066cc>集成到</font></u></span></a></span><span style="FONT-SIZE: 9pt">你的网站中，帮助买家管理</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/checkout/developer/index.html#order_processing_api"><span><u><font color=#0066cc>订单状态</font></u></span></a></span><span style="FONT-SIZE: 9pt">以及自己的信用卡信息。</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">为大家提供了</span><span style="FONT-SIZE: 9pt">Java</span><span style="FONT-SIZE: 9pt">、</span><span style="FONT-SIZE: 9pt">PHP</span><span style="FONT-SIZE: 9pt">和</span><span style="FONT-SIZE: 9pt">ASP</span><span style="FONT-SIZE: 9pt">三种版本的</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/checkout/samplecode.html"><span><u><font color=#0066cc>客户端实现</font></u></span></a></span><span style="FONT-SIZE: 9pt">。</span></font></font></div>
<div align=left><span style="FONT-SIZE: 9pt"><font face="Times New Roman" size=3>&nbsp;</font></span></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/webtoolkit/"><font face="Times New Roman" color=#0066cc size=3><u>Google Web Toolkit</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google Web Toolkit (GWT)</span><span style="FONT-SIZE: 9pt">是一种</span><span style="FONT-SIZE: 9pt">Java</span><span style="FONT-SIZE: 9pt">开发框架，帮助你更快的开发</span><span style="FONT-SIZE: 9pt">Ajax</span><span style="FONT-SIZE: 9pt">应用。当你的应用发布时，</span><span style="FONT-SIZE: 9pt">GWT</span><span style="FONT-SIZE: 9pt">将会把你的</span><span style="FONT-SIZE: 9pt">Java</span><span style="FONT-SIZE: 9pt">代码转译成跨浏览器的</span><span style="FONT-SIZE: 9pt">JavaScript</span><span style="FONT-SIZE: 9pt">和</span><span style="FONT-SIZE: 9pt">HTML</span><span style="FONT-SIZE: 9pt">。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://groups.google.com/support/bin/answer.py?answer=12388"><font face="Times New Roman" color=#0066cc size=3><u>Google Groups Feeds</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">针对</span><span style="FONT-SIZE: 9pt">Google Groups</span><span style="FONT-SIZE: 9pt">的</span><span style="FONT-SIZE: 9pt">Atom</span><span style="FONT-SIZE: 9pt">种子，使用方式</span><span style="FONT-SIZE: 9pt"><a href="http://nick.typepad.com/blog/2004/05/google_groups_2.html"><span><u><font color=#0066cc>如下</font></u></span></a></span><span style="FONT-SIZE: 9pt">！</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://www.google.com/apis/maps/"><font face="Times New Roman" color=#800080 size=3><u>Google Maps API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">为你将</span><span style="FONT-SIZE: 9pt">Google Maps</span><span style="FONT-SIZE: 9pt">集成到你的应用中提供了方式。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://news.google.com/intl/en_us/news_feed_terms.html"><font face="Times New Roman" color=#0066cc size=3><u>Google News Feeds</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">提供的新闻聚合功能，提供</span><span style="FONT-SIZE: 9pt">RSS</span><span style="FONT-SIZE: 9pt">和</span><span style="FONT-SIZE: 9pt">Atom</span><span style="FONT-SIZE: 9pt">两种形式的种子。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://www.google.com/relatedlinks/"><font face="Times New Roman" color=#0066cc size=3><u>Google Related Links</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google Related Links</span><span style="FONT-SIZE: 9pt">提供了</span><span style="FONT-SIZE: 9pt">Javascript</span><span style="FONT-SIZE: 9pt">的调用方式，帮助你为自己的网站生成相关内容的链接。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://www.google.com/enterprise/gsa/"><font face="Times New Roman" color=#0066cc size=3><u>Google Search Appliance APIs</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">属于</span><span style="FONT-SIZE: 9pt">Google Enterprise</span><span style="FONT-SIZE: 9pt">的一套</span><span style="FONT-SIZE: 9pt">API</span><span style="FONT-SIZE: 9pt">，包括</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/enterprise/documentation/xml_reference.html"><span><u><font color=#0066cc>搜索协议</font></u></span></a></span><span style="FONT-SIZE: 9pt">、</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/enterprise/documentation/feedsguide.html"><u><font color=#0066cc>Feeds<span>协议</span></font></u></a></span><span style="FONT-SIZE: 9pt">和</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/enterprise/documentation/authn_authz_spi.html"><span><u><font color=#0066cc>安全服务接口</font></u></span></a></span><span style="FONT-SIZE: 9pt">。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://www.google.com/support/bin/answer.py?answer=38344"><font face="Times New Roman" color=#0066cc size=3><u>Google Search History Feeds</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">以</span><span style="FONT-SIZE: 9pt">RSS</span><span style="FONT-SIZE: 9pt">种子的形式提供用户最近搜索的相关记录。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://www.google.com/webmasters/sitemaps/docs/en/about.html"><font face="Times New Roman" color=#0066cc size=3><u>Google Sitemaps</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google Sitemaps</span><span style="FONT-SIZE: 9pt">是针对网站主，用于提高网站被收录状况的服务。</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">提供了一个</span><span style="FONT-SIZE: 9pt"><a href="http://goog-sitemapgen.sourceforge.net/"><span><u><font color=#0066cc>开源项目</font></u></span></a></span><span style="FONT-SIZE: 9pt">来帮助用户创建</span><span style="FONT-SIZE: 9pt">sitemaps</span><span style="FONT-SIZE: 9pt">文件，同时还提供一些其它的</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/sm_thirdparty.html"><u><font color=#800080><span>第三方</span>Sitemap<span>工具</span></font></u></a></span><span style="FONT-SIZE: 9pt">。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://www.google.com/talk/developer.html"><font face="Times New Roman" color=#0066cc size=3><u>Google Talk XMPP</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google Talk</span><span style="FONT-SIZE: 9pt">使用</span><span style="FONT-SIZE: 9pt"><a href="http://www.xmpp.org/"><u><font color=#0066cc>XMPP</font></u></a></span><span style="FONT-SIZE: 9pt">作为通信协议（</span><span style="FONT-SIZE: 9pt"><a href="http://www.google.com/talk/developer.html"><span><u><font color=#0066cc>相关文档</font></u></span></a></span><span style="FONT-SIZE: 9pt">），因此开发者可以基于</span><span style="FONT-SIZE: 9pt">XMPP</span><span style="FONT-SIZE: 9pt">协议开发关于</span><span style="FONT-SIZE: 9pt">Google Talk</span><span style="FONT-SIZE: 9pt">的相关应用。要了解更多细节，请查看</span><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/talk/about.html"><u><font color=#0066cc>Libjingle<span>开发指南</span></font></u></a></span><span style="FONT-SIZE: 9pt">。已有的开发语言示例包括</span><span style="FONT-SIZE: 9pt"><a href="http://xmpppy.sourceforge.net/"><u><font color=#0066cc>python</font></u></a>, <a href="http://cjphp.netflint.net/"><u><font color=#0066cc>PHP</font></u></a>, <a href="http://www.jivesoftware.org/smack/"><u><font color=#0066cc>Java</font></u></a> and <a href="http://www.cursive.net/jabber-net/"><u><font color=#0066cc>c#</font></u></a></span><span style="FONT-SIZE: 9pt">。</span><span style="FONT-SIZE: 9pt"><a href="http://www.jabber.org/"><u><font color=#0066cc>Jabber<span>软件组织</span></font></u></a></span><span style="FONT-SIZE: 9pt">还提供了大量可用的</span><span style="FONT-SIZE: 9pt"><a href="http://www.jabber.org/software/libraries.shtml"><span><u><font color=#0066cc>库文件</font></u></span></a></span><span style="FONT-SIZE: 9pt">。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://www.google.com/tools/toolbar/buttons/apis/"><font face="Times New Roman" color=#0066cc size=3><u>Google Toolbar API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google Toolbar API</span><span style="FONT-SIZE: 9pt">允许你创建自己所喜欢的按钮，控制</span><span style="FONT-SIZE: 9pt">Google Toolbar</span><span style="FONT-SIZE: 9pt">的展现形式。</span></font></font></div>
<div align=left><font face="Times New Roman" size=3>&nbsp;</font></div>
<div align=left><span style="FONT-SIZE: 9pt"><a href="http://code.google.com/apis/soapsearch/"><font face="Times New Roman" color=#0066cc size=3><u>Google SOAP Search API</u></font></a><font face="Times New Roman" size=3> </font></span></div>
<div align=left><font size=3><font face="Times New Roman"><span style="FONT-SIZE: 9pt">Google SOAP API</span><span style="FONT-SIZE: 9pt">服务的使用需要下载相关包，创建</span><span style="FONT-SIZE: 9pt">Google</span><span style="FONT-SIZE: 9pt">帐号，并加载</span><span style="FONT-SIZE: 9pt">license key</span><span style="FONT-SIZE: 9pt">，服务基于</span><span style="FONT-SIZE: 9pt">SOAP</span><span style="FONT-SIZE: 9pt">协议和</span><span style="FONT-SIZE: 9pt">WSDL</span><span style="FONT-SIZE: 9pt">标准。</span></font></font></div>
<img src ="http://www.cppblog.com/eday/aggbug/35979.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-11-06 19:23 <a href="http://www.cppblog.com/eday/articles/35979.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>javascript操作cookie</title><link>http://www.cppblog.com/eday/articles/35542.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 30 Oct 2007 13:05:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/35542.html</guid><description><![CDATA[<div class=blogOne>正如我们所知道的，在网络词汇中，cookie是一个特殊的信息，虽然只是服务器存于用户计算机上的一个文本文件，但由于其内容的不寻常性(与服务器有一定的互交性，且常会存储用户名，甚至口令，或是其它一些敏感信息，例如在江湖或是一些社区中，常会用cookie来保存用户集分，等级等等)。因而成为一些高手关注的对像，借此来取得特殊权限，甚至攻克整个网站。本人出些拙作，以java script中对cookie的应用，来说初步说明cookie欺骗的实现过程及具体应用。&nbsp;<br>　　&nbsp;<br>　　 (一)cookie的建立&nbsp;<br>　　&nbsp;<br>　　在讲如何建立cookie之前，我们先来了解一下cookie的基本格式：&nbsp;<br>　　&nbsp;<br>　　cookiename+cookievalue;expire=expirationdategmt;path=urlpath;domain=sitedomain&nbsp;<br>　　&nbsp;<br>　　其中各项以;分开，首先是指定cookie的名称，并为其赋值。接下来分别是cookie的有效期，url路径以及域名，在这几项中，除了第一项以外，其它部分均为可先项。&nbsp;<br>　　下面我们来看一段代码，了解一下cookie究竟是怎样建立的：&nbsp;<br>　　&nbsp;<br>　　&lt;HTML&gt;&nbsp;<br>　　&lt;HEAD&gt;&nbsp;<br>　　&lt;TITLE&gt;Set a cookie based on a form&lt;/TITLE&gt;&nbsp;<br>　　&lt;SCRIPT LANGUAGE="java script" TYPE="TEXT/java script"&gt;&nbsp;<br>　　&lt;!-- Hide script from older browsers&nbsp;<br>　　&nbsp;<br>　　expireDate = new Date&nbsp;<br>　　expireDate.setMonth(expireDate.getMonth()+6)&nbsp;<br>　　&nbsp;<br>　　userName = ""&nbsp;<br>　　if (documents .cookie != "") {&nbsp;<br>　　userName = documents .cookie.split("=")[1]&nbsp;<br>　　}&nbsp;<br>　　&nbsp;<br>　　function setCookie() {&nbsp;<br>　　userName = document.myform.nameField.value&nbsp;<br>　　documents .cookie = "userName="+userName+";expires=" + expireDate.toGMTString()&nbsp;<br>　　}&nbsp;<br>　　&nbsp;<br>　　// End hiding script --&gt;&nbsp;<br>　　&lt;/SCRIPT&gt;&nbsp;<br>　　&lt;/HEAD&gt;&nbsp;<br>　　&lt;BODY BGCOLOR="WHITE" onLoad="document.myform.nameField.value = userName"&gt;&nbsp;<br>　　&lt;form NAME="myform"&gt;&nbsp;<br>　　&lt;H1&gt;Enter your name:&lt;INPUT TYPE="TEXT" NAME="nameField" onBlur="setCookie()"&gt;&lt;/H1&gt;&nbsp;<br>　　&lt;/form&gt;&nbsp;<br>　　&lt;/BODY&gt;&nbsp;<br>　　&lt;/HTML&gt;&nbsp;<br>　　&nbsp;<br>　　这是一锻简单的建立cookie的脚本。&nbsp;<br>　　&nbsp;<br>　　1，&lt;SCRIPT LANGUAGE="java script" TYPE="TEXT/java script"&gt;&nbsp;<br>　　&nbsp;<br>　　脚本开始的标记，由此一句告诉浏览器以下将是java script.&nbsp;<br>　　&nbsp;<br>　　2,&lt;!-- Hide script from older browsers&nbsp;<br>　　&nbsp;<br>　　为了防止浏览器不能识别脚本，而让浏览器误以为是HTML注释而忽略它。&nbsp;<br>　　&nbsp;<br>　　3，expireDate = new Date&nbsp;<br>　　&nbsp;<br>　　获取当前日期，并存入变量expireDate中。&nbsp;<br>　　&nbsp;<br>　　4，expireDate.setMonth(expireDate.getMonth()+6)&nbsp;<br>　　&nbsp;<br>　　获取当前月份值，将其加6后设置为expireDate的月份总值部分。这意味着本cookie的有效期为6个月。&nbsp;<br>　　&nbsp;<br>　　5，if (documents .cookie != "")&nbsp;<br>　　&nbsp;<br>　　如果document的值不为空，相当于检查用户硬盘上是否已经有了cookie。&nbsp;<br>　　&nbsp;<br>　　6，userName = documents .cookie.split("=")[1]&nbsp;<br>　　&nbsp;<br>　　此处用到了split("=")函数，它的功能是把cookie记录分割为数组，cookie的名为cookie[0],值为cookie[1],以此累推。所以此处documents .cookie.split("=")[1]返回的值是此cookie的值。在此句中将值赋给了变量username。&nbsp;<br>　　&nbsp;<br>　　7，function setCookie()&nbsp;<br>　　&nbsp;<br>　　设置名为setCookie的函数。&nbsp;<br>　　&nbsp;<br>　　8，documents .cookie = "userName="+userName+";expires=" + expireDate.toGMTString()&nbsp;<br>　　&nbsp;<br>　　此句是将设置好的cookie写入用户硬盘。expireDate.toGMTString()把expireDate中的值转换为文本字符串，这&nbsp;<br>　　样才能写入cookie中。&nbsp;<br>　　&nbsp;<br>　　9，onLoad="document.myform.nameField.value = userName"&nbsp;<br>　　&nbsp;<br>　　当页面载入时，把username的值写入文本框(如果有的话)。&nbsp;<br>　　&nbsp;<br>　　10，onBlur="setCookie()"&nbsp;<br>　　&nbsp;<br>　　当用户离开文本框时，onBlur调用函数setCookie。&nbsp;<br>　　&nbsp;<br>　　结合上面的注释，读那段代码相信不成问题吧!既然我们可以建立cookie，那么读取也不是什么难事，请接着往下看!&nbsp;<br>　　&nbsp;<br>　　 (二)读取和显示cookie&nbsp;<br>　　&nbsp;<br>　　一般来说，cookie的作者并不希望cookie被显示出来，这是当然的!天知道里面写了些什么!？然而这也是我们想要读出它的原因!~~~:D&nbsp;<br>　　&nbsp;<br>　　&lt;HTML&gt;&nbsp;<br>　　&lt;HEAD&gt;&nbsp;<br>　　&lt;TITLE&gt;Cookie Check&lt;/TITLE&gt;&nbsp;<br>　　&lt;/HEAD&gt;&nbsp;<br>　　&lt;BODY BGCOLOR="WHITE"&gt;&nbsp;<br>　　&lt;H2&gt;&nbsp;<br>　　&lt;SCRIPT LANGUAGE="java script" TYPE="TEXT/java script"&gt;&nbsp;<br>　　&lt;!-- Hide script from older browsers&nbsp;<br>　　&nbsp;<br>　　if (documents .cookie == "") {&nbsp;<br>　　document.write("There are no cookies here")&nbsp;<br>　　}&nbsp;<br>　　else {&nbsp;<br>　　thisCookie = documents .cookie.split("; ")&nbsp;<br>　　&nbsp;<br>　　for (i=0; i&lt;thisCookie.length; i++) {&nbsp;<br>　　document.write("Cookie name is '"+thisCookie.split("=")[0])&nbsp;<br>　　document.write("', and the value is '"+thisCookie.split("=")[1]+"'&lt;BR&gt;")&nbsp;<br>　　}&nbsp;<br>　　}&nbsp;<br>　　&nbsp;<br>　　// End hiding script --&gt;&nbsp;<br>　　&lt;/SCRIPT&gt;&nbsp;<br>　　&lt;/H2&gt;&nbsp;<br>　　&lt;/BODY&gt;&nbsp;<br>　　&lt;/HTML&gt;&nbsp;<br>　　&nbsp;<br>　　以上的便是一段读取cookie的名字和值的脚本。上文中解释过的语句在此不多赘述，且看有什么新的语法：&nbsp;<br>　　&nbsp;<br>　　1，thisCookie = documents .cookie.split("; ")[注意：并非前文中出现过的split("=")。&nbsp;<br>　　&nbsp;<br>　　split("; ")可以产生数组的结果，本句中，由documents .cookie.split("; ")来获取cookie的值，并将这个数组赋值缎带变量：thisCookie。&nbsp;<br>　　&nbsp;<br>　　2，for (i=0; i&lt;thisCookie.length; i++)&nbsp;<br>　　&nbsp;<br>　　设置计算器变量i的值为0，如果其值小于thisCookie.length(thisCookie中值的个数)，将i的值加1。&nbsp;<br>　　&nbsp;<br>　　3，document.write("Cookie name is '"+thisCookie.split("=")[0])&nbsp;<br>　　&nbsp;<br>　　此句中thisCookie.split("=")[0]较难理解，上面的脚本中，thiscookie已经被赋值为一个数组的值，那么thisCookie是指数组中第i个值，也就是第i个cookie，而由上文可知split("=")[0]是指cookie的名字。&nbsp;<br>　　这样thisCookie.split("=")[0]便是第i的cookie中cookie的名字!&nbsp;<br>　　&nbsp;<br>　　4,document.write("', and the value is '"+thisCookie.split("=")[1]&nbsp;<br>　　&nbsp;<br>　　跟3极为相似，即是第i个cookie中 cookie的值。&nbsp;<br>　　&nbsp;<br>　　到此，我们已经熟悉了如何建立cookie以及它的读取。这些也正是cookie欺骗也需要的主要技术!<br>　　&nbsp;<br>　　 (三)cookie欺骗的实现&nbsp;<br>　　&nbsp;<br>　　要做到cookie欺骗，最重要的是理解目标cookie中的储值情况，并设法改变它。由上面的学习我们知道，基于cookie的格式所限，一般来说，只有在Cookie.split("=")[0]和Cookie.split("=")[1]中的值对我们才是有用的。也就是说只需改变这两处或是处的值即可达到我们的目的。&nbsp;<br>　　而在实际操作中，还得先解决另一个问题。&nbsp;<br>　　由于受浏览器的内部cookie机制所限，每个cookie只能被它的原服务器所访问!可我们总不能跑到人家服务器上操作吧!这里就需要一个小技巧了。&nbsp;<br>　　在上面我们提到过cookie的格式，最后两项中分别是它的url路径和域名。不难想到，服务器对cookie的识别靠的就是这个!&nbsp;<br>　　而在平时，我们要浏览一个网站时，输入的url便是它的域名，需要经过域名管理系统dns将其转化为IP地址后进行连接的。这其中就有一个空当。如果能在dns上做手脚，把目标域名的IP地址对应到其它站点上，我们便可以非法访问目标站点的cookie了!&nbsp;<br>　　做到这一点并不难，当然我不并不是要去操纵dns，而且那也是不可能的事情。在win9下的安装目录下，有一名为hosts.sam的文件，以文本方式打开后会看到这样的格式：&nbsp;<br>　　127.0.0.1 lockhost #注释&nbsp;<br>　　利用它，我们便可以实现域名解析的本地化!而且其优先权高于网络中的dns!&nbsp;<br>　　具体使用时，只需将IP和域名依上面的格式添加，并另存为hosts即可!(注意：此文件无后赘名，并非hosts.sam 文件本身!)&nbsp;<br>　　&nbsp;<br>　　到此，cookie欺骗所需的所以知识已经齐备。下面以一个&#8220;假&#8221;的例子，演示一下如何进入实战.(不便给出真实地址，以免引起犯罪!~~~:P)&nbsp;<br>　　假设目标站点是 www.xxx.com&nbsp;<br>　　www.self.com是自己的站点。(可以用来存放欺骗目标所需的文件，用来读取和修改对方的cookie.)&nbsp;<br>　　首先ping出www.self.com的IP地址：&nbsp;<br>　　ping www.self.com&nbsp;<br>　　&nbsp;<br>　　Reply from 12.34.56.78: bytes=32 time=20ms TTL=244&nbsp;<br>　　&nbsp;<br>　　然后修改hosts.sam文件如下：&nbsp;<br>　　&nbsp;<br>　　12.34.56.78 www.xxx.com&nbsp;<br>　　并保存为hosts。&nbsp;<br>　　&nbsp;<br>　　将用来读取cookie的页面传至www.self.com(脚本如二所示)。&nbsp;<br>　　此时连上www.xxx.com。由于我们已经对hosts动过手脚，这时来到的并不是www.xxx.com，而是www.self.com&nbsp;<br>　　www.xxx.com设在本地的cookie便可被读出!~~:D&nbsp;<br>　　然后根据具体情况修改一的脚本，用同样的方法，向此cookie中写入数据。修改完毕后，删掉hosts文件，再重新进入www.xxx.com，此时已经大功告成，可享受你的hack成果了!~~~:)&nbsp;<br>　　&nbsp;<br>　　[编后]&nbsp;<br>　　cookie欺骗是一种发现较早，且较难使用的hack手法，除了java script 可以控制以外，asp等也可以用来对其进进设置。所以在此声名，未必能对所有站点有较。但技术真实，无须置疑!&nbsp;<br>　　&nbsp;<br>　　补充：在win2000中hosts文件的建立与win98不同，需要c:\winnt\system32\drivers\etc文件夹中创建!</div>
<img src ="http://www.cppblog.com/eday/aggbug/35542.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-30 21:05 <a href="http://www.cppblog.com/eday/articles/35542.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>路由跟踪命令.查看DNS、IP、Mac等</title><link>http://www.cppblog.com/eday/articles/35494.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 30 Oct 2007 01:40:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/35494.html</guid><description><![CDATA[1.最基本，最常用的，测试物理网络的 <br>　　ping 192.168.0.8 －t ，参数－t是等待用户去中断测试
<p>　　2.查看DNS、IP、Mac等 <br>　　A.Win98：winipcfg <br>　　B.Win2000以上：Ipconfig/all </p>
<p>　　C.NSLOOKUP：如查看河北的DNS <br>　　C:\&gt;nslookup <br>　　Default Server: ns.hesjptt.net.cn <br>　　Address: 202.99.160.68 <br>　　&gt;server 202.99.41.2 则将DNS改为了41.2 <br>　　&gt; pop.pcpop.com <br>　　Server: ns.hesjptt.net.cn <br>　　Address: 202.99.160.68 </p>
<p>　　Non-authoritative answer: <br>　　Name: pop.pcpop.com <br>　　Address: 202.99.160.212 </p>
<p>　　3.网络信使 （经常有人问的~） <br>　　Net send 计算机名/IP|* (广播) 传送内容，注意不能跨网段 <br>　　net stop messenger 停止信使服务，也可以在面板－服务修改 <br>　　net start messenger 开始信使服务 </p>
<p>　　4.探测对方对方计算机名，所在的组、域及当前用户名 （追捕的工作原理） <br>　　ping －a IP －t ，只显示NetBios名 <br>　　nbtstat -a 192.168.10.146 比较全的 </p>
<p>　　5.netstat -a 显示出你的计算机当前所开放的所有端口 <br>　　netstat -s -e 比较详细的显示你的网络资料，包括TCP、UDP、ICMP 和 IP的统计等 </p>
<p>　　6.探测arp绑定（动态和静态）列表，显示所有连接了我的计算机，显示对方IP和MAC地址 <br>　　arp -a </p>
<p>　　7.在代理服务器端 <br>　　捆绑IP和MAC地址，解决局域网内盗用IP！： <br>　　ARP －s 192.168.10.59 00 －50－ff－6c－08－75 <br>　　解除网卡的IP与MAC地址的绑定： <br>　　arp -d 网卡IP </p>
<p>　　8.在网络邻居上隐藏你的计算机 （让人家看不见你！） <br>　　net config server /hidden:yes <br>　　net config server /hidden:no 则为开启 <br>　　9.几个net命令 <br>　　A.显示当前工作组服务器列表 net view，当不带选项使用本命令时，它就会显示当前域或网络上的计算机上的列表。 <br>　　比如：查看这个IP上的共享资源，就可以 <br>　　C:\&gt;net view 192.168.10.8 <br>　　在 192.168.10.8 的共享资源 <br>　　资源共享名 类型 用途 注释 <br>　　-------------------------------------- <br>　　网站服务 Disk <br>　　命令成功完成。 </p>
<p>　　B.查看计算机上的用户帐号列表 net user <br>　　C.查看网络链接 net use <br>　　例如：net use z: <a href="file://192.168.10.8/movie"><u><font color=#0066cc>\\192.168.10.8\movie</font></u></a> 将这个IP的movie共享目录映射为本地的Z盘 </p>
<p>　　D.记录链接 net session <br>　　例如： <br>　　C:\&gt;net session <br>　　计算机 用户名 客户类型 打开空闲时间 <br>　　------------------------------------------------------------------------------- <br>　　<a href="file://192.168.10.110/"><u><font color=#0066cc>\\192.168.10.110</font></u></a> ROME Windows 2000 2195 0 00:03:12 </p>
<p>　　<a href="file://192.168.10.51/"><u><font color=#0066cc>\\192.168.10.51</font></u></a> ROME Windows 2000 2195 0 00:00:39 <br>　　命令成功完成。 </p>
<p>　　10.路由跟踪命令 <br>　　A.tracert pop.pcpop.com <br>　　B.pathping pop.pcpop.com 除了显示路由外，还提供325S的分析，计算丢失包的％ </p>
<p>　　11.关于共享安全的几个命令 <br>　　A.查看你机器的共享资源 net share <br>　　B.手工删除共享（可以编个bat文件，开机自运行，把共享都删了！） <br>　　net share c$ /d <br>　　net share d$ /d <br>　　net share ipc$ /d <br>　　net share admin$ /d <br>　　注意$后有空格。 <br>　　C.增加一个共享： <br>　　c:\net share mymovie=e:\downloads\movie /users:1 <br>　　mymovie 共享成功。 <br>　　同时限制链接用户数为1人。 </p>
<p>　　12.在DOS行下设置静态IP <br>　　A.设置静态IP <br>　　CMD <br>　　netsh <br>　　netsh&gt;int <br>　　interface&gt;ip <br>　　interface ip&gt;set add "本地链接" static IP地址 mask gateway <br>　　B.查看IP设置 <br>　　interface ip&gt;show address </p>
<p>　　Arp <br>　　显示和修改&#8220;地址解析协议 (ARP)&#8221;缓存中的项目。ARP 缓存中包含一个或多个表，它们用于存储 IP 地址及其经过解析的以太网或令牌环物理地址。计算机上安装的每一个以太网或令牌环网络适配器都有自己单独的表。如果在没有参数的情况下使用，则 arp 命令将显示帮助信息。 </p>
<p>　　语法 <br>　　arp [-a [InetAddr] [-N IfaceAddr]] [-g [InetAddr] [-N IfaceAddr]] [-d InetAddr [IfaceAddr]] [-s InetAddr EtherAddr [IfaceAddr]] </p>
<p>　　参数 <br>　　-a [InetAddr] [-N IfaceAddr] <br>　　显示所有接口的当前 ARP 缓存表。要显示指定 IP 地址的 ARP 缓存项，请使用带有 InetAddr 参数的 arp -a，此处的 InetAddr 代表指定的 IP 地址。要显示指定接口的 ARP 缓存表，请使用 -N IfaceAddr 参数，此处的 IfaceAddr 代表分配给指定接口的 IP 地址。-N 参数区分大小写。 <br>　　-g [InetAddr] [-N IfaceAddr] <br>　　与 -a 相同。 <br>　　-d InetAddr [IfaceAddr] <br>　　删除指定的 IP 地址项，此处的 InetAddr 代表 IP 地址。对于指定的接口，要删除表中的某项，请使用 IfaceAddr <br>　　参数，此处的 IfaceAddr 代表分配给该接口的 IP 地址。要删除所有项，请使用星号 (*) 通配符代替 InetAddr。 <br>　　-s InetAddr EtherAddr [IfaceAddr] <br>　　向 ARP 缓存添加可将 IP 地址 InetAddr 解析成物理地址 EtherAddr 的静态项。要向指定接口的表添加静态 ARP 缓存项，请使用 IfaceAddr 参数，此处的 IfaceAddr 代表分配给该接口的 IP 地址。 <br>　　/? <br>　　在命令提示符显示帮助。 <br>　　注释 <br>　　InetAddr 和 IfaceAddr 的 IP 地址用带圆点的十进制记数法表示。 <br>　　物理地址 EtherAddr 由六个字节组成，这些字节用十六进制记数法表示并且用连字符隔开（比如，00-AA-00-4F-2A-9C）。 <br>　　通过 -s 参数添加的项属于静态项，它们不会 ARP 缓存中超时。如果终止 TCP/IP 协议后再启动，这些项会被删除。要创建永久的静态 ARP 缓存项，请在批处理文件中使用适当的 arp 命令并通过&#8220;计划任务程序&#8221;在启动时运行该批处理文件。 <br>　　只有当网际协议 (TCP/IP) 协议在 网络连接中安装为网络适配器属性的组件时，该命令才可用。 <br>　　范例 <br>　　要显示所有接口的 ARP 缓存表，可键入： </p>
<p>　　arp -a </p>
<p>　　对于指派的 IP 地址为 10.0.0.99 的接口，要显示其 ARP 缓存表，可键入： </p>
<p>　　arp -a -N 10.0.0.99 </p>
<p>　　要添加将 IP 地址 10.0.0.80 解析成物理地址 00-AA-00-4F-2A-9C 的静态 ARP 缓存项，可键入： </p>
<p>　　arp -s 10.0.0.80 00-AA-00-4F-2A-9C <br>　　At <br>　　计划在指定时间和日期在计算机上运行命令和程序。at 命令只能在&#8220;计划&#8221;服务运行时使用。如果在没有参数的情况下使用，则 at 列出已计划的命令。 </p>
<p>　　语法 <br>　　at [\\ComputerName] [{[ID] [/delete]|/delete [/yes]}] </p>
<p>　　at [[\\ComputerName] hours:minutes [/interactive] [{/every:date[,...]|/next:date[,...]}] command] </p>
<p>　　参数 <br>　　<a href="file://computername/"><u><font color=#0066cc>\\computername</font></u></a> <br>　　指定远程计算机。如果省略该参数，则 at 计划本地计算机上的命令和程序。 <br>　　ID <br>　　指定指派给已计划命令的识别码。 <br>　　/delete <br>　　取消已计划的命令。如果省略了 ID，则计算机中所有已计划的命令将被取消。 <br>　　/yes <br>　　删除已计划的事件时，对来自系统的所有询问都回答&#8220;是&#8221;。 <br>&nbsp;</p>
<p>&nbsp;　　hours:minutes <br>　　指定命令运行的时间。该时间用 24 小时制（即从 00:00 [午夜] 到 23:59）的 小时: 分钟格式表示。 <br>　　/interactive <br>　　对于在运行 command 时登录的用户,允许 command 与该用户的桌面进行交互。 <br>　　/every: <br>　　在每个星期或月的指定日期（例如，每个星期四，或每月的第三天）运行 command 命令。</p>
<p>　　date <br>　　指定运行命令的日期。可以指定一周的某日或多日（即，键入 M、T、W、Th、F、S、Su）或一个月中的某日或多日（即，键入从 1 到31 之间的数字）。用逗号分隔多个日期项。如果省略了 date，则 at 使用该月的当前日。 <br>　　/next: <br>　　在下一个指定日期（比如，下一个星期四）到来时运行 command。</p>
<p>　　command <br>　　指定要运行的 Windows 命令、程序（.exe 或 .com 文件）或批处理程序（.bat 或 .cmd 文件）。当命令需要路径作为参数时，请使用绝对路径，也就是从驱动器号开始的整个路径。如果命令在远程计算机上，请指定服务器和共享名的通用命名协定 (UNC) 符号，而不是远程驱动器号。 <br>　　/? <br>　　在命令提示符显示帮助。 <br>　　注释 <br>　　Schtasks 是功能更为强大的超集命令行计划工具，它含有 at 命令行工具中的所有功能。对于所有的命令行计划任务，都可以使用 schtasks 来替代 at。有关 schtasks 的详细信息，请参阅&#8220;相关主题&#8221;。 </p>
<p>　　使用 at <br>　　使用 at 命令时，要求您必须是本地 Administrators 组的成员。 <br>加载 Cmd.exe <br>　　在运行命令之前，At 不会自动加载 Cmd.exe （命令解释器）。如果没有运行可执行文件 (.exe)，则在命令开头必须使用如下所示的方法专门加载 Cmd.exe： </p>
<p>　　cmd /c dir &gt; c:\test.out。 </p>
<p>　　查看已计划的命令 <br>　　当不带命令行选项使用 at 时，计划任务会出现在类似于以下格式的表中： </p>
<p>　　Status ID Day Time Command Line <br>　　OK 1 Each F 4:30 PM net send group leads status due <br>　　OK 2 Each M 12:00 AM chkstor &gt; check.file <br>　　OK 3 Each F 11:59 PM backup2.bat <br>　　包含标识号 (ID) <br>　　当在命令提示下使用带有标识号 (ID) 的 at 命令时，单个任务项的信息会显示在类似于下面的格式中： </p>
<p>　　Task ID： 1 </p>
<p>　　Status:OK </p>
<p>　　Schedule:Each F </p>
<p>　　Time of Day:4:30 PM </p>
<p>　　Command:net send group leads status due当计划带有 at 的命令（尤其是带有命令行选项的命令）后，要通过键入不带命令行选项的 at 来检查该命令语法是否输入正确。如果显示在&#8220;命令行&#8221;列中的信息不正确，请删除该命令，然后重新键入它。如果还不正确，则可以在重新键入该命令时让它少带些命令行选项。 </p>
<p>　　查看结果 <br>　　使用 at 的已经计划的命令作为后台程序运行。运行结果不会显示在计算机上。要将输出重定向到文件，请使用重定向符号 (&gt; )。如果将输出重定向到文件，则不论是在命令行还是在批处理文件中使用 at，都需要在重定向符号之前使用转义符 (^)。例如，要重定向输出到 Output.text 文件，则要键入： </p>
<p>　　at 14:45 c:\test.bat ^&gt;c:\output.txt </p>
<p>　　执行命令的当前目录为 systemroot 文件夹。 </p>
<p>　　更改系统时间 <br>　　在使用 at 命令计划了要运行的命令之后，如果更改了计算机的系统时间，则通过键入不带命令行选项的 at 可使 at 计划程序与修改后的系统时间同步。 </p>
<p>　　存储命令 <br>　　已计划的命令存储在注册表中。这样，如果重新启动&#8220;计划&#8221;服务，则不会丢失计划任务。 </p>
<p><br>　　连接到网络驱动器 <br>　　对于需要访问网络的计划作业，请不要使用已重新定向的驱动器。&#8220;计划&#8221;服务可能无法访问这些重定向的驱动器，或者，在该计划任务运行时如果有其他用户登录，则这些重定向的驱动器可能不会出现。因此，对于计划作业，请使用 UNC 路径。例如： </p>
<p>　　at 1:00pm my_backup <a href="file://server/share"><u><font color=#0066cc>\\server\share</font></u></a> </p>
<p>　　请不要使用下述语法（其中 x: ?表示由用户建立的连接）： </p>
<p>　　at 1:00pm my_backup x: </p>
<p>　　如果计划了一个使用驱动器号的 at 命令来连接共享目录，则应包含一个 at 命令以使在完成该驱动器的使用时断开与驱动器的连接。如果不能断开与驱动器的连接，则在命令提示下，所指派的驱动器号将不可用。 </p>
<p>　　范例 <br>　　要显示 Marketing 服务器上已计划的命令列表，请键入： </p>
<p>　　at <a href="file://marketing/"><u><font color=#0066cc>\\marketing</font></u></a> <br>　　要了解服务器 Corp 上标识号为 3 的命令的详细信息，请键入： </p>
<p>　　at <a href="file://corp/"><u><font color=#0066cc>\\corp</font></u></a> 3 <br>　　要计划在上午 8:00 于 Corp 服务器上运行网络共享命令，并将该列表重定向到 Maintenance 服务器的 Corp.txt 文件（位于 Reports 共享目录下）中，请键入： </p>
<p>　　at <a href="file://corp/"><u><font color=#0066cc>\\corp</font></u></a> 08:00 cmd /c "net share reports=d:\marketing\reports &gt;&gt; <a href="file://maintenance/reports/corp.txt"><u><font color=#0066cc>\\maintenance\reports\corp.txt</font></u></a>" <br>　　为了在每五天后的午夜将 Marketing 服务器的硬盘驱动器备份到磁带驱动器，首先创建名为 Archive.cmd 的批处理程序（它含有备份命令），然后计划该批处理程序的运行，为此请键入： </p>
<p>　　at <a href="file://marketing/"><u><font color=#0066cc>\\marketing</font></u></a> 00:00 /every:5,10,15,20,25,30 archive <br>　　要取消当前服务器上已计划的所有命令，请按下述方法清除 at 计划信息： </p>
<p>　　at /delete <br>　　如果要运行的命令不是可执行 (.exe) 文件，请按如下所示的方法在该命令之前使用 cmd /c 来加载 Cmd.exe： </p>
<p>　　cmd /c dir &gt; c:\test.out。<br>　　Rsh <br>　　在运行 RSH 服务的远程计算机上运行命令。Windows XP 和 Windows 2000 不提供 RSH 服务。Windows 2000 Server Resource Kit 提供名为 Rshsvc.exe 的 RSH 服务。使用不带参数的 rsh 显示帮助。 </p>
<p>　　语法 <br>　　rsh [Host] [-l UserName] [-n] [Command] </p>
<p>　　参数 <br>　　Host <br>　　指定运行 command 的远程计算机。 <br>　　-l UserName <br>　　指定远程计算机上使用的用户名。在省略情况下，使用当前登录用户的名称。 <br>　　-n <br>　　将 rsh 的输入重定向到 NULL 设备。这防止本地计算机命令结果的显示。 <br>　　Command <br>　　指定要运行的命令。 <br>　　/? <br>　　在命令提示符显示帮助。 <br>　　注释 <br>　　标准操作 <br>　　rsh 命令将标准输入复制到远程 command，将远程 command 的标准输出复制到其标准输出，将远程 command 的标准错误复制到其标准错误。Rsh 通常在远程命令终止时终止。 </p>
<p>　　使用重定向符号 <br>　　为了使重定向在远程计算机上发生，要以引号引住重定向符号（例如 "&gt;&gt;"）。如果不使用引号，重定向会在本地计算机发生。例如，以下命令将远程文件&#8220;RemoteFile&#8221;附加到本地文件&#8220;LocalFile&#8221;中： </p>
<p>　　rsh othercomputer cat remotefile &gt;&gt; localfile </p>
<p>　　以下命令将远程文件 Remotefile 附加到远程文件 otherremotefile 中： </p>
<p>　　rsh othercomputer cat remotefile "&gt;&gt;" otherremotefile </p>
<p>　　使用 rsh <br>　　在使用已登录到某个域并且运行 Windows XP Professional 的计算机时，该域的主域控制器必须可用于确认用户名或 rsh 命令失败。 </p>
<p>　　.rhosts 文件 <br>　　.rhosts 文件通常许可 UNIX 系统的网络访问权限。.rhosts 文件列出可以访问远程计算机的计算机名及关联的登录名。在正确配置了 .rhosts 文件的远程计算机上运行 rcp、rexec 或 rsh 命令时，您不必提供远程计算机的登录和密码信息。 </p>
<p>　　.rhosts 文件是一个文本文件，该文件中每一行为一个条目。条目由本地计算机名、本地用户名和有关该条目的所有注释组成。每个条目均由制表符或空格分开，注释用符号 (#) 打头。例如： </p>
<p>　　host7 #This computer is in room 31A </p>
<p>　　.rhosts 文件必须在远程计算机的用户主目录中。有关远程计算机 .rhosts 文件特定执行的详细信息，请参阅远程系统的文档。 </p>
<p>　　只有当网际协议 (TCP/IP) 协议在 网络连接中安装为网络适配器属性的组件时，该命令才可用。 <br>　　范例 <br>　　要以名称 admin1 在远程计算机 vax1 上执行 telcon 命令，请键入： </p>
<p>　　rsh vax1 -l admin1 telcon <br>　　Tftp <br>　　向运行平凡文件传输协议 (TFTP) 服务或 daemon 的远程计算机（尤其是运行 UNIX 的计算机）传输文件或从运行平凡文件传输协议 (TFTP) 服务或 daemon 的远程计算机（尤其是运行 UNIX 的计算机）传输文件。 </p>
<p>　　语法 <br>　　tftp [-i] [Host] [{get | put}] [Source] [Destination] </p>
<p>　　参数 <br>　　-i <br>　　指定二进制图像传送模式（也称为八进制模式）。在二进制图像模式下，文件以一个字节为单位进行传输。在传送二进制文件时使用该模式。如果省略了 -i，文件将以 ASCII 模式传送。这是默认的传送模式。该模式将行尾 (EOL) 字符转换为指定计算机的适当格式。传送文本文件时使用该模式。如果文件传送成功，将显示数据传输率。 <br>　　Host <br>　　指定本地或远程计算机。 <br>　　put <br>　　将本地计算机上的 Destination 文件传送到远程计算机上的 Source 文件。因为 TFTP 协议不支持用户身份验证，所以用户必须登录到远程计算机，同时文件在远程计算机上必须可写。 <br>　　get <br>　　将远程计算机上的 Destination 文件传送到本地计算机上的 Source 文件。 <br>　　Source <br>　　指定要传送的文件。 <br>　　Destination <br>　　指定将文件传送到的位置。如果省略了 Destination，将假定它与 Source 同名。 <br>　　/? <br>　　在命令提示符显示帮助。 <br>　　注释 <br>　　使用 get 参数 <br>　　如果将本地计算机上的文件 FileTwo 传送到远程计算机上的文件 FileOne，则指定 put。如果将远程计算机上的文件 FileTwo 传送到远程计算机上的文件 FileOne，则指定 get。 </p>
<p>　　Windows XP 或 Windows 2000 不提供一般用途的 TFTP 服务器。Windows 2000 提供的 TFTP 服务器服务只为 Windows XP 和 Windows 2000 客户端计算机提供远程引导功能。 <br>　　只有当网际协议 (TCP/IP) 协议在 网络连接中安装为网络适配器属性的组件时，该命令才可用。 <br>　　范例 <br>　　要从本地计算机将文件 Users.txt 传送到远程计算机 vax1 上的 Users19.txt，请键入： </p>
<p>　　tftp vax1 put users.txt users19.txt <br>　　Nbtstat <br>　　显示本地计算机和远程计算机的基于 TCP/IP (NetBT) 协议的 NetBIOS 统计资料、NetBIOS 名称表和 NetBIOS 名称缓存。Nbtstat 可以刷新 NetBIOS 名称缓存和注册的 Windows Internet 名称服务 (WINS) 名称。使用不带参数的 nbtstat 显示帮助。 </p>
<p>　　语法 <br>　　nbtstat [-a RemoteName] [-A IPAddress] [-c] [-n] [-r] [-R] [-RR] [-s] [-S] [Interval] </p>
<p>　　参数 <br>　　-a remotename <br>　　显示远程计算机的 NetBIOS 名称表，其中，RemoteName 是远程计算机的 NetBIOS 计算机名称。NetBIOS 名称表是运行在该计算机上的应用程序使用的 NetBIOS 名称列表。 <br>　　-A IPAddress <br>　　显示远程计算机的 NetBIOS 名称表，其名称由远程计算机的 IP 地址指定（以小数点分隔）。 <br>　　-c <br>　　显示 NetBIOS 名称缓存内容、NetBIOS 名称表及其解析的各个地址。 <br>　　-n <br>　　显示本地计算机的 NetBIOS 名称表。Registered 中的状态表明该名称是通过广播或 WINS 服务器注册的。 <br>　　-r <br>　　显示 NetBIOS 名称解析统计资料。在配置为使用 WINS 的 Windows XP 计算机上，该参数将返回已通过广播和 WINS 解析和注册的名称号码。 <br>　　-R <br>　　清除 NetBIOS 名称缓存的内容并从 Lmhosts 文件中重新加载带有 #PRE 标记的项目。 <br>　　-RR <br>　　重新释放并刷新通过 WINS 注册的本地计算机的 NetBIOS 名称。 <br>　　-s <br>　　显示 NetBIOS 客户和服务器会话，并试图将目标 IP 地址转化为名称。 <br>　　-S <br>　　显示 NetBIOS 客户和服务器会话，只通过 IP 地址列出远程计算机。 <br>　　Interval <br>　　重新显示选择的统计资料，可以中断每个显示之间的 Interval 中指定的秒数。按 CTRL+C 停止重新显示统计信息。如果省略该参数， netstat 将只显示一次当前的配置信息。 <br>　　/? <br>　　在命令提示符显示帮助。 <br>　　注释 <br>　　Nbtstat 命令行参数区分大小写。 <br>　　下表列出了由 Nbtstat 生成的列标题。 标题 说明 <br>　　Input 接收的字节数。 <br>　　Output 发送的字节数。 <br>　　In/Out 该连接是否从计算机（传出）或者其他计算机到本地计算机（传入）。 <br>　　Lift 名称表缓存项在被清除之前所存留的时间。 <br>　　Local Name 本地 NetBIOS 名称与连接相关联。 <br>　　Remote Host 与远程计算机相关的名称或 IP 地址。 <br>　　&lt;03&gt; 转化为十六进制的 NetBIOS 名称的最后一个字节。每个 NetBIOS 名称长度均为 16 个字符。由于最后一个字节通常有特殊的意义，因为相同的名称（只有最后一个字节不同）可能在一台计算机上出现几次。例如，&lt;20&gt; 在 ASCII 文本中是一个空格。 <br>　　Type 名称类型。名称可以是单个名称，也可以是组名称。 <br>　　Status 远程计算机上是否在运行 NetBIOS 服务（&#8220;已注册&#8221;），或同一计算机名是否已注册了相同的服务（&#8220;冲突&#8221;）。 <br>　　State NetBIOS 连接的状态。 </p>
<p>　　下表列出了可能的 NetBIOS 连接状态。 状态 说明 <br>　　已连接 会话已建立。 <br>　　关联 连接的终结点已经被创建并与 IP 地址关联。 <br>　　正接听 该终结点对内向连接可用。 <br>　　空闲 该结束点已被打开单不能接收连接。 <br>　　正在连接 会话处于连接阶段。在此阶段正在解析所选目标的由名称到 IP 地址的映射。 <br>　　接受 入站会话当前正在被接受，将在短期内连接。 <br>　　重新连接 会话将试图重新连接（如果第一次连接失败）。 <br>　　出站 会话正处于连接阶段。此阶段正在创建 TCP 连接。 <br>　　入站 入站会话在连接期。 <br>　　正在断开 会话正在断开连接。 <br>　　已中断连接 本地计算机已断开连接，并正等待远程系统的确认。 </p>
<p>　　只有当网际协议 (TCP/IP) 协议在 网络连接中安装为网络适配器属性的组件时，该命令才可用。 <br>　　范例 <br>　　要显示 NetBIOS 计算机名为 CORP07 的远程计算机的 NetBIOS 名称表，请键入： </p>
<p>　　nbtstat -a CORP07 </p>
<p>　　要显示所分配 IP 地址为 10.0.0.99 的远程计算机的 NetBIOS 名称表，请键入： </p>
<p>　　nbtstat -A 10.0.0.99 </p>
<p>　　要显示本地计算机的 NetBIOS 名称表，请键入： </p>
<p>　　nbtstat -n </p>
<p>　　要显示本地计算机 NetBIOS 名称缓存的内容，请键入： </p>
<p>　　nbtstat -c </p>
<p>　　要清除 NetBIOS 名称缓存并重新装载本地 Lmhosts 文件中带标记 #PRE 的项目，请键入： </p>
<p>　　nbtstat -R </p>
<p>　　要释放通过 WINS 服务器注册的 NetBIOS 名称并对其重新注册，请键入： </p>
<p>　　nbtstat -RR </p>
<p>　　要每隔 5 秒以 IP 地址显示 NetBIOS 会话统计资料，请键入： </p>
<p>　　nbtstat -S 5 <br>　　Netstat <br>　　显示活动的 TCP 连接、计算机侦听的端口、以太网统计信息、IP 路由表、IPv4 统计信息（对于 IP、ICMP、TCP 和 UDP 协议）以及 IPv6 统计信息（对于 IPv6、ICMPv6、通过 IPv6 的 TCP 以及通过 IPv6 的 UDP 协议）。使用时如果不带参数，netstat 显示活动的 TCP 连接。 </p>
<p>　　语法 <br>　　netstat [-a] [-e] [-n] [-o] [-p Protocol] [-r] [-s] [Interval] </p>
<p>　　参数 <br>　　-a <br>　　显示所有活动的 TCP 连接以及计算机侦听的 TCP 和 UDP 端口。 <br>　　-e <br>　　显示以太网统计信息，如发送和接收的字节数、数据包数。该参数可以与 -s 结合使用。 <br>　　-n <br>　　显示活动的 TCP 连接，不过，只以数字形式表现地址和端口号，却不尝试确定名称。 <br>　　-o <br>　　显示活动的 TCP 连接并包括每个连接的进程 ID (PID)。可以在 Windows 任务管理器中的&#8220;进程&#8221;选项卡上找到基于 PID 的应用程序。该参数可以与 -a、-n 和 -p 结合使用。 <br>　　-p Protocol <br>　　显示 Protocol 所指定的协议的连接。在这种情况下，Protocol 可以是 tcp、udp、tcpv6 或 udpv6。如果该参数与 -s 一起使用按协议显示统计信息，则 Protocol 可以是 tcp、udp、icmp、ip、tcpv6、udpv6、icmpv6 或 ipv6。 <br>　　-s <br>　　按协议显示统计信息。默认情况下，显示 TCP、UDP、ICMP 和 IP 协议的统计信息。如果安装了 Windows XP 的 IPv6 协议，就会显示有关 IPv6 上的 TCP、IPv6 上的 UDP、ICMPv6 和 IPv6 协议的统计信息。可以使用 -p 参数指定协议集。 <br>　　-r <br>　　显示 IP 路由表的内容。该参数与 route print 命令等价。 <br>　　Interval <br>　　每隔 Interval 秒重新显示一次选定的信息。按 CTRL+C 停止重新显示统计信息。如果省略该参数，netstat 将只打印一次选定的信息。 <br>　　/? <br>　　在命令提示符显示帮助。 <br>　　注释 <br>　　与该命令一起使用的参数必须以连字符 (-) 而不是以短斜线 (/) 作为前缀。 <br>　　Netstat 提供下列统计信息： <br>　　Proto <br>　　协议的名称（TCP 或 UDP）。 </p>
<p>---------------------------------------------------------------------------------------------------------------------------------------------------------------</p>
<p>补充：</p>
<p>C:\tracert <a href="http://www.baidu.com/"><u><font color=#800080>http://www.baidu.com/</font></u></a><br>C:\pathping <a href="http://www.baidu.com/"><u><font color=#800080>http://www.baidu.com/</font></u></a></p>
<p>除了显示路由外 还提供325S的分析 计算丢失包的％ </p>
<p>使用 nbtstat 解决 NetBIOS 名称问题 <br>TCP/IP 上的 NetBIOS (NetBT) 将 NetBIOS 名称解析成 IP 地址。TCP/IP 为 NetBI <br>OS 名称解析提供了很多选项，包括本地缓存搜索、WINS 服务器查询、广播、DNS 服 <br>务器查询以及 Lmhosts 和主机文件搜索。 </p>
<p>Nbtstat 是解决 NetBIOS 名称解析问题的有用工具。可以使用 nbtstat 命令删除或 <br>更正预加载的项目： </p>
<p>nbtstat -n 显示由服务器或重定向器之类的程序在系统上本地注册的名称。 <br>nbtstat -c 显示 NetBIOS 名称缓存，包含其他计算机的名称对地址映射。 <br>nbtstat -R 清除名称缓存，然后从 Lmhosts 文件重新加载。 <br>nbtstat -RR 释放在 WINS 服务器上注册的 NetBIOS 名称，然后刷新它们的注册。 <br>nbtstat -a name 对 name 指定的计算机执行 NetBIOS 适配器状态命令。适配器状态 <br>命令将返回计算机的本地 NetBIOS 名称表，以及适配器的媒体访问控制地址。 <br>nbtstat -S 列出当前的 NetBIOS 会话及其状态（包括统计），如下例所示： <br>NetBIOS connection table </p>
<p>Local name State In/out Remote Host Input Output <br>------------------------------------------------------------------ <br>CORP1 &lt;00&gt; Connected Out CORPSUP1&lt;20&gt; 6MB 5MB <br>CORP1 &lt;00&gt; Connected Out CORPPRINT&lt;20&gt; 108KB 116KB <br>CORP1 &lt;00&gt; Connected Out CORPSRC1&lt;20&gt; 299KB 19KB <br>CORP1 &lt;00&gt; Connected Out CORPEMAIL1&lt;20&gt; 324KB 19KB <br>CORP1 &lt;03&gt; Listening <br>使用 netstat 显示连接统计 <br>可以使用 netstat 命令显示协议统计信息和当前的 TCP/IP 连接。netstat -a 命令 <br>将显示所有连接，而 netstat -r 显示路由表和活动连接。netstat -e 命令将显示 <br>Ethernet 统计信息，而 netstat -s 显示每个协议的统计信息。如果使用 netstat <br>-n，则不能将地址和端口号转换成名称。下面是 netstat 的输出示例：</p>
<p>路由命令<br>C:\\&gt;netstat -e <br>Interface Statistics </p>
<p>Received Sent <br>Bytes 3995837940 47224622 <br>Unicast packets 120099 131015 <br>Non-unicast packets 7579544 3823 <br>Discards 0 0 <br>Errors 0 0 <br>Unknown protocols 363054211 </p>
<p>C:\\&gt;netstat -a </p>
<p>Active Connections </p>
<p>Proto Local Address Foreign Address State <br>TCP CORP1:1572 172.16.48.10:nbsession ESTABLISHED <br>TCP CORP1:1589 172.16.48.10:nbsession ESTABLISHED <br>TCP CORP1:1606 172.16.105.245:nbsession ESTABLISHED <br>TCP CORP1:1632 172.16.48.213:nbsession ESTABLISHED <br>TCP CORP1:1659 172.16.48.169:nbsession ESTABLISHED <br>TCP CORP1:1714 172.16.48.203:nbsession ESTABLISHED <br>TCP CORP1:1719 172.16.48.36:nbsession ESTABLISHED <br>TCP CORP1:1241 172.16.48.101:nbsession ESTABLISHED <br>UDP CORP1:1025 *:* <br>UDP CORP1:snmp *:* <br>UDP CORP1:nbname *:* <br>UDP CORP1:nbdatagram *:* <br>UDP CORP1:nbname *:* <br>UDP CORP1:nbdatagram *:* </p>
<p>C:\\&gt;netstat -s <br>IP Statistics </p>
<p>Packets Received = 5378528 <br>Received Header Errors = 738854 <br>Received Address Errors = 23150 <br>Datagrams Forwarded = 0 <br>Unknown Protocols Received = 0 <br>Received Packets Discarded = 0 <br>Received Packets Delivered = 4616524 <br>Output Requests = 132702 <br>Routing Discards = 157 <br>Discarded Output Packets = 0 <br>Output Packet No Route = 0 <br>Reassembly Required = 0 <br>Reassembly Successful = 0 <br>Reassembly Failures = <br>Datagrams Successfully Fragmented = 0 <br>Datagrams Failing Fragmentation = 0 <br>Fragments Created = 0 </p>
<p>ICMP Statistics <br>Received Sent <br>Messages 693 4 <br>Errors 0 0 <br>Destination Unreachable 685 0 <br>Time Exceeded 0 0 <br>Parameter Problems 0 0 <br>Source Quenches 0 0 <br>Redirects 0 0 <br>Echoes 4 0 <br>Echo Replies 0 4 <br>Timestamps 0 0 <br>Timestamp Replies 0 0 <br>Address Masks 0 0 <br>Address Mask Replies 0 0 </p>
<p>TCP Statistics </p>
<p>Active Opens = 597 <br>Passive Opens = 135 <br>Failed Connection Attempts = 107 <br>Reset Connections = 91 <br>Current Connections = 8 <br>Segments Received = 106770 <br>Segments Sent = 118431 <br>Segments Retransmitted = 461 </p>
<p>UDP Statistics </p>
<p>Datagrams Received = 4157136 <br>No Ports = 351928 <br>Receive Errors = 2 <br>Datagrams Sent = 13809 </p>
<p>使用 tracert 跟踪网络连接 <br>Tracert（跟踪路由）是路由跟踪实用程序，用于确定 IP 数据报访问目标所采取的路 <br>径。Tracert 命令用 IP 生存时间 (TTL) 字段和 ICMP 错误消息来确定从一个主机到 <br>网络上其他主机的路由。 </p>
<p>Tracert 工作原理 <br>通过向目标发送不同 IP 生存时间 (TTL) 值的&#8220;Internet 控制消息协议 (ICMP)&#8221;回 <br>应数据包，Tracert 诊断程序确定到目标所采取的路由。要求路径上的每个路由器在 <br>转发数据包之前至少将数据包上的 TTL 递减 1。数据包上的 TTL 减为 0 时，路由器 <br>应该将&#8220;ICMP 已超时&#8221;的消息发回源系统。 </p>
<p>Tracert 先发送 TTL 为 1 的回应数据包，并在随后的每次发送过程将 TTL 递增 1， <br>直到目标响应或 TTL 达到最大值，从而确定路由。通过检查中间路由器发回的&#8220;ICM <br>P 已超时&#8221;的消息确定路由。某些路由器不经询问直接丢弃 TTL 过期的数据包，这在 <br>Tracert 实用程序中看不到。 </p>
<p>Tracert 命令按顺序打印出返回&#8220;ICMP 已超时&#8221;消息的路径中的近端路由器接口列表 <br>。如果使用 -d 选项，则 Tracert 实用程序不在每个 IP 地址上查询 DNS。 </p>
<p>在下例中，数据包必须通过两个路由器（10.0.0.1 和 192.168.0.1）才能到达主机 <br>172.16.0.99。主机的默认网关是 10.0.0.1，192.168.0.0 网络上的路由器的 IP 地 <br>址是 192.168.0.1。 </p>
<p>C:\\&gt;tracert 172.16.0.99 -d <br>Tracing route to 172.16.0.99 over a maximum of 30 hops <br>1 2s 3s 2s 10,0.0,1 <br>2 75 ms 83 ms 88 ms 192.168.0.1 <br>3 73 ms 79 ms 93 ms 172.16.0.99 <br>Trace complete. <br>用 tracert 解决问题 <br>可以使用 tracert 命令确定数据包在网络上的停止位置。下例中，默认网关确定 19 <br>2.168.10.99 主机没有有效路径。这可能是路由器配置的问题，或者是 192.168.10. <br>0 网络不存在（错误的 IP 地址）。 </p>
<p>C:\\&gt;tracert 192.168.10.99 </p>
<p>Tracing route to 192.168.10.99 over a maximum of 30 hops </p>
<p>1 10.0.0.1 reports:Destination net unreachable. </p>
<p>Trace complete. </p>
<p>Tracert 实用程序对于解决大网络问题非常有用，此时可以采取几条路径到达同一个 <br>点。 </p>
<p>Tracert 命令行选项 <br>Tracert 命令支持多种选项，如下表所示。 </p>
<p>tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name </p>
<p>选项 描述 <br>-d 指定不将 IP 地址解析到主机名称。 <br>-h maximum_hops 指定跃点数以跟踪到称为 target_name 的主机的路由。 <br>-j host-list 指定 Tracert 实用程序数据包所采用路径中的路由器接口列表。 <br>-w timeout 等待 timeout 为每次回复所指定的毫秒数。 <br>target_name 目标主机的名称或 IP 地址。 </p>
<p>详细信息，请参阅使用 tracert 命令跟踪路径。 </p>
<p>使用 pathping 测试路由器 <br>pathping 命令是一个路由跟踪工具，它将 ping 和 tracert 命令的功能和这两个工 <br>具所不提供的其他信息结合起来。pathping 命令在一段时间内将数据包发送到到达最 <br>终目标的路径上的每个路由器，然后基于数据包的计算机结果从每个跃点返回。由于 <br>命令显示数据包在任何给定路由器或链接上丢失的程度，因此可以很容易地确定可能 <br>导致网络问题的路由器或链接。某些选项是可用的，如下表所示。 </p>
<p>选项 名称 功能 <br>-n Hostnames 不将地址解析成主机名。 <br>-h Maximum hops 搜索目标的最大跃点数。 <br>-g Host-list 沿着路由列表释放源路由。 <br>-p Period 在 ping 之间等待的毫秒数。 <br>-q Num_queries 每个跃点的查询数。 <br>-w Time-out 为每次回复所等待的毫秒数。 <br>-T Layer 2 tag 将第 2 层优先级标记（例如，对于 IEEE 802.1p）连接到数据包并 <br>将它发送到路径中的每个网络设备。这有助于标识没有正确配置第 2 层优先级的网络 <br>设备。-T 开关用于测试服务质量 (QoS) 连通性。 <br>-R RSVP test Che检查以确定路径中的每个路由器是否支持&#8220;资源保留协议 (RSVP)&#8221; <br>，此协议允许主机为数据流保留一定量的带宽。 -R 开关用于测试服务质量 (QoS) 连 <br>通性。 </p>
<p>默认的跃点数是 30，并且超时前的默认等待时间是 3 秒。默认时间是 250 毫秒，并 <br>且沿着路径对每个路由器进行查询的次数是 100。 </p>
<p>以下是典型的 pathping 报告。跃点列表后所编辑的统计信息表明在每个独立路由器 <br>上数据包丢失的情况。 </p>
<p><br>D:\\&gt;pathping -n msw </p>
<p>Tracing route to msw [7.54.1.196] <br>over a maximum of 30 hops: <br>0 172.16.87.35 <br>1 172.16.87.218 <br>2 192.68.52.1 <br>3 192.68.80.1 <br>4 7.54.247.14 <br>5 7.54.1.196 </p>
<p>Computing statistics for 125 seconds... <br>Source to Here This Node/Link <br>Hop RTT Lost/Sent = Pct Lost/Sent = Pct Address <br>0 172.16.87.35 <br>0/ 100 = 0% │ <br>1 41ms 0/ 100 = 0% 0/ 100 = 0% 172.16.87.218 <br>13/ 100 = 13% │ <br>2 22ms 16/ 100 = 16% 3/ 100 = 3% 192.68.52.1 <br>0/ 100 = 0% │ <br>3 24ms 13/ 100 = 13% 0/ 100 = 0% 192.68.80.1 <br>0/ 100 = 0% │ <br>4 21ms 14/ 100 = 14% 1/ 100 = 1% 10.54.247.14 <br>0/ 100 = 0% │ <br>5 24ms 13/ 100 = 13% 0/ 100 = 0% 10.54.1.196 </p>
<p>Trace complete. </p>
<p>当运行 pathping 时，在测试问题时首先查看路由的结果。此路径与 tracert 命令所 <br>显示的路径相同。然后 pathping 命令对下一个 125 毫秒显示忙消息（此时间根据跃 <br>点计数变化）。在此期间，pathping 从以前列出的所有路由器和它们之间的链接之间 <br>收集信息。在此期间结束时，它显示测试结果。 </p>
<p>最右边的两栏 This Node/Link Lost/Sent=Pct 和 Address 包含的信息最有用。172 <br>.16.87.218（跃点 1）和 192.68.52.1（跃点 2）丢失 13% 的数据包。 所有其他链 <br>接工作正常。在跃点 2 和 4 中的路由器也丢失寻址到它们的数据包（如 This Node <br>/Link 栏中所示），但是该丢失不会影响转发的路径。 </p>
<p>对链接显示的丢失率（在最右边的栏中标记为 │）表明沿路径转发丢失的数据包。该 <br>丢失表明链接阻塞。对路由器显示的丢失率（通过最右边栏中的 IP 地址显示）表明 <br>这些路由器的 CPU 可能超负荷运行。这些阻塞的路由器可能也是端对端问题的一个因 <br>素，尤其是在软件路由器转发数据包时。<br></p>
<img src ="http://www.cppblog.com/eday/aggbug/35494.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-30 09:40 <a href="http://www.cppblog.com/eday/articles/35494.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DIV与Table布局在大型网站的可用性比较</title><link>http://www.cppblog.com/eday/articles/35302.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Sat, 27 Oct 2007 03:27:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/35302.html</guid><description><![CDATA[<p>　　DIV与TABLE本身并不存在什么优缺点，所谓web标准只是推荐的是正确的使用标签，好比说:DIV用于布局，而TABLE则本来就是转二维数据的。让TABLE做该做的事，并不是说页面里不出现TABLE就是多么多么牛。</p>
<p>　　用DIV进行排版的优势就是我不说，大家应该都比较清楚。DIV是标准，是大势所趋，但并不意味着所有的页面都适合用它来做。</p>
<p>　　中国的门户和国外的有很大的区别，中国网民并不喜欢信息量少的页面，YAHOO到了中国页面上的内容就多了不少，而上次改为简洁的页面后访问量下降的厉害以至于没过几天就又改了回来。正式由于中国的国情造就了搜狐、新浪这样门户。</p>
<p>　　为什么DIV不适合他们?下面我从几个方面来逐一说明:</p>
<p>　　<strong>精简代码:</strong></p>
<p>　　大家都说DIV的布局精简代码，但是用DIV替代TABLE所节约的代码又被CSS(样式)所占用，而这些样式大多用于控制DIV的排版布局。那你会说了，CSS可以放在外部重用啊，要想得到这个问题的答案请往下看。</p>
<p>　　<strong>重用性与下载量:</strong></p>
<p>　　统一使用一个.css的样式表文件，可以实现修改一次，全站修改的效果，这样使得维护的成本更低。但是请大家换一个角度想，如果所有页面在加载时都要访问一个文件，那这个文件每天的下载量，特别时在搜狐、新浪的网站平台上将达到几亿次，这就需要后面有很多台前端web<a class=bluekey href="http://server.chinabyte.com/" target=_blank><u><font color=#0066cc>服务器</font></u></a>在做支撑，那后台的成本无形中也提高了很多。如果后台支撑没有做好，那么页面就会出现花屏，之前所作的工作也是白费。很多人会问，这样的几率太小了。我们所作的工作就是为了避免这一两次意外的发生，如果意外发生了，对于门户后果将是不堪设想的。</p>
<p>　　<strong>HTTP通讯:</strong></p>
<p>　　统一的样式表文件采用外部调用的形式，这样每次加载单个页面都会多一次对服务器的http请求服务器都会增加一次响应，这样对前端web服务器会是很大的消耗。而原来很长时间都是将css和js写在页面前端(大家可以看看sohu和sina的页面，大多都是采用这样的形式)，而不是作为外部调用的形式，也是为了尽量避免给服务器增加消耗。</p>
<p>　　<strong>页面缓存:</strong></p>
<p>　　每次用户访问的页面，都会在浏览器缓存中保存一定时间，以保证用户下次再访问该页面时能够大大提高页面显示速度。而每次修改都会使页面重新下载，对于每个外部导入的样式文件也是如此，如果CSS文件修改，那么访问网站的每一个页面都会重新下载，而以往的将样式写在页面中的方式，只是修改的页面需要重新下载。</p>
<p>　　<strong>兼容性:</strong></p>
<p>　　对于CSS(样式表)并不是所有浏览器的所有版本都支持的很好，比如IE5以前的浏览器对于CSS的支持就不是很好。而现在使用IE5以前版本浏览器的用户不在少数，这样就使得在页面制作的过程中需要针对不同浏览器版本进行测试，以保证兼容性，无形中也增加很多工作量(至少我接触的开发人员制作div页面比table页面的标准时间要长一些)。</p>
<p>　　<strong>横切与延展性:</strong></p>
<p>　　横切——传统的布局方式为了使页面下载的更快，把页面自上而下分成若干个块，但是往往采用DIV进行布局的页面都会出现这样的情况，由于每块中间栏或者其他栏内容条数不固定导致两边栏目没有同时自适应，而出现留白。</p>
<p>　　<strong>原来的页面:</strong></p>
<p>　　<img height=390 alt=点击查看原始尺寸 src="http://homepage.yesky.com/imagelist/06/45/y788980g1rf4.jpg" width=661></p>
<p>　　而在出现内容不固定的情况，页面就会变成下面的样子:</p>
<p>　　<img height=500 alt=点击查看原始尺寸 src="http://homepage.yesky.com/imagelist/06/45/704nyxc5e2rr.gif" width=661></p>
<p>　　相比之下传统的table方式更容易规避这样情况的发生。</p>
<p>　　以上我们只是讨论某一技术在某一领域的可用性，而非技术本身。</p>
<p>　　说了这么多并不是说DIV这种布局方式不好，而是说我们应该正确的看待Table在以内容为基础的大型门户中的作用，而不是人云亦云。之所以DIV的布局方式没有在大型网站应用，不是说门户没有用DIV是技术落后，是里面的人没有前瞻性，而是多种原因决定的。网易之所以全部采用DIV的方式是因为内容并不是他们主攻方向。而对于其他门户来说，这样的决策是要靠时间来验证的。只是现在这个时机还不成熟而已。</p>
<img src ="http://www.cppblog.com/eday/aggbug/35302.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-27 11:27 <a href="http://www.cppblog.com/eday/articles/35302.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MapInfo介绍  </title><link>http://www.cppblog.com/eday/articles/35228.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Fri, 26 Oct 2007 03:17:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/35228.html</guid><description><![CDATA[<div><font color=#0000ff>MapInfo</font>是一个开发桌面地图软件及GIS分析系统的公司。其旗下的多种软件产品都是用来支持GIS的二次开发的。刚刚接触MapInfo的开发者一般都会被这些产品的关系弄的晕头转向。下面的内容大部分来自于MapInfo公司的官方介绍；也有一部分纯属个人理解，可能有错误。
<p>&nbsp;&nbsp;&nbsp; <font color=#ff0000>MapInfo Professional</font>是一套基于Windows平台的地图化信息解决方案。可以方便、直观的展现数据和地理信息的关系，其周密而详细的数据分析能力，可帮助用户从地理的角度更好地理解商业信息，辅助用户做出更具洞察力的分析和决策。<br>&nbsp;&nbsp;&nbsp; <font color=#ff0000>MapInfo MapX</font>是功能强大的ActiveX 组件式GIS开发工具，与VB、VC、PB、Delphi等应用开发平台无缝连接，可以很方便地将地图功能集成到各类商业应用中。MapInfo MapX可以说是单机版的GIS开发工具。<br>&nbsp;&nbsp;&nbsp; <font color=#ff0000>MapInfo MapXtreme for Windows</font>。通过MapXtreme，用户可以在Internet/Intranet上发布基于电子地图的应用系统。所有的最终用户只需在自己的机器上安装浏览器即可访问存放在服务器端的空间数据，用户可以很方便地对地图进行放大、缩小、漫游、查询、统计等操作。它支持ASP。可以说MapXtreme系列是在MapX的基础上开发出来的支持B/S结构的产品。<br>&nbsp;&nbsp;&nbsp; <font color=#ff0000>MapInfo MapXtreme Java Edition</font>是用于Internet或企业内部Intranet的由JAVA编写的地图应用服务器，是MapInfo MapXtreme技术和JAVA技术的有机结合，向应用开发者提供了一套高度可视化的、直观的组件，方便开发者将地图功能集成到任何Web应用中。<br>&nbsp;&nbsp;&nbsp; <font color=#ff0000>MapInfo MapXtreme 2004</font>是MapInfo为了支持Microsoft公司的.NET框架，重新设计MapX和MapXtreme for Windows代码库体系结构的新产品。MapXtreme 2004是开发地图和可地图化应用程序的理想开发环境。它与Visual Studio .NET平台无缝结合，支持C#和ASP.NET。<br>&nbsp;&nbsp;&nbsp; <font color=#ff0000>MapInfo MapX Mobile</font>是一个可以用在手持电脑上的MapX平台，它是为Pocket PC开发用户化地图应用软件所开发的工具。用 MapX Mobile开发的应用软件支持Pocket PC的Windows CE操作系统，并可以单独在设备上运行，无需无线连接。它是 MapX and MapXtreme for Windows的自然延伸，用 MapX Mobile开发的应用软件运行在移动的Pocket PC上，显示来自MapXtreme的地图信息。<br>&nbsp;&nbsp;&nbsp; <font color=#ff0000>MapInfo MapXtend</font>是为开发者提供的，用于为无线设备进行地图应用开发的工具，用户可以通过该产品创建基于空间位置信息的应用，从而通过手持设备获取各种基于空间位置的数据信息，帮助客户在任意时间和地点与信息中心进行适当的信息交换。MapXtend是MapXtrem的自然延伸，通过MapXtend，可以为MapXtreme for Java的顾客提供基于无线手持设备的空间信息浏览解决方案。服务器端基于J2EE，客户端基于J2ME。<br>&nbsp;&nbsp;&nbsp; <font color=#ff0000>MapInfo Spatialware</font>是MapInfo公司最新推出的空间数据库服务器，目前已发布了基于Oracle、DB2、MS SQL Server、Informix数据库的各种版本。它的主要作用是能够把复杂的MapInfo地图对象存入大型数据库中，并能为其建立空间数据索引，从而在数据库服务器上实现对属性数据和空间图形对象数据的统一管理。前端用户可以象访问普通数据库字段一样访问这些图形对象字段，开发出完整的C/S、B/S模式下的MapInfo应用程序。<br>&nbsp;&nbsp;&nbsp; <font color=#ff0000>MapInfo Routing J Server</font> 是一个可以定制的空间信息应用系统，用来为人员、产品和资源安排行程和路线。使用Routing J Server，可以迅速建立起高度安全和复杂的应用系统，用来处理大量的路线和路由选择计算请求；计算两点间的最短路径或者最迅速的路线，并返回详细的行车路线说明。Routing J Server采用Java进行开发。</p>
</div>
<img src ="http://www.cppblog.com/eday/aggbug/35228.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-26 11:17 <a href="http://www.cppblog.com/eday/articles/35228.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C# 修改IP、网关、DNS</title><link>http://www.cppblog.com/eday/articles/35085.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Wed, 24 Oct 2007 13:58:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/35085.html</guid><description><![CDATA[<font color=#339966>1、在 &#8220;解决方案资源管理器&#8221; 右击 &#8220;引用&#8221; 添加 &#8220;System.Management&#8221; 的引用。<br>2、添加 &#8220;using System.Management;&#8221;。 <br><br></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static void SetNetworkAdapter()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ManagementBaseObject inPar = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ManagementBaseObject outPar = null;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ManagementObjectCollection moc = mc.GetInstances();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (ManagementObject mo in moc)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!(bool)mo["IPEnabled"])<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#339966> //设置ip地址和子网掩码 </font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inPar = mo.GetMethodParameters("EnableStatic");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inPar["IPAddress"] = new string[] { "192.168.16.248", "192.168.16.249" };// 1.备用 2.IP<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inPar["SubnetMask"] = new string[] { "255.255.255.0", "255.255.255.0" };<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; outPar = mo.InvokeMethod("EnableStatic", inPar, null);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#339966> //设置网关地址 </font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inPar = mo.GetMethodParameters("SetGateways");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inPar["DefaultIPGateway"] = new string[] { "192.168.16.2", "192.168.16.254" }; <font color=#339966>// 1.网关;2.备用网关</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; outPar = mo.InvokeMethod("SetGateways", inPar, null);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color=#339966>&nbsp;&nbsp; //设置DNS </font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inPar = mo.GetMethodParameters("SetDNSServerSearchOrder");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inPar["DNSServerSearchOrder"] = new string[] { "211.97.168.129", "202.102.152.3" }; <font color=#339966>// 1.DNS 2.备用DNS</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; outPar = mo.InvokeMethod("SetDNSServerSearchOrder", inPar, null);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
<img src ="http://www.cppblog.com/eday/aggbug/35085.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-24 21:58 <a href="http://www.cppblog.com/eday/articles/35085.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用CPU时间戳进行高精度计时</title><link>http://www.cppblog.com/eday/articles/35033.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 23 Oct 2007 14:17:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/35033.html</guid><description><![CDATA[<p>　　对关注性能的程序开发人员而言，一个好的计时部件既是益友，也是良师。计时器既可以作为程序组件帮助程序员精确的控制程序进程，又是一件有力的调试武器，在有经验的程序员手里可以尽快的确定程序的性能瓶颈，或者对不同的算法作出有说服力的性能比较。<br><br>　　在Windows平台下，常用的计时器有两种，一种是timeGetTime多媒体计时器，它可以提供毫秒级的计时。但这个精度对很多应用场合而言还是太粗糙了。另一种是QueryPerformanceCount计数器，随系统的不同可以提供微秒级的计数。对于实时图形处理、多媒体数据流处理、或者实时系统构造的程序员，善用QueryPerformanceCount/QueryPerformanceFrequency是一项基本功。<br><br>　　本文要介绍的，是另一种直接利用Pentium CPU内部时间戳进行计时的高精度计时手段。以下讨论主要得益于《Windows图形编程》一书，第15页－17页，有兴趣的读者可以直接参考该书。关于RDTSC指令的详细讨论，可以参考Intel产品手册。本文仅仅作抛砖之用。<br>　　在Intel Pentium以上级别的CPU中，有一个称为&#8220;时间戳（Time Stamp）&#8221;的部件，它以64位无符号整型数的格式，记录了自CPU上电以来所经过的时钟周期数。由于目前的CPU主频都非常高，因此这个部件可以达到纳秒级的计时精度。这个精确性是上述两种方法所无法比拟的。<br><br>　　在Pentium以上的CPU中，提供了一条机器指令RDTSC（Read Time Stamp Counter）来读取这个时间戳的数字，并将其保存在EDX:EAX寄存器对中。由于EDX:EAX寄存器对恰好是Win32平台下C++语言保存函数返回值的寄存器，所以我们可以把这条指令看成是一个普通的函数调用。像这样：<br><br>inline unsigned __int64 GetCycleCount()<br>{<br>__asm RDTSC<br>}<br><br>但是不行，因为RDTSC不被C++的内嵌汇编器直接支持，所以我们要用_emit伪指令直接嵌入该指令的机器码形式0X0F、0X31，如下：<br><br>inline unsigned __int64 GetCycleCount()<br>{<br>__asm _emit 0x0F<br>__asm _emit 0x31<br>}<br><br>以后在需要计数器的场合，可以像使用普通的Win32 API一样，调用两次GetCycleCount函数，比较两个返回值的差，像这样：<br><br>unsigned long t;<br>t = (unsigned long)GetCycleCount();<br>//Do Something time-intensive ...<br>t -= (unsigned long)GetCycleCount();<br><br>　　《Windows图形编程》第15页编写了一个类，把这个计数器封装起来。有兴趣的读者可以去参考那个类的代码。作者为了更精确的定时，做了一点小小的改进，把执行RDTSC指令的时间，通过连续两次调用GetCycleCount函数计算出来并保存了起来，以后每次计时结束后，都从实际得到的计数中减掉这一小段时间，以得到更准确的计时数字。但我个人觉得这一点点改进意义不大。在我的机器上实测，这条指令大概花掉了几十到100多个周期，在Celeron 800MHz的机器上，这不过是十分之一微秒的时间。对大多数应用来说，这点时间完全可以忽略不计；而对那些确实要精确到纳秒数量级的应用来说，这个补偿也过于粗糙了。<br>这个方法的优点是：<br><br>1.高精度。可以直接达到纳秒级的计时精度（在1GHz的CPU上每个时钟周期就是一纳秒），这是其他计时方法所难以企及的。<br><br>2.成本低。timeGetTime 函数需要链接多媒体库winmm.lib，QueryPerformance* 函数根据MSDN的说明，需要硬件的支持（虽然我还没有见过不支持的机器）和KERNEL库的支持，所以二者都只能在Windows平台下使用（关于DOS平台下的高精度计时问题，可以参考《图形程序开发人员指南》，里面有关于控制定时器8253的详细说明）。但RDTSC指令是一条CPU指令，凡是i386平台下Pentium以上的机器均支持，甚至没有平台的限制（我相信i386版本UNIX和Linux下这个方法同样适用，但没有条件试验），而且函数调用的开销是最小的。<br><br>3.具有和CPU主频直接对应的速率关系。一个计数相当于1/(CPU主频Hz数)秒，这样只要知道了CPU的主频，可以直接计算出时间。这和QueryPerformanceCount不同，后者需要通过QueryPerformanceFrequency获取当前计数器每秒的计数次数才能换算成时间。<br>这个方法的缺点是：<br><br>1.现有的C/C++编译器多数不直接支持使用RDTSC指令，需要用直接嵌入机器码的方式编程，比较麻烦。<br><br>2.数据抖动比较厉害。其实对任何计量手段而言，精度和稳定性永远是一对矛盾。如果用低精度的timeGetTime来计时，基本上每次计时的结果都是相同的；而RDTSC指令每次结果都不一样，经常有几百甚至上千的差距。这是这种方法高精度本身固有的矛盾。<br><br>关于这个方法计时的最大长度，我们可以简单的用下列公式计算：<br>自CPU上电以来的秒数 = RDTSC读出的周期数 / CPU主频速率（Hz）<br>64位无符号整数所能表达的最大数字是1.8&#215;10^19，在我的Celeron 800上可以计时大约700年（书中说可以在200MHz的Pentium上计时117年，这个数字不知道是怎么得出来的，与我的计算有出入）。无论如何，我们大可不必关心溢出的问题。<br>下面是几个小例子，简要比较了三种计时方法的用法与精度<br><br>//Timer1.cpp 使用了RDTSC指令的Timer类//KTimer类的定义可以参见《Windows图形编程》P15<br>//编译行：CL Timer1.cpp /link USER32.lib<br>#include &lt;stdio.h&gt;<br>#include "KTimer.h"<br><br>main()<br>{<br>&nbsp; unsigned t;<br>&nbsp; KTimer timer;<br>&nbsp; timer.Start();<br>&nbsp; Sleep(1000);<br>&nbsp; t = timer.Stop();<br>&nbsp; printf("Lasting Time: %d\n",t);<br>}<br><br>//Timer2.cpp 使用了timeGetTime函数<br>//需包含&lt;mmsys.h&gt;，但由于Windows头文件错综复杂的关系<br>//简单包含&lt;windows.h&gt;比较偷懒：）<br>//编译行：CL timer2.cpp /link winmm.lib <br>#include &lt;windows.h&gt;<br>#include &lt;stdio.h&gt;<br><br>main()<br>{<br>&nbsp; DWORD t1, t2;<br>&nbsp; t1 = timeGetTime();<br>&nbsp; Sleep(1000);<br>&nbsp; t2 = timeGetTime();<br>&nbsp; printf("Begin Time: %u\n", t1);<br>&nbsp; printf("End Time: %u\n", t2);<br>&nbsp; printf("Lasting Time: %u\n",(t2-t1));<br>}<br><br>//Timer3.cpp 使用了QueryPerformanceCounter函数<br>//编译行：CL timer3.cpp /link KERNEl32.lib<br>#include &lt;windows.h&gt;<br>#include &lt;stdio.h&gt;<br><br>main()<br>{<br>&nbsp; LARGE_INTEGER t1, t2, tc;<br>&nbsp; QueryPerformanceFrequency(&amp;tc);<br>&nbsp; printf("Frequency: %u\n", tc.QuadPart);<br>&nbsp; QueryPerformanceCounter(&amp;t1);<br>&nbsp; Sleep(1000);<br>&nbsp; QueryPerformanceCounter(&amp;t2);<br>&nbsp; printf("Begin Time: %u\n", t1.QuadPart);<br>&nbsp; printf("End Time: %u\n", t2.QuadPart);<br>&nbsp; printf("Lasting Time: %u\n",( t2.QuadPart- t1.QuadPart));<br>}<br><br>////////////////////////////////////////////////<br>//以上三个示例程序都是测试1秒钟休眠所耗费的时间<br>file://测/试环境：Celeron 800MHz / 256M SDRAM <br>// Windows 2000 Professional SP2<br>// Microsoft Visual C++ 6.0 SP5<br>////////////////////////////////////////////////<br><br>以下是Timer1的运行结果，使用的是高精度的RDTSC指令<br>Lasting Time: 804586872<br><br>以下是Timer2的运行结果，使用的是最粗糙的timeGetTime API<br>Begin Time: 20254254<br>End Time: 20255255<br>Lasting Time: 1001<br><br>以下是Timer3的运行结果，使用的是QueryPerformanceCount API<br>Frequency: 3579545<br>Begin Time: 3804729124<br>End Time: 3808298836<br>Lasting Time: 3569712<br><br>对于wince, 只有采用KTimer那种方式，因为QueryPerformanceFrequency，timeGetTime均不支持。　</p>
<img src ="http://www.cppblog.com/eday/aggbug/35033.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-23 22:17 <a href="http://www.cppblog.com/eday/articles/35033.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>“变速齿轮”研究手记</title><link>http://www.cppblog.com/eday/articles/35029.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 23 Oct 2007 13:43:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/35029.html</guid><description><![CDATA[注意：如果你看了本文，对我们这个软件有兴趣，请到我们的主页www.vrbrothers.com下载。<br><br>注：为节省篇幅，本文对一些计算机术语直接使用而没有作详细的解释，读者若有不熟悉之处，建议参考清华大学出版社出版，周明德编著的《微型计算机系统原理及应用》一书中关于8253/8254定时器和x86保护模式的相应章节。<br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#8220;变速齿轮&#8221;研究手记<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; 也许是我孤陋寡闻吧，说出来不怕您笑话，对于&#8220;变速齿轮&#8221;这样著名的软件，我一直到五天前，也就是2001年2月28号才第一次听说。我有几个同学很喜欢玩图形MUD，整天见了面就在一起切磋&#8220;泥&#8221;技。我对MUD本身并没有多大兴趣，但是那天早上偶尔听他们说某个MUD站点明文规定严禁使用&#8220;齿轮&#8221;，这才好奇地问他们什么是&#8220;齿轮&#8221;。别人告诉我，&#8220;齿轮&#8221;是一个软件，能对Windows下的游戏加速，他们在玩MUD时就依靠这个软件作弊。这不禁令我一头雾水，能让Windows游戏改变速度，太神奇了！<br>&nbsp; &nbsp; 我一贯对技术很有兴趣，听说有这么一个神奇的软件，当然要想想它是怎么实现的。这个软件看起来并不复杂，我原以为一个早自习好好琢磨琢磨就行，可是我想了好几节课，始终不得其要领。说来也巧，我们这学期有一面必修课是Linux内核原理分析，这几天正好学到了进程调度，老师说，当一个时钟中断发生的时候，操作系统要做很多事情，比如必要时要重新调度进程从而实现抢先式多任务，还要更新系统时钟......慢着，我突发奇想，如果让时钟中断产生的更快，会发生什么事情呢？<br>&nbsp; &nbsp; 我们已经学过&#8220;微机原理&#8221;这门课程，我知道让时钟中断产生的更快不是难事，以前我就用DOS下的汇编语言写过这样的程序，这是我们当时的作业。可是我以前的程序在Windows下虽然可以运行，但并不能对Windows系统加速，道理很显然：Windows9x是使用x86虚拟机的机制来兼容DOS程序的，我的程序只能改变虚拟机，就是那个黑窗口的时钟中断。<br>&nbsp; &nbsp; 于是我试图把以前的DOS程序搬到32位环境中。用VC内嵌汇编做这件事再合适不过了，在一个VC程序框架中加上一个__asm，然后只管把以前的汇编程序往里贴就行。我满怀希望地运行这样一个拼凑出来的怪物，结果，出现了一个大家都很熟悉的&#8220;该程序执行了非法操作&#8221;，我的试验以失败告终。<br>&nbsp; &nbsp; 后来冷静下来仔细想想，这次失败的原因是显然的。Windows作为一个复杂的32位操作系统，如果能让你随便对硬件进行操作，那也许运行不了几个程序就崩溃了。但是如何绕过操作系统去操作硬件呢？我首先想到了vxd，编写一个驱动程序肯定可以操作硬件，但是，很可惜，我不会设计驱动程序。于是我想到了以前看到的CIH的源码，CIH没有写vxd，却能操作硬件去烧毁BIOS，陈盈豪真是太伟大了，他的程序精巧之处我至今记忆犹新。于是我模仿他的技术，修改IDT表，创建一个中断门，然后发生中断，进入ring0，现在我可以做任何事情了，按照以前的DOS程序那样，往8253定时器里写一个控制字，再分两次写入新的时钟中断发生频率，一切顺利！（详细技术请您参考我的&#8220;兄弟变速器&#8221;源码）我看到VC编辑区的光标疯狂的闪烁；双击已经失效了，因为Windows认为我双击的时间间隔太长；Windows任务栏右方的时间飞快跳动，应该说，我已经成功了。<br>&nbsp; &nbsp; 当时我想当然的以为&#8220;变速齿轮&#8221;的原理也是如此，可是当我从同学那里把&#8220;齿轮&#8221;拷来并研究时，发现Windows的时钟并不变快，而游戏速度照样可以加上去，也就是说，&#8220;齿轮&#8221;采用了与我的程序不同的技术，是什么技术呢？我决定继续研究。<br>&nbsp; &nbsp; 我访问了&#8220;变速齿轮&#8221;的主页，这个主页上有一个&#8220;你问我答&#8221;的栏目，由&#8220;齿轮&#8221;的作者王荣先生进行技术支持。我试图在这里找到一些关于&#8220;齿轮&#8221;的技术细节，但是很可惜，没有找到，王荣先生只是告诉大家这个程序不能用VB编写等等根本连皮毛也不涉及的问题，好不容易见到一个外国人问能不能公布源代码，其实这也是我想问的，但是王荣先生明确表示不行，这不禁令我感到非常失望。<br>&nbsp; &nbsp; 我也想过写信去索取原码，也许他不向外国人公布，中国人可不一定。但是咱们&#8220;臭老九&#8221;最爱一个面子，我实在拉不下脸去问。这时已经是晚上10点了，我决定祭出SoftIce，用一夜时间去研究他的程序。<br>&nbsp; &nbsp; 当时使用的工具是SoftIce，WD32ASM和VC，手边两本参考书是《微型计算机系统原理及应用》和《Linux操作系统内核分析》（都是我们的课本，呵呵）。<br>&nbsp; &nbsp; 起初，&#8220;变速齿轮&#8221;0.2版的一个叫hook.dll的文件很大程度上吸引了我的注意力，我怀疑他使用Windows消息钩子实现变速，消息钩子我很熟悉，但我把MSDN上面关于钩子的介绍看了好久，也没有想出它和变速有什么联系，这时偶然看了一下在王荣先生的主页上得到的&#8220;变速齿轮&#8221;0.1版，才发现老版本中并没有这个文件，也就是说，我只需要反汇编他的主程序就够了，于是，二话不说，用WD32ASM先把0.1版的&#8220;齿轮&#8221;给拆了，汇编代码5000多行，并不算多。<br>&nbsp; &nbsp; 我是从这个程序的导入函数着手的，以前编程时用于定时的SetTimer，timeGetTime，timeSetEvent等等这里都导入了，看看它们被引用的地方，我发现这些函数都是集中出现的，而且大都以这样的形式出现：<br>&nbsp; &nbsp; * Reference To: WINMM.timeGetTime, Ord:0098h<br>&nbsp; &nbsp; :00401F3E 8B0D64424000&nbsp; &nbsp; &nbsp; &nbsp; mov ecx, dword ptr [00404264]<br>&nbsp; &nbsp; :00401F44 8B11&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mov edx, dword ptr [ecx]<br>&nbsp; &nbsp; 也就是说，他并没有调用这些函数，只是取得了函数的入口地址，保存在ecx中，然后又根据这个入口地址得到了函数的前面几个字节，保存在edx中。<br>&nbsp; &nbsp; 这让我想到了前些日子在CSDN上面和别人讨论的Hook API的原理，当时我还索取了一份Hook API的例程，如果我要Hook这里的函数timeGetTime，修改ecx中的地址或者修改edx处的头几条指令就行，用汇编语言写，与上面看到的这段代码类似。<br>&nbsp; &nbsp; 为了测试&#8220;齿轮&#8221;是不是要Hook这里的timeGetTime，我自己编写了一个很简单的小程序，调用timeGetTime，每秒钟显示一个数字。用&#8220;齿轮&#8221;进行加速后，果然显示的速度快多了。再用SoftIce跟进这个timeGetTime函数，第一条指令变成一个跳转，这充分说明&#8220;齿轮&#8221;确实Hook了这几个API，不难猜测，他要改变函数的返回值，也就是说在timeGetTime结束时还要再跳入&#8220;齿轮&#8221;自身的代码，耐心跟下去，我发现回到timeGetTime时栈里多压了一个地址，这样，当timeGetTime用ret指令返回时，先返回&#8220;齿轮&#8221;的代码（这个思想确实很巧），返回值经过处理后，才跳回我的应用程序。至于怎么处理这个返回值就简单了，改到原先的2倍，应用程序速度也就提高了2倍。<br>&nbsp; &nbsp; 回头再看WD32ASM反汇编的代码，我又发现在Hook API前面的不远处使用了一次SGDT指令和两次SLDT指令，这是x86保护方式的特有指令，用于获得全局描述符表，进一步得到局部描述符表，这段代码引起了我的兴趣，用SoftIce跟进去，往下走几步，一边跟一边猜，大致整理出了这样的思路：<br>&nbsp; &nbsp; 1.创建一个内存映射，把自己的代码映射到0x80000000以上的地方，在Win9x下，这块虚存是所有进程共享的。<br>&nbsp; &nbsp; 2.先得到局部描述符表的地址，然后利用这张表修改代码段的特权级。<br>&nbsp; &nbsp; 3.用局部描述符表创建一个调用门，在x86的保护模式下要进入ring0必须通过门来进行，CIH是用中断门完成的，这里用调用门完成，异曲同工。<br>&nbsp; &nbsp; 4.保存几个关键函数前六个字节，改为一条跳转指令，跳到自己已经映射到高端的代码。<br>&nbsp; &nbsp; 5.发生函数调用时进入自己的代码，通过调用门进入ring0，恢复函数开头的几个字节，修改返回值。<br>&nbsp; &nbsp; 这时已经是凌晨5点了，既然主要思想已经掌握，我也就没有细看这段代码，8点钟还要上课，睡觉去也。<br>&nbsp; &nbsp; 回头想想，我认为王荣先生的代码还有几点值得推敲之处：<br>&nbsp; &nbsp; 1.如果要Hook API，一定要改变函数的第一条指令吗？如果仅仅改变函数的入口地址，不是既容易编也容易调试吗？<br>&nbsp; &nbsp; 2.即使要改变函数第一条指令，一定要进入ring0吗？<br>&nbsp; &nbsp; 3.即使要进入ring0，使用中断门不是比用调用门更方便吗？<br>&nbsp; &nbsp; 当然，按照王荣先生在他的主页上的说法，&#8220;变速齿轮&#8221;0.1版是他在三年前即1997年写的，那时Windows95刚刚出来两年，能有这样的技术已经难能可贵了，这里对王荣先生的钻研精神表示由衷的敬佩。<br>&nbsp; &nbsp; 在我研究出&#8220;变速齿轮&#8221;的原理后三天，我以自己原先的研究结果为核心，编写出了&#8220;兄弟变速器&#8221;的最初版本，不用&#8220;变速齿轮&#8221;的技术是因为我认为我的技术更优越，何况也没有拾人牙慧之嫌了 ^_^<br>&nbsp; &nbsp; 最后再次对王荣先生表示感谢，这样精彩的创意值得我们敬佩。
<img src ="http://www.cppblog.com/eday/aggbug/35029.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-23 21:43 <a href="http://www.cppblog.com/eday/articles/35029.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>变速齿轮核心实现</title><link>http://www.cppblog.com/eday/articles/35030.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 23 Oct 2007 13:43:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/35030.html</guid><description><![CDATA[<p>　变速齿轮通过修改API函数GETTICKCOUNT和TIMEGETTIME骗过了游戏和程序的定时器导致游戏和程序速度看起来被改变。</p>
<p>下面以GETTICKCOUNT为例进行分析：原本的GETTICKCOUNT汇编： <br>kernel32!gettickcount mov gs,[bffcaea18]</p>
<p>mov eax,gs:[00000000]</p>
<p>sub edx,edx</p>
<p>mov gs,dx</p>
<p>ret</p>
<p>变速齿轮修改后的GETTICKCOUNT汇编：</p>
<p>kernel32!gettickcount</p>
<p>这里是关键--&gt;jmp 840500d9（840500d9并不是绝对的）</p>
<p>add [eax],al </p>
<p>add [ecx+00000000],ah </p>
<p>sub edx,edx </p>
<p>mov gs,dx </p>
<p>ret </p>
<p>可以看出变速齿轮修改了gettickcount的代码，当游戏和程序使用gettickcount时就会自动跳转到840500d9处执行。</p>
<p>再看看840500d9处的代码汇编：</p>
<p>840500d9:CLI </p>
<p>push ebp</p>
<p>mov ebp,esp </p>
<p>push ebx </p>
<p>push ecx </p>
<p>push edx</p>
<p>push esi</p>
<p>push edi</p>
<p>call 840500e7</p>
<p>840500e7:pop edi</p>
<p>xor di,di</p>
<p>mov esi,edi</p>
<p>add esi,00402051</p>
<p>sub esi,00401f0b</p>
<p>push esi </p>
<p>call edi</p>
<p>call 84050101</p>
<p>84050101:pop edi</p>
<p>xor di,di </p>
<p>call [edi+0000fef0] </p>
<p>call 84050110 </p>
<p>84050110:sub eax,[edi+0000ff30] </p>
<p>mul dword,ptr[edi+0000ff30] </p>
<p>mov ebx,00100000 </p>
<p>div ebx </p>
<p>add eax,[edi+0000fe20] </p>
<p>push eax </p>
<p>mov eax,00402072 </p>
<p>sub eax,00401f08 </p>
<p>add eax,edi </p>
<p>push eax </p>
<p>call edi </p>
<p>pop eax </p>
<p>pop edi </p>
<p>pop esi </p>
<p>pop edx </p>
<p>pop ecx </p>
<p>pop ebx </p>
<p>pop ebp </p>
<p>sil </p>
<p>ret </p>
<p>以上正是变速齿轮变速的核心所在。（GETTICKCOUNT返回的是EAX的值你可以对EAX进行跟踪）</p>
<p>　　下面说一下变速齿轮挂接API的方法：首先变速齿轮在MMF区（WIN9X/ME）申请一块内存，把上面的代码从程序中移到该内存。使用修改描述符的方法从应用程序级跳到核心级（具体可查看《电脑编程技巧与维护》2000年第6期34页）修改GETTICKCOUNT开头的代码使之指向申请的内存的首地址实现挂接。</p>
<img src ="http://www.cppblog.com/eday/aggbug/35030.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-23 21:43 <a href="http://www.cppblog.com/eday/articles/35030.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>XHTML1.0标签列表</title><link>http://www.cppblog.com/eday/articles/34903.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 23 Oct 2007 01:54:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/34903.html</guid><description><![CDATA[<p>XHTML1.0 标签参考,按功能排列<span></span></p>
<ul>
    <li>NN: 表明哪个早期Netscape版本支持这个标签
    <li>IE: 表明哪个早期Internet Explorer版本支持这个标签
    <li>DTD: 表明符合XHTML 1.0 DTD 何级别的定义 . S=Strict（严格）, T=Transitional（过渡）, and F=Frameset（框架） </li>
</ul>
<table>
    <tbody>
        <tr>
            <th>开始标签</th>
            <th>用途（Purpose）</th>
            <th>NN</th>
            <th>IE</th>
            <th>DTD</th>
        </tr>
        <tr>
            <td colSpan=5><strong>基本标签</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;!DOCTYPE&gt;</td>
            <td>文档类型（Defines the document type）</td>
            <td></td>
            <td></td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;html&gt;</td>
            <td>html文档（Defines a html document）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;body&gt;</td>
            <td>body元素（Defines the body element）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;h1&gt; to &lt;h6&gt;</td>
            <td>标题1 — 标题6（Defines header 1 to header 6）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;p&gt;</td>
            <td>段落（Defines a paragraph）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;br /&gt;</td>
            <td>换行（Inserts a single line break）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;hr /&gt;</td>
            <td>水平线（Defines a horizontal rule）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;!&#8211;&#8230;&#8211;&gt;</td>
            <td>注释（Defines a comment）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>Char Format</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;b&gt;</td>
            <td>粗体文本（Defines bold text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;font&gt;</td>
            <td>文字的外观，大小和颜色（Defines the font face, size, and color of text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td>&lt;i&gt;</td>
            <td>文本为斜体（Defines italic text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;em&gt;</td>
            <td>文本为重要（Defines emphasized text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;big&gt;</td>
            <td>文本增大（Defines big text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;strong&gt;</td>
            <td>文本为非常重要（Defines strong text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;small&gt;</td>
            <td>文本缩小（Defines small text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;sup&gt;</td>
            <td>文本上标（Defines superscripted text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;sub&gt;</td>
            <td>文本下标（Defines subscripted text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;bdo&gt;</td>
            <td>文本输出顺序（Defines the direction of text display）</td>
            <td>6.2</td>
            <td>5.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;u&gt;</td>
            <td>文本下划线（Defines underlined text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>输出</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;pre&gt;</td>
            <td>预先格式（保留文件中空格的大小）（Defines preformatted text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;code&gt;</td>
            <td>码（显示源码用）（Defines computer code text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;tt&gt;</td>
            <td>打印机字体（Defines teletype text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;kbd&gt;</td>
            <td>键盘（Defines keyboard text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;dfn&gt;</td>
            <td>定义（Defines a definition term）</td>
            <td>?</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;var&gt;</td>
            <td>变数（Defines a variable）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;samp&gt;</td>
            <td>样本（Defines sample computer code）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;xmp&gt;</td>
            <td>不赞成使用，使用&lt;pre&gt;代替（Deprecated. Defines preformatted text. Use &lt;pre&gt; instead）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td></td>
        </tr>
        <tr>
            <td colSpan=5><strong>结构性定义</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;acronym&gt;</td>
            <td>只取首字母的缩写词（Defines an acronym）</td>
            <td>6.2</td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;abbr&gt;</td>
            <td>缩写（Defines an abbreviation）</td>
            <td>6.2</td>
            <td>?</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;address&gt;</td>
            <td>地址（Defines an address element）</td>
            <td>4.0</td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;blockquote&gt;</td>
            <td>引文区块（Defines an long quotation）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;center&gt;</td>
            <td>句中对齐（Defines centered text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td>&lt;q&gt;</td>
            <td>引用短语（Defines a short quotation）</td>
            <td>6.2</td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;cite&gt;</td>
            <td>引文（Defines a citation）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;ins&gt;</td>
            <td>插入（Defines inserted text）</td>
            <td>6.2</td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;del&gt;</td>
            <td>删除（Defines deleted text）</td>
            <td>6.2</td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;s&gt;</td>
            <td>删除线（Defines strikethrough text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td>&lt;strike&gt;</td>
            <td>删除线（Defines strikethrough text）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>链接</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;a&gt;</td>
            <td>链接（Defines an anchor）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;link&gt;</td>
            <td>资源参考（Defines a resource reference） </td>
            <td>4.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>框架</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;frame&gt;</td>
            <td>定义个别视框（Defines a sub window (a frame)）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>F</td>
        </tr>
        <tr>
            <td>&lt;frameset&gt;</td>
            <td>视框格式总定义（Defines a set of frames）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>F</td>
        </tr>
        <tr>
            <td>&lt;noframes&gt;</td>
            <td>无视框时的内容（Defines a noframe section）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td>&lt;iframe&gt;</td>
            <td>定义嵌入视图（Defines an inline sub window (frame)）</td>
            <td>6.0</td>
            <td>4.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>输入</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;form&gt;</td>
            <td>定义表单（Defines a form）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;input /&gt;</td>
            <td>定义输入域（Defines an input field）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;textarea&gt;</td>
            <td>输入区换行方式（Defines a text area）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;button&gt;</td>
            <td>按钮（Defines a push button）</td>
            <td>6.2</td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;select&gt;</td>
            <td>下拉式选单（Defines a selectable list）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;optgroup&gt;</td>
            <td>选项组（Defines an option group）</td>
            <td>6.0</td>
            <td>6.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;option&gt;</td>
            <td>列表选项（Defines an item in a list box）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;label&gt;</td>
            <td>标签（用于表单控制）（Defines a label for a form control）</td>
            <td>6.2</td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;fieldset&gt;</td>
            <td>域（Defines a fieldset）</td>
            <td>6.2</td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;legend&gt;</td>
            <td>域标题（Defines a title in a fieldset）</td>
            <td>6.2</td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;isindex&gt;</td>
            <td>不建议使用（可搜寻，使用input代替）（Deprecated. Defines a single-line input field. Use &lt;input&gt; instead）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>列举</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;ul&gt;</td>
            <td>无次序式列举（Defines an unordered list）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;ol&gt;</td>
            <td>有次序式列举（Defines an ordered list）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;li&gt;</td>
            <td>每条项目列表（Defines a list item）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;dir&gt;</td>
            <td>目录式列举（Defines a directory list）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td>&lt;dl&gt;</td>
            <td>定义式列举（Defines a definition list）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;dt&gt;</td>
            <td>定义项目（Defines a definition term）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;dd&gt;</td>
            <td>定义说明（Defines a definition description）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;menu&gt;</td>
            <td>菜单列表（Defines a menu list）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>图片</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;img /&gt;</td>
            <td>图片（Defines an image）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;map&gt;</td>
            <td>图片地图（Defines an image map）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;area /&gt;</td>
            <td>图片热点（Defines an area inside an image map）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>表格</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;table&gt;</td>
            <td>表格（Defines a table）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;caption&gt;</td>
            <td>表格抬头（Defines a table caption）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;th&gt;</td>
            <td>表格标题（Defines a table header）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;tr&gt;</td>
            <td>行（Defines a table row）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;td&gt;</td>
            <td>单元格（列）（Defines a table cell）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;thead&gt;</td>
            <td>定义表格头（Defines a table header）</td>
            <td></td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;tbody&gt;</td>
            <td>定义表格主体（Defines a table body）</td>
            <td></td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;tfoot&gt;</td>
            <td>定义表格脚（Defines a table footer）</td>
            <td></td>
            <td>4.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;col&gt;</td>
            <td>定义特有特征（Defines attributes for table columns）</td>
            <td></td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;colgroup&gt;</td>
            <td>定义特征集合（Defines groups of table columns）</td>
            <td></td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>样式</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;style&gt;</td>
            <td>样式定义（Defines a style definition）</td>
            <td>4.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;div&gt;</td>
            <td>在文档中定义一个区域（Defines a section in a document）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;span&gt;</td>
            <td>在文档中定义一个区域（Defines a section in a document）</td>
            <td>4.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>头信息</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;head&gt;</td>
            <td>定语关于文档的信息（Defines information about the document）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;title&gt;</td>
            <td>定义文档标题（Defines the document title）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;meta&gt;</td>
            <td>定义背景资讯（Defines meta information）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;base /&gt;</td>
            <td>基本文档中所有链接的基准（Defines a base URL for all the links in a page）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;basefont /&gt;</td>
            <td>定义基本字体（Defines a base font）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td colSpan=5><strong>脚本、引用外部对象相关</strong>&nbsp;&nbsp;&nbsp;&nbsp;</td>
        </tr>
        <tr>
            <td>&lt;script&gt;</td>
            <td>定义脚本（Defines a script）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;noscript&gt;</td>
            <td>定义无脚本的显示区域（Defines a noscript section）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;applet&gt;</td>
            <td>定义java程序（Defines an applet）</td>
            <td>2.0</td>
            <td>3.0</td>
            <td>TF</td>
        </tr>
        <tr>
            <td>&lt;object&gt;</td>
            <td>定义内嵌对象（Defines an embedded object）</td>
            <td>?</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
        <tr>
            <td>&lt;param&gt;</td>
            <td>定义对象的参数（Defines a parameter for an object）</td>
            <td>3.0</td>
            <td>3.0</td>
            <td>STF</td>
        </tr>
    </tbody>
</table>
<img src ="http://www.cppblog.com/eday/aggbug/34903.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-23 09:54 <a href="http://www.cppblog.com/eday/articles/34903.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Silverlight 简介</title><link>http://www.cppblog.com/eday/articles/34877.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Mon, 22 Oct 2007 11:15:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/34877.html</guid><description><![CDATA[<p><a title=http://nibblestutorials.net/ href="http://nibblestutorials.net/"><u><font color=#800080>http://nibblestutorials.net/</font></u></a><br><br><br>Silverlight 是一种新的 Web 呈现技术，能在各种平台上运行。借助该技术，您将拥有内容丰富、视觉效果绚丽的交互式体验，而且，无论是在浏览器内、在多个设备上还是在桌面操作系统（如 Apple Macintosh）中，您都可以获得这种体验。Microsoft .NET Framework 3.0（Windows 编程基础结构）中的呈现技术 XAML（可扩展应用程序标记语言）遵循 WPF (Windows Presentation Foundation)，它是 Silverlight 呈现功能的基础。</p>
<p>本白皮书将逐步引导您了解 Silverlight 的基本情况，以及如何使用 Microsoft 的众多工具（包括 Microsoft Expression Blend、Microsoft Visual Studio 2005 和 XAML）来构建内容丰富的图形站点。首先，让我们了解一下 Silverlight 发展历程的相关背景信息，以及它在开发领域所处的位置。<br><br></p>
<h2>Web 开发的演变：转向 Web.Next</h2>
<p>CERN 的 Tim Berners-Lee 发明现代 Web 时，初衷是将其作为允许在基于网络的系统上存储和链接静态文档的系统。之后的数年间，随着创新的发展和成熟，&#8220;活动&#8221;文档自然而然地成为了现代 Web 发展的新阶段，这些文档在收到访问请求时即会生成，文档中包含特定于时间或用户的信息。CGI 之类的技术成为了这一阶段的实现基础。随着时间的推移，在 Web 上生成文档的功能变得极为重要，技术上的发展也历经 CGI、Java、ASP，到达 ASP.NET 阶段。</p>
<p>在使开发人员拥有采用服务器开发模式并使用 Visual Studio 系列产品中的同类最佳工具快速开发高质量 Web 应用程序的能力这一方面，ASP.NET 树立了一个里程碑。</p>
<p>事实证明，用户体验是 Web 应用程序中的一大障碍，在这方面，技术上的限制使 Web 应用程序无法提供与使用本地数据的客户端应用程序同样丰富的用户体验。</p>
<p><strong>XMLHttpRequest</strong> 对象（2000 年由 Microsoft 作为 Internet Explorer 5 的一部分发布）成为了异步 JavaScript 和 XML (AJAX) 技术的基础，该技术使 Web 应用程序能够更加动态地响应用户输入，因为采用该技术时只会刷新网页的一小部分，并不需要重新加载所有内容。基于 AJAX 构建的创新型解决方案（如 Windows Live Local 映射）使 Web 应用程序更进一步，已经能够提供与客户端类似的用户体验。</p>
<p>Silverlight 是应用程序开发人员和设计人员可以向其客户呈现潜在用户体验丰富性的下一个发展阶段。为了实现此目的，它允许设计人员展现其创造力并以能够直接对 Web 产生影响的格式保存其工作。过去，设计人员会使用提供了丰富输出功能的工具来设计网站和用户体验，但在这些设计的实现能力方面，开发人员会受到 Web 平台的限制。在 Silverlight 模型中，设计人员可以构建所需的用户体验，并将其表示为 XAML。随后，开发人员可以使用 Silverlight 运行时直接将该 XAML 合并到网页中。因此，两者的合作可以比以往任何时候都更加紧密，从而提供丰富的客户端用户体验。</p>
<p>由于 XAML 属于 XML，因此它是基于文本的，能够为这些丰富的内容提供与防火墙兼容的、易于检查的说明。尽管其他技术（如 Java 小程序、ActiveX 和 Flash）可用来部署比 DHTML/CSS/JavaScript 更丰富的内容，但它们都会向浏览器发送二进制内容。这就导致难以进行安全性审核，更不用说还有更新上的困难，因为进行任何更改后都必须重新安装整个应用程序，而这并不是友好的用户体验，并且可能导致页面停滞。如果使用 Silverlight，则需要更改丰富的内容时，服务器端会生成新的 XAML 文件。用户下次浏览到该页面时，会下载该 XAML 并更新体验，而不需要进行任何重新安装。</p>
<p>Silverlight 的核心是浏览器增强模块，其作用是呈现 XAML 并在浏览器界面上绘制生成的图形。它的下载体积较小（不到 2 MB），可以在用户点击包含 Silverlight 内容的站点时进行安装。该模块向 JavaScript 开发人员公开 XAML 页面的底层框架，以便实现页面级的内容交互，这样，开发人员就可以进行自己的工作，例如编写事件处理程序或使用 JavaScript 代码来处理 XAML 页面内容。</p>
<p>不过，理论方面的探讨已经够多的了！我们还是通过实践来看一看我们的第一个 Silverlight 项目。<br><br></p>
<h2>构建一个简单的 Silverlight 应用程序</h2>
<p>我们先来看一看 Microsoft Expression Blend，使用该工具创建一个 XAML 格式的非常简单的应用程序，以供 Silverlight 使用。要在 Blend 中创建 Silverlight 应用程序，请选择 File（文件）-&gt;New project（新建项目），此时会打开&#8220;New Project&#8221;（新建项目）对话框。请参见图 1。</p>
<div style="WIDTH: 423px"><img height=298 alt=. src="http://www.microsoft.com/china/MSDN/library/Windev/WindowsVista/art/Bb404300.startingwithsilverlight_01(en-us,MSDN.10).gif" width=423 border=0><br>
<p class=figureCaption><strong>图 1. 使用 Expression Blend 创建新的 Silverlight 项目</strong></p>
<div class=figureRule></div>
</div>
<p>选择 OK（确定），即会创建一个新项目。该项目将包含一个默认 HTML 页面、该页面的一些 JavaScript 源代码、一篇 XAML 文档和该 XAML 文档的 JavaScript 源代码及 Silverlight.js。</p>
<p>Silverlight.js 包含用于下载和实例化 Silverlight 控件的代码。它作为 Silverlight SDK 的一部分提供给用户。 </p>
<p>Default.html 是标准的 HTML 网页。该网页包含三个 JavaScript 脚本引用，分别指向 Silverlight.js、Default.html.js（其中包含特定于应用程序的用于安装 Silverlight 的代码）和 Scene.xaml.js（其中包含在 XAML 中定义的应用程序事件的事件处理程序）。 </p>
<p>它被设计为一个独立的页面 (default.html)，与实例化逻辑 (default.html.js)、设计 (Scene.xaml) 和事件代码 (Scene.xaml.js) 分开。不过，理论方面的探讨已经够多了，现在我们开始开发一个简单的应用程序。<br><br></p>
<h2>创建供视频播放器使用的 UI</h2>
<p>在项目中添加视频文件。为此，请右键单击屏幕右上方 Project Files（项目文件）窗口中的项目文件，然后选择 Add Existing Item...（添加现有项目）。</p>
<p>选择某个 WMV 文件并将其添加到项目时，项目浏览器中将显示该文件，同时在视图中添加了一个媒体元素。</p>
<div style="WIDTH: 621px"><img height=389 alt=. src="http://www.microsoft.com/china/MSDN/library/Windev/WindowsVista/art/Bb404300.startingwithsilverlight_02(en-us,MSDN.10).gif" width=621 border=0><br>
<p class=figureCaption><strong>图 2. 在 XAML 视图中添加媒体元素</strong></p>
<div class=figureRule></div>
</div>
<p>现在即可运行您的项目，浏览器将启动并播放您的视频！</p>
<p>通过编辑 XAML 可以停止自动播放视频。您会看到 XAML 设计器右侧有两个选项卡：Design（设计）和 XAML。选择&#8220;XAML&#8221;选项卡，会打开 XAML 编辑器，如图 3 中所示。使用该编辑器为媒体元素编辑 XAML 文本，添加属性 AutoPlay=False。</p>
<div style="WIDTH: 621px"><img height=389 alt=. src="http://www.microsoft.com/china/MSDN/library/Windev/WindowsVista/art/Bb404300.startingwithsilverlight_03(en-us,MSDN.10).gif" width=621 border=0><br>
<p class=figureCaption><strong>图 3. 在 XAML 编辑器中编辑 XAML</strong></p>
<div class=figureRule></div>
</div>
<p>现在，如果您运行该应用程序，会看到 Silverlight 内容虽然呈现了视频的第一帧，但并不播放。</p>
<h3>在视频播放器中添加控件</h3>
<p>为该应用程序添加两个文本块，文本内容分别为 Play 和 Stop，名称分别为 txtPlay 和 txtStop。完成后，XAML 应如下所示：</p>
<pre class=codeSample>&lt;Canvas&nbsp;&nbsp;&nbsp; xmlns="http://schemas.microsoft.com/client/2007"&nbsp;&nbsp;&nbsp; xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&nbsp;&nbsp;&nbsp; Width="640" Height="480"&nbsp;&nbsp;&nbsp; Background="White"&nbsp;&nbsp;&nbsp; &gt;&nbsp;&nbsp;&nbsp; &lt;MediaElement AutoPlay="False" x:Name="Movie_wmv" Width="320" Height="240" Canvas.Left="128" Canvas.Top="56" Source="Movie.wmv" Stretch="Fill"/&gt;&nbsp;&nbsp;&nbsp; &lt;TextBlock x:Name="txtPlay" Width="72" Height="24" Canvas.Left="136" Canvas.Top="336" Text="Play" TextWrapping="Wrap"/&gt;&nbsp;&nbsp;&nbsp; &lt;TextBlock x:Name="txtStop" Width="80" Height="24" Canvas.Left="136" Canvas.Top="368" Text="Stop" TextWrapping="Wrap"/&gt;&lt;/Canvas&gt;</pre>
<p>接下来，为文本块在 XAML 中添加事件处理程序声明。为此，可以使用 MouseLeftButtonDown 属性声明单击鼠标的处理程序。在 txtPlay 文本块中，添加对 DoPlay 的事件处理程序；在 txtStop 文本块中，添加对 DoStop 的事件处理程序。完成后，XAML 应如下所示：</p>
<pre class=codeSample>&lt;TextBlock x:Name="txtPlay" Width="72" Height="24" Canvas.Left="136"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Canvas.Top="336" Text="Play" TextWrapping="Wrap"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MouseLeftButtonDown="javascript:DoPlay"/&gt;&lt;TextBlock x:Name="txtStop" Width="80" Height="24" Canvas.Left="136"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Canvas.Top="368" Text="Stop" TextWrapping="Wrap"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MouseLeftButtonDown="javascript:DoStop"/&gt;</pre>
<p>现在，如果用户单击其中一个文本块，将触发一个事件，您可通过 JavaScript 功能捕获并处理该事件。</p>
<h3>在 JavaScript 中处理事件</h3>
<p>模板创建的 Scene.xaml.js 可用于在 JavaScript 中捕获并处理用户事件。由于您在 XAML 内指定了 DoPlay 和 DoStop 事件处理程序，因此应在此处付诸实施。相应的代码如下所示：</p>
<pre class=codeSample>function DoPlay(sender, eventArgs){&nbsp;&nbsp;&nbsp; var theHost = document.getElementById("SilverlightControl");&nbsp;&nbsp;&nbsp; var theMedia = theHost.content.findName("Movie_wmv");&nbsp;&nbsp;&nbsp; theMedia.Play();}function DoStop(sender, eventArgs){&nbsp;&nbsp;&nbsp; var theHost = document.getElementById("SilverlightControl");&nbsp;&nbsp;&nbsp; var theMedia = theHost.content.findName("Movie_wmv");&nbsp;&nbsp;&nbsp; theMedia.Stop();}</pre>
<p>在本例中，将 Silverlight 控件称为 SilverlightControl，将引用该控件的 JavaScript 变量称为 theHost。稍后查找媒体元素（在本例中称为 Movie_wmv）时，将用到上述名称。在项目中添加电影时，为您创建了此媒体元素，该元素的名称是根据电影名称命名的。因此，如果电影的名称是 Movie.wmv，则此媒体元素就称为 Movie_wmv。如果使用其他电影，则控件也会相应地采用其他名称。</p>
<p>该媒体元素有 Play 和 Stop 两个方法，分别用于启动或停止媒体播放。</p>
<p>由于存在对该媒体元素的引用，因而可以调用上述方法，电影将随之停止或启动，如图 4 中所示。</p>
<div style="WIDTH: 623px"><img height=526 alt=. src="http://www.microsoft.com/china/MSDN/library/Windev/WindowsVista/art/Bb404300.startingwithsilverlight_04(en-us,MSDN.10).gif" width=623 border=0><br>
<p class=figureCaption><strong>图 4. 运行应用程序</strong></p>
<div class=figureRule></div>
</div>
<p>至此，您已构建了自己的第一个 Silverlight 应用程序！有关 Silverlight 的更多资源，请查看新的 <a href="http://msdn.microsoft.com/silverlight/" target=_blank><u><font color=#0066cc>Silverlight 开发人员中心</font></u></a>和 <a href="http://www.silverlight.net/" target=_blank><u><font color=#0066cc>http://www.silverlight.net/</font></u></a>。<br><br></p>
<h2>了解 Silverlight 调用</h2>
<p>HTML 页面会调用 Default.html.js 源代码页中的 createSilverlight()。</p>
<pre class=codeSample>Sys.Silverlight.createObjectEx({&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; source: "Scene.xaml",&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parentElement: document.getElementById("SilverlightControlHost"),&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; id: "SilverlightControl",&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; properties: {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; width: "100%",&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; height: "100%",&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; version: "0.9"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; events: {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; onLoad: Sys.Silverlight.createDelegate(scene, scene.handleLoad)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; }); </pre>
<p>该调用将用到许多属性，其中包括那些用于定义要呈现的 XAML、Silverlight 控件外观以及 onLoad 和 onError 事件处理程序的属性。</p>
<p>source:属性用于定义希望 Silverlight 控件呈现的 XAML。该属性可以是外部文件（如本例中所示），也可以是包含 XAML 的页面上的命名 &lt;script&gt; 标记。</p>
<p>在页面上添加 Silverlight 控件时，应将该控件添加到命名 &lt;DIV&gt; 内。应将 parentElement:属性作为该 &lt;DIV&gt; 的名称。</p>
<p>控件的 ID 由 id:属性指定。</p>
<p>控件的物理属性（如高度、宽度和版本）是由加载到 properties:属性中的数组设定的。要查看全部属性，请参阅 <a href="http://msdn2.microsoft.com/en-us/library/bb188743.aspx" target=_blank><u><font color=#0066cc>Silverlight SDK 文档</font></u></a>。<br><br></p>
<h2>结束语</h2>
<p>本白皮书中高度概述了 Microsoft Silverlight，并介绍了 Silverlight 对下一代 Web 应用程序开发堆栈的适用情况。您已经看到，XAML 就像一个凝聚体，将设计人员的规范、开发人员的工具和面向用户的交付三者结合在了一起。您大体了解了 Expression Blend，并学习了如何用它来为网页定义 UI，以及如何使用 JavaScript 对它们进行编程。</p>
<p>您通过本文所了解的内容只触及到 Silverlight 功能的皮毛。这项技术中蕴含着诸多功能，您现在就可以使用这项技术开始构建下一个 Web。这会是一个有趣的旅程，快来体验吧！ </p>
<img src ="http://www.cppblog.com/eday/aggbug/34877.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-22 19:15 <a href="http://www.cppblog.com/eday/articles/34877.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL 和 .Net2.0配合使用</title><link>http://www.cppblog.com/eday/articles/34626.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Fri, 19 Oct 2007 10:10:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/34626.html</guid><description><![CDATA[<div class=postbody>MySql现在的最新版本是5.x.第一次接触它是在大二的时候，用php，那时好像还是4.x版本。<br><br>Mysql5增加很多新的功能，开始支持：存储过程、触发器、视图、信息架构视图等...<br><br>MySql在安装时一如既往的比较复杂，往往就是一个失败的提示，没有什么其它提示原因。<br><br><br>这是一篇文章，比较MySql和SqlServer的，<a href="http://htm.winsteps.net/database/331.htm"><u><font color=#0066cc>http://htm.winsteps.net/database/331.htm</font></u></a><br><br>MySql中文网站<a href="http://www.mysql.cn/"><u><font color=#0066cc>http://www.mysql.cn/</font></u></a>上资料很少，大多是些安装帮助。<br>要查资料还是去MySql的网站<a href="http://www.mysql.com/"><u><font color=#0066cc>http://www.mysql.com/</font></u></a>。<br><br>MySql现在有提供的各种连接工具（<a href="http://dev.mysql.com/downloads/connector/"><u><font color=#0066cc>http://dev.mysql.com/downloads/connector/</font></u></a>），.net下可以用的有<a href="http://dev.mysql.com/downloads/connector/odbc/"><u><font color=#0066cc>Connector/ODBC</font></u></a>和<a href="http://dev.mysql.com/downloads/connector/net/"><u><font color=#800080>Connector/Net</font></u></a>。<br><br>ODBC连接效率可能稍低，最好还是用Net直接的连接<br>这篇文章介绍了各种连接方法<a href="http://www.mysql.com/news-and-events/press-release/release_2002_10.html"><u><font color=#800080>http://www.mysql.com/news-and-events/press-release/release_2002_10.html</font></u></a><br><br>1：ODBC连接<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在的版本是3.51，安装之后，可以这样操作：<br>&nbsp;&nbsp;&nbsp;&nbsp;
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;string&nbsp;conStr&nbsp;=&nbsp;"DRIVER&nbsp;=&nbsp;{MySQL&nbsp;ODBC&nbsp;3.51&nbsp;Driver};&nbsp;SERVER&nbsp;=&nbsp;localhost;&nbsp;DATABASE&nbsp;=test;&nbsp;UID&nbsp;=&nbsp;root;&nbsp;PASSWORD=;";</span><span style="COLOR: #008000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;conStr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">DRIVER={MySQL&nbsp;ODBC&nbsp;3.51&nbsp;Driver};SERVER=localhost;DATABASE=test;USER=root;PASSWORD=;OPTION=3;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;conStr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">provider&nbsp;=&nbsp;MySQL&nbsp;ODBC&nbsp;3.51&nbsp;Driver;&nbsp;SERVER&nbsp;=&nbsp;localhost;&nbsp;DATABASE&nbsp;=test;&nbsp;UID&nbsp;=&nbsp;root;&nbsp;PASSWORD=;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_406_529_Open_Image onclick="this.style.display='none'; Codehighlighter1_406_529_Open_Text.style.display='none'; Codehighlighter1_406_529_Closed_Image.style.display='inline'; Codehighlighter1_406_529_Closed_Text.style.display='inline';" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_406_529_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_406_529_Closed_Text.style.display='none'; Codehighlighter1_406_529_Open_Image.style.display='inline'; Codehighlighter1_406_529_Open_Text.style.display='inline';" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_406_529_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cnblogs.com/Images/dot.gif"></span><span id=Codehighlighter1_406_529_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OleDbConnection&nbsp;&nbsp;connection&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;OleDbConnection(conStr);<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connection.Open();<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">(Exception&nbsp;ex)<br><img id=Codehighlighter1_575_632_Open_Image onclick="this.style.display='none'; Codehighlighter1_575_632_Open_Text.style.display='none'; Codehighlighter1_575_632_Closed_Image.style.display='inline'; Codehighlighter1_575_632_Closed_Text.style.display='inline';" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_575_632_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_575_632_Closed_Text.style.display='none'; Codehighlighter1_575_632_Open_Image.style.display='inline'; Codehighlighter1_575_632_Open_Text.style.display='inline';" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_575_632_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cnblogs.com/Images/dot.gif"></span><span id=Codehighlighter1_575_632_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MessageBox.Show(ex.Message);<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
<br>2：Net连接：<br>&nbsp;&nbsp;&nbsp;&nbsp; MySQL Connector Net 1.0.7：有net1.0；net.1;net2.0;mono1.0四个版本的connector。免费<br>&nbsp;&nbsp;&nbsp; &nbsp;CoreLab.MySql 3.5：这是个商业的版本，试用期30天。<br><br>&nbsp;&nbsp;&nbsp; 下边的代码是使用MySQL Connector Net&nbsp;的例子。注意：他的Parameter的前缀是&#8220;？&#8221;而不是&#8220;@&#8221;。这个问题比较特殊。CoreLab里面的Parameter的前缀就是&#8220;@&#8221;.<br>&nbsp;&nbsp;&nbsp;&nbsp;
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">string</span><span style="COLOR: #000000">&nbsp;connStr&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;String.Format(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">server={0};user&nbsp;id={1};&nbsp;password={2};&nbsp;database={3};&nbsp;pooling=false;port=3308</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">localhost</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">root</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">test</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_173_668_Open_Image onclick="this.style.display='none'; Codehighlighter1_173_668_Open_Text.style.display='none'; Codehighlighter1_173_668_Closed_Image.style.display='inline'; Codehighlighter1_173_668_Closed_Text.style.display='inline';" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_173_668_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_173_668_Closed_Text.style.display='none'; Codehighlighter1_173_668_Open_Image.style.display='inline'; Codehighlighter1_173_668_Open_Text.style.display='inline';" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_173_668_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cnblogs.com/Images/dot.gif"></span><span id=Codehighlighter1_173_668_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MySqlConnection&nbsp;myConn&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;MySqlConnection(connStr);<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myConn.Open();<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MySqlCommand&nbsp;cmd&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;myConn.CreateCommand();<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmd.Parameters.Add(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">?DocName</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;MySqlDbType.VarChar,&nbsp;</span><span style="COLOR: #000000">50</span><span style="COLOR: #000000">);<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmd.Parameters[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">].Value&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">test&nbsp;by&nbsp;code</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmd.Parameters[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">].SourceColumn&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">DocName</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmd.CommandText&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">update&nbsp;t_docs&nbsp;set&nbsp;DocName=?DocName&nbsp;where&nbsp;DocId=4</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmd.ExecuteNonQuery();</span></div>
</span><br>这是使用一个ORM时设置provider的例子<br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">CustomProvider&nbsp;mysqlProvider&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;CustomProvider(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">MySql.Data</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">MySql.Data.MySqlClient.MySqlConnection</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">MySql.Data.MySqlClient.MySqlDataAdapter</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br></span><span style="COLOR: #008000"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysqlProvider.StartDelimiter&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">default&nbsp;is&nbsp;"/""</span><span style="COLOR: #008000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysqlProvider.EndDelimiter&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">default&nbsp;is&nbsp;"/""</span><span style="COLOR: #008000"><br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysqlProvider.ParameterPrefix&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">?</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;//设置参数前缀<br><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysqlProvider.SelectPageQuery&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">SELECT&nbsp;*&nbsp;LIMIT&nbsp;{0}&nbsp;OFFSET&nbsp;{1}</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">设置分页算法<br></span><span style="COLOR: #008000"><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mysqlProvider.IdentityQuery&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">SELECT&nbsp;LAST_INSERT_ID()</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">设置获取刚刚插入记录Id的函数</span></div>
<br><br>3：OLE连接：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 现在还没有来自官方的支持。<br><br>在vs2005中，直接引用for .net2.0版本的dll即可。至于那个商业版，就得费些功夫了，需要一个许可文件（拖动一个Conection组件到Form上就能自动创建该许可）<br><br>附，连接字符串可以到这里查询<a href="http://www.connectionstrings.com/"><u><font color=#800080>http://www.connectionstrings.com/</font></u></a>， 够全的了。</div>
<img src ="http://www.cppblog.com/eday/aggbug/34626.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-19 18:10 <a href="http://www.cppblog.com/eday/articles/34626.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在多线程中如何调用Winform</title><link>http://www.cppblog.com/eday/articles/34258.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Mon, 15 Oct 2007 04:08:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/34258.html</guid><description><![CDATA[问题的产生：<br><br>　　我的WinForm程序中有一个用于更新主窗口的工作线程（worker thread），但文档中却提示我不能在多线程中调用这个form（为什么？），而事实上我在调用时程序常常会崩掉。请问如何从多线程中调用form中的方法呢？ <br><br>　　解答：<br><br>　　每一个从Control类中派生出来的WinForm类（包括Control类）都是依靠底层Windows消息和一个消息泵循环（message pump loop）来执行的。消息循环都必须有一个相对应的线程，因为发送到一个window的消息实际上只会被发送到创建该window的线程中去。其结果是，即使提供了同步（synchronization），你也无法从多线程中调用这些处理消息的方法。大多数plumbing是掩藏起来的，因为WinForm是用代理（delegate）将消息绑定到事件处理方法中的。WinForm将Windows消息转换为一个基于代理的事件，但你还是必须注意，由于最初消息循环的缘故，只有创建该form的线程才能调用其事件处理方法。如果你在你自己的线程中调用这些方法，则它们会在该线程中处理事件，而不是在指定的线程中进行处理。你可以从任何线程中调用任何不属于消息处理的方法。<br><br>　　Control类（及其派生类）实现了一个定义在System.ComponentModel命名空间下的接口 -- ISynchronizeInvoke，并以此来处理多线程中调用消息处理方法的问题：<br><br>
<table cellSpacing=0 cellPadding=0 width="100%" bgColor=#ffffff border=0>
    <tbody>
        <tr>
            <td>public interface ISynchronizeInvoke<br>{<br>　object Invoke(Delegate　method,object[] args);<br>　IAsyncResult BeginInvoke(Delegate　method,object[] args);<br>　object EndInvoke(IAsyncResult result);<br>　bool InvokeRequired {get;}<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　ISynchronizeInvoke提供了一个普通的标准机制用于在其他线程的对象中进行方法调用。例如，如果一个对象实现了ISynchronizeInvoke，那么在线程T1上的客户端可以在该对象中调用ISynchronizeInvoke的Invoke()方法。Invoke()方法的实现会阻塞（block）该线程的调用，它将调用打包发送（marshal）到 T2，并在T2中执行调用，再将返回值发送会T1，然后返回到T1的客户端。Invoke()方法以一个代理来定位该方法在T2中的调用，并以一个普通的对象数组做为其参数。<br><br>　　调用者还可以检查InvokeRequired属性，因为你既可以在同一线程中调用ISynchronizeInvoke也可以将它重新定位（redirect）到其他线程中去。如果InvokeRequired的返回值是false的话，则调用者可以直接调用该对象的方法。<br><br>　　比如，假设你想要从另一个线程中调用某个form中的Close方法，那么你可以使用预先定义好的的MethodInvoker代理，并调用Invoke方法:<br><br>
<table cellSpacing=0 cellPadding=0 width="100%" bgColor=#ffffff border=0>
    <tbody>
        <tr>
            <td>Form form;<br>/* obtain a reference to the form, <br>then: */<br>ISynchronizeInvoke synchronizer;<br>synchronizer = form;<br><br>if(synchronizer.InvokeRequired)<br>{<br>MethodInvoker invoker = new <br>MethodInvoker(form.Close);<br>synchronizer.Invoke(invoker,null);<br>}<br>else<br>form.Close();</td>
        </tr>
    </tbody>
</table>
<br>　　ISynchronizeInvoke不仅仅用于WinForm中。例如，一个Calculator类提供了将两个数字相加的Add()方法，它就是通过ISynchronizeInvoke来实现的。用户必须确定ISynchronizeInvoke.Invoke()方法的调用是执行在正确的线程中的。<br><br>　　C# 在正确的线程中写入调用<br><br>　　列表A. Calculator类的Add()方法用于将两个数字相加。如果用户直接调用Add()方法，它会在该用户的线程中执行调用，而用户可以通过ISynchronizeInvoke.Invoke()将调用写入正确的线程中。
<p>　　列表A:<br></p>
<table cellSpacing=0 cellPadding=0 width="100%" bgColor=#ffffff border=0>
    <tbody>
        <tr>
            <td>
            <p>public class Calculator : ISynchronizeInvoke<br>{<br>　public int Add(int arg1,int arg2)<br>　{　<br>　　int threadID = Thread.CurrentThread.GetHashCode();<br>　　Trace.WriteLine( "Calculator thread ID is " + threadID.ToString());<br>　　return arg1 + arg2;<br>　}<br>　//ISynchronizeInvoke implementation <br>　public object Invoke(Delegate method,object[] args)<br>　{<br>　　public IAsyncResult BeginInvoke(Delegate method,object[] args)<br>　　{<br>　　　public object EndInvoke(IAsyncResult result)<br>　　　{<br>　　　　public bool InvokeRequired<br>　　　　{<br>　　　　}<br>　　　}<br>　　　//Client-side code<br>　　　public delegate int AddDelegate(int arg1,int arg2);</p>
            <p>　　　　int threadID = Thread.CurrentThread.GetHashCode();<br>　　　　Trace.WriteLine("Client thread ID is " + threadID.ToString());</p>
            <p>　　　　Calculator calc;<br>　　　　/* Some code to initialize calc */</p>
            <p>　　　　AddDelegate addDelegate = new AddDelegate(calc.Add);</p>
            <p>　　　　object[] arr = new object[2];<br>　　　　arr[0] = 3;<br>　　　　arr[1] = 4;</p>
            <p>　　　　int sum = 0;<br>　　　　sum = (int) calc.Invoke(addDelegate,arr);<br>　　　　Debug.Assert(sum ==7);</p>
            <p>　　　　/* Possible output:<br>　　　　Calculator thread ID is 29<br>　　　　Client thread ID is 30 <br>　　　　*/</p>
            </td>
        </tr>
    </tbody>
</table>
<p>　　或许你并不想进行同步调用，因为它被打包发送到另一个线程中去了。你可以通过BeginInvoke()和EndInvoke()方法来实现它。你可以依照通用的.NET非同步编程模式（asynchronous programming model）来使用这些方法：用BeginInvoke()来发送调用，用EndInvoke()来实现等待或用于在完成时进行提示以及收集返回结果。<br><br>　　还值得一提的是ISynchronizeInvoke方法并非安全类型。 类型不符会导致在执行时被抛出异常，而不是编译错误。所以在使用ISynchronizeInvoke时要格外注意，因为编辑器无法检查出执行错误。<br><br>　　实现ISynchronizeInvoke要求你使用一个代理来在后期绑定（late binding）中动态地调用方法。每一种代理类型均提供DynamicInvoke()方法： public object DynamicInvoke(object[] <br>args);<br><br>　　理论上来说，你必须将一个方法代理放到一个需要提供对象运行的真实的线程中去，并使Invoke() 和BeginInvoke()方法中的代理中调用DynamicInvoke()方法。ISynchronizeInvoke的实现是一个非同一般的编程技巧，本文附带的源文件中包含了一个名为Synchronizer的帮助类（helper class）和一个测试程序，这个测试程序是用来论证列表A中的Calculator类是如何用Synchronizer类来实现ISynchronizeInvoke的。Synchronizer是ISynchronizeInvoke的一个普通实现，你可以使用它的派生类或者将其本身作为一个对象来使用，并将ISynchronizeInvoke实现指派给它。 <br><br>　　用来实现Synchronizer的一个重要元素是使用一个名为WorkerThread的嵌套类（nested class）。WorkerThread中有一个工作项目（work item）查询。WorkItem类中包含方法代理和参数。Invoke()和BeginInvoke()用来将一个工作项目实例加入到查询里。WorkerThread新建一个.NET worker线程，它负责监测工作项目的查询任务。查询到项目之后，worker会读取它们，然后调用DynamicInvoke()方法。</p>
<img src ="http://www.cppblog.com/eday/aggbug/34258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-15 12:08 <a href="http://www.cppblog.com/eday/articles/34258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用C++品尝Vista美味：界面的毛玻璃效果</title><link>http://www.cppblog.com/eday/articles/33694.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Sun, 07 Oct 2007 08:37:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/33694.html</guid><description><![CDATA[　　<strong>简介</strong><br><br>　　本文将演示在基于Windows Vista的普通Windows应用程序及对话框程序中，如何利用C++来生成Aero毛玻璃效果，此处使用的是Beta 2版本的Vista及Windows SDK，也许在后续的版本中，一些API在细节上会有所变化。另外，文中没有使用MFC，全部例子用WTL 7.5生成，其可在http://wtl.sourceforge.net/下载得到，虽然此处使用的是Visual C++ 2003，但Visual C++ 2005也类似。<br><br>　　Aero主题及毛玻璃效果，是随同Vista"桌面窗口管理（DWM）"而来的新特性，也是微软市场推广的一个重心，在应用程序中集成毛玻璃效果，当打开Aero主题时，程序看上去会显得非常与众不同--很酷，对吧。 <br><br>　　<strong>Aero主题中的毛玻璃效果</strong><br><br>　　当以Aero为主题时，Vista会根据计算机显卡进行判断是否开启毛玻璃效果，此时桌面由DWM进行绘制，而DWM使用一个composition进程来渲染桌面，其会在顶层窗口的非客户区自动使用Aero主题元素（有点类似于Windows XP）。话又说回来，也不是总会添加这些毛玻璃效果的，如果计算机运行于"电池模式"，或用户决定关闭透明效果，那么非客户区就不会有毛玻璃效果了，如下图所示。<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://dev.yesky.com/imagelist/06/43/49387f5bk3ww.jpg" border=1></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　如果在控制面板的可视效果中打开了透明玻璃效果，那非客户区看上去就像下图这样：<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://dev.yesky.com/imagelist/06/43/n970s31f0ikr.jpg" border=1></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　请留意，记事本的边框呈现绿色调，这是墙纸透过来的颜色，并且也可以透过标题栏看到桌面的一些图标。<br><br>　　我们在编写代码的时候，关键只须留意composition是否打开，而不是设置了什么毛玻璃效果，因为DWM会处理毛玻璃效果绘制的部分。<br><br>　　<strong>项目开始</strong><br><br>　　第一个示例程序是不带视窗口、工具条、状态条的SDI应用程序，在运行完WTL AppWizard之后，第一件事就是设置stdafx.h中的#define，以便利用Vista的新特性。Vista的Windows版本为6，且Vista中IE的版本为7，设置完成后应像下面这样：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>#define WINVER 0x0600<br>#define _WIN32_WINNT 0x0600<br>#define _WIN32_IE 0x0700</td>
        </tr>
    </tbody>
</table>
<br>　　接下来包含ATL与WTL的头文件：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>#define _WTL_NO_WTYPES // 不要在WTL头文件中定义CRect/CPoint/CSize<br>#include &lt;atlbase.h&gt;<br>#include &lt;atltypes.h&gt;//共享的CRect/CPoint/CSize<br>#include &lt;atlapp.h&gt;<br><br>extern CAppModule _Module;<br><br>#include &lt;atlwin.h&gt;<br>#include &lt;atlframe.h&gt;<br>#include &lt;atlmisc.h&gt;<br>#include &lt;atlcrack.h&gt;<br>#include &lt;atltheme.h&gt;// XP/Vista主题支持<br>#include &lt;dwmapi.h&gt;// DWM API</td>
        </tr>
    </tbody>
</table>
<br>　　如果修改完成之后就编译，将会从atltheme.h中得到4个错误。例如，以下是不会编译通过的CTheme::GetThemeTextMetrics()代码：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>HRESULT GetThemeTextMetrics(..., PTEXTMETRICW pTextMetric)<br>{<br>　ATLASSERT(m_hTheme != NULL);<br><br>　//注意：因为uxtheme.h头文件，所以转换为PTEXTMETRIC。<br>　//替换掉PTEXTMETRICW是不对的<br>　return ::GetThemeTextMetrics(m_hTheme, ..., (PTEXTMETRIC) pTextMetric);<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　在GetThemeTextMetrics() API中的转换，是对Platform SDK的uxtheme.h中错误的修正，然而，Windows SDK却没有这个错误，所以这个转换导致了一个错误，可删除函数中的这个转换，其他三个也同样。<br><br>　　<strong>添加边框的毛玻璃效果</strong><br><br>　　通过把毛玻璃效果从非客户区扩展到客户区，就可完成添加程序的毛玻璃效果，这个API是DwmExtendFrameIntoClientArea()。DwmExtendFrameIntoClientArea()接受两个参数：我们框架窗口的HWND和一个用于说明毛玻璃效果扩展到窗口四周多远的MARGINS结构。可在OnCreate()中调用这个API：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>LRESULT CMainFrame::OnCreate(LPCREATESTRUCT lpcs)<br>{<br>　//在底部添加玻璃效果<br>　MARGINS mar = {0};<br>　mar.cyBottomHeight = 100;<br>　DwmExtendFrameIntoClientArea ( m_hWnd, &amp;mar );<br>　return 0;<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　但如果运行程序，看不到有任何变化：<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://dev.yesky.com/imagelist/06/43/w1s1li5r7ebk.jpg" border=1></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　这是因为毛玻璃效果依赖于窗口的透明度，为显示出玻璃效果，区域中像素（在本例中为客户区底部的100像素）的alpha值必须设置为0。最简单的方法是用一个黑画刷来绘制这个区域，它会把像素的颜色值（红、绿、蓝和alpha）设为0，可在OnEraseBkgnd()中完成：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>BOOL CMainFrame::OnEraseBkgnd ( HDC hdc )<br>{<br>　CDCHandle dc = hdc;<br>　CRect rcClient;<br>　GetClientRect(rcClient);<br>　dc.FillSolidRect(rcClient, RGB(0,0,0));<br>　return true;<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　修改之后，框架窗口看起来像这样：<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://dev.yesky.com/imagelist/06/43/elrw4etj4ghw.jpg" border=1></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　底部的100像素现在是毛玻璃效果了。<br><br>　　<strong>在毛玻璃区域添加文本</strong><br><br>　　在窗口中添加毛玻璃效果是比较简单的部分，但要把自己的界面元素（UI）添加到毛玻璃之上，就有点难度了。因为必须一直保持像素的alpha值，所以就要用到那些可以理解并适当设置alpha的绘图API。坏消息是，GDI函数差不多全部不理会alpha--唯一剩下的API则为带有SRCCOPY光栅操作的BilBlt()函数了，因此，程序必须使用GDI+或主题API来进行绘图，这些API都是时刻不忘alpha的。<br><br>　　在Vista中，有关毛玻璃的效果一般用在表示程序状态的区域（取代了通用控件中的状态栏），例如，Windows Media Player 11就在窗口底部的毛玻璃区域显示播放控制与当前歌曲信息：<br><br><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://dev.yesky.com/imagelist/06/43/5x2sss3hf932.jpg" border=1><br><br>　　以下，将演示怎样在毛玻璃区域上绘制文本，并怎样在文本上添加发光效果，以便文本在任何背景上都方便阅读。<br><br>　　<strong>使用正确的字体</strong><br><br>　　Vista已经彻底放弃使用MS Sans Serif与Tahoma字体，转而把Segoe UI作为默认的UI字体。我们的程序也应该使用Segoe UI字体，所以，将会在基于当前主题的情况下创建一个字体。如果主题被禁用（如用户正在使用Windows经典颜色方案），那我们就使用SystemParametersInfo() API。<br><br>　　首先，需要在CMainFrame中添加主题支持，这一点非常简单，因为WTL已经有一个用于处理主题的类：CThemeImpl。我们可把CThemeImpl添加到继承列表，并把消息链接至CThemeImpl，以便在当前主题改变时，程序可以得到相应的通知。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>class CMainFrame :<br>public CFrameWindowImpl&lt;CMainFrame&gt;,<br>public CMessageFilter,<br>public CThemeImpl&lt;CMainFrame&gt;<br>{<br>　// ...<br>　BEGIN_MSG_MAP(CMainFrame)<br>　　CHAIN_MSG_MAP(CThemeImpl&lt;CMainFrame&gt;)<br>　　// ...<br>　END_MSG_MAP()<br><br>　protected:<br>　　CFont m_font; //用于绘制文本的字体<br>};</td>
        </tr>
    </tbody>
</table>
<br>　　在CMainFrame的构造函数中，我们调用了CThemeImpl::SetThemeClassList()，其指定了我们正在使用哪一个主题的窗口类。对一般窗口来说（即不是普通控件的窗口），名称为"globals"。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>CMainFrame::CMainFrame()<br>{<br>　SetThemeClassList ( L"globals" );<br>}</td>
        </tr>
    </tbody>
</table>
<br><br>　　最后，在OnCreate()中，从主题中读取字体信息，并创建一个字体自用：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>LRESULT CMainFrame::OnCreate ( LPCREATESTRUCT lpcs )<br>{<br>　// ...<br>　//决定在文本中使用哪一种字体<br><br>　LOGFONT lf = {0};<br>　if ( !IsThemeNull() )<br>　　GetThemeSysFont ( TMT_MSGBOXFONT, &amp;lf );<br>　else<br>　{<br>　　NONCLIENTMETRICS ncm = { sizeof(NONCLIENTMETRICS) };<br>　　SystemParametersInfo (SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS),&amp;ncm, false );<br>　　lf = ncm.lfMessageFont;<br>　}<br>　m_font.CreateFontIndirect ( &amp;lf );<br>　return 0;<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　<strong>绘制文本</strong><br><br>　　在毛玻璃效果上绘制文本涉及以下步骤：<br><br>　　&#183;创建一个用于双缓冲绘制的内存DC。<br><br>　　&#183;创建一个32位色深的DIB，并选入DC。<br><br>　　&#183;用DrawThemeTextEx()把文本绘制在内存中的DIB上。<br><br>　　&#183;用BitBit()把文本复制到屏幕。<br><br>　　因为我们的绘制代码将会因为composition是否打开而有所不同，所以需要在绘制期间检查composition状态。检查状态的API为DwmIsCompositionEnabled()，如果API执行失败，在返回值中就不会指示出打开状态，但CMainFrame中有一个包装好的函数IsCompositionEnabled()，非常易于使用：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>bool CMainFrame::IsCompositionEnabled() const<br>{<br>　HRESULT hr;<br>　BOOL bEnabled;<br>　hr = DwmIsCompositionEnabled(&amp;bEnabled);<br>　return SUCCEEDED(hr) &amp;&amp; bEnabled;<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　现在，让我们再检查一遍OnEraseBkgnd()，看看每个步骤是否都完成了。这个程序是一个时钟程序，所以先用GetTimeFormat()获取当前时间：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>BOOL CMainFrame::OnEraseBkgnd(HDC hdc)<br>{<br>　CDCHandle dc = hdc;<br>　CRect rcClient, rcText;<br>　GetClientRect ( rcClient );<br>　dc.FillSolidRect ( rcClient, RGB(0,0,0) );<br>　rcText = rcClient;<br>　rcText.top = rcText.bottom - 100;<br>　<br>　//获取当前时间<br><br>　TCHAR szTime[64];<br>　GetTimeFormat(LOCALE_USER_DEFAULT,0,NULL,NULL,szTime,_countof(szTime));<br>　&#8230;&#8230;<br>}<br><br></td>
        </tr>
    </tbody>
</table>
<br>　　如果composition打开，我们就进行合成绘制步骤，先设置好一个内存DC：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>if ( IsCompositionEnabled() )<br>{<br>　//设置一个我们将绘制的内存DC和位图<br>　CDC dcMem;<br>　CBitmap bmp;<br>　BITMAPINFO dib = {0};<br>　dcMem.CreateCompatibleDC ( dc );</td>
        </tr>
    </tbody>
</table>
<br>　　接下来，填充BITMAPINFO结构以得到一个32位色深位图，且与毛玻璃区域的高宽相同。此处需重点留意的是，位图高度（即BITMAPINFOHEADER的biHeight成员）为负数，这是因为通常情况下BMP是按照从下至上的顺序存储在内存中的，但DrawThemeTextEx()需要的位图顺序是从上至下，所以要把高度设为负数。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);<br>dib.bmiHeader.biWidth = rcText.Width();<br>dib.bmiHeader.biHeight = -rcText.Height();<br>dib.bmiHeader.biPlanes = 1;<br>dib.bmiHeader.biBitCount = 32;<br>dib.bmiHeader.biCompression = BI_RGB;<br><br>bmp.CreateDIBSection (dc,&amp;dib,DIB_RGB_COLORS,NULL,NULL,0);</td>
        </tr>
    </tbody>
</table>
<br>　　现在，我们的图形对象就创建好了，可以开始绘制文本了。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>//设置好DC<br><br>dcMem.SelectBitmap ( bmp );<br>dcMem.SelectFont ( m_font );<br><br>//绘制文本<br><br>DTTOPTS dto = { sizeof(DTTOPTS) };<br>const UINT uFormat = DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_NOPREFIX;<br>CRect rcText2 = rcText;<br>dto.dwFlags = DTT_COMPOSITED|DTT_GLOWSIZE;<br>dto.iGlowSize = 10;<br>rcText2 -= rcText2.TopLeft(); //相同的rect，但左上角为(0,0)<br><br>DrawThemeTextEx ( m_hTheme, dcMem, 0, 0, CT2CW(szTime), -1,<br>uFormat, rcText2, &amp;dto );</td>
        </tr>
    </tbody>
</table>
<br>　　DTTOPTS结构控制了文本怎样被绘制，在标志中我们指明了要绘制"合成文本"，并让文本有一个发光效果。最后，把内存中的位图贴到屏幕上：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>　//将文本绘制到屏幕上。<br>　BitBlt ( dc, rcText.left, rcText.top, rcText.Width(), rcText.Height(), dcMem, 0, 0, SRCCOPY );<br>} // end if (IsCompositionEnabled())</td>
        </tr>
    </tbody>
</table>
<br>　　如果composition未打开，我们用GDI函数绘制文本：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>else<br>{<br>　const UINT uFormat = DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_NOPREFIX;<br>　//设置好DC<br><br>　dc.SetTextColor ( RGB(255,255,255) );<br>　dc.SelectFont ( m_font );<br>　dc.SetBkMode ( TRANSPARENT );<br><br>　//绘制文本<br><br>　dc.DrawText ( szTime, -1, rcText, uFormat );<br>}<br>return true; //我们绘制了整个背景<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　下面就是"合成文本"的模样：<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://dev.yesky.com/imagelist/06/43/856a5og8f8cv.jpg" border=1></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　为演示发光效果，下面是同一背景上的一段文本，但没有发光效果： <br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://dev.yesky.com/imagelist/06/43/kys160n37oye.jpg" border=1></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　<strong>处理composition相关的通知</strong><br><br>　　当DWM的composition状态打开或关闭时，系统会向所有顶层窗口广播一个WM_DWMCOMPOSITIONCHANGED消息；如果composition为打开，需要再次调用DwmExtendFrameIntoClientArea()以告之DWM，我们窗口的哪一部分应为毛玻璃效果：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>LRESULT CMainFrame::OnCompositionChanged(...)<br>{<br>　if ( IsCompositionEnabled() )<br>　{<br>　　MARGINS mar = {0};<br>　　mar.cyBottomHeight = 100;<br>　　DwmExtendFrameIntoClientArea ( m_hWnd, &amp;mar );<br>　}<br>　return 0;<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　<strong>在对话框程序中应用毛玻璃效果</strong><br><br>　　在对话框程序中添加毛玻璃效果的过程，与上面框架窗口的例子非常相似，但需要对代码作一些轻微的改动。在示例对话框程序中为顶层窗口添加了毛玻璃效果，下面，相对前一例子作了修改或添加的代码，将以黑体字标出。<br><strong><br>　　设置对话框</strong><br><br>　　如之前一样，要告之CThemeImpl我们要使用哪个窗口类主题，并调用DwmExtendFrameIntoClientArea()为窗口边框添加毛玻璃效果。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>CMainDlg::CMainDlg()<br>{<br>　SetThemeClassList ( L"globals" );<br>}<br><br>BOOL CMainDlg::OnInitDialog ( HWND hwndFocus, LPARAM lParam )<br>{<br>　//删除了向导生成的某些初始化代码<br>　//为顶层窗口添加毛玻璃效果<br><br>　if ( IsCompositionEnabled() )<br>　{<br>　　MARGINS mar = {0};<br>　　mar.cyTopHeight = 150;<br>　　DwmExtendFrameIntoClientArea ( m_hWnd, &amp;mar );<br>　}</td>
        </tr>
    </tbody>
</table>
<br>　　接下来，构建文本字体。注意，我们需要显式调用OpenThemeData()，而为什么在前面的框架窗口例子中不需要调用呢，因为CThemeImpl在它的WM_CREATE处理程序中已调用了。反观对话框取而代之接收WM_INITDIALOG，而CThemeImpl未处理WM_INITDIALOG，所以就需要我们自己调用OpenThemeData()了。另外，在代码中也把字体设置得更大，只是为了演示更大字体的发光效果。 <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>//决定使用哪一种字体<br>LOGFONT lf = {0};<br>OpenThemeData();<br><br>if ( !IsThemeNull() )<br>　GetThemeSysFont ( TMT_MSGBOXFONT, &amp;lf );<br>else<br>{<br>　NONCLIENTMETRICS ncm = { sizeof(NONCLIENTMETRICS) };<br>　SystemParametersInfo (SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS),&amp;ncm, false );<br>　lf = ncm.lfMessageFont;<br>}<br><br>lf.lfHeight *= 3;<br>m_font.CreateFontIndirect ( &amp;lf );</td>
        </tr>
    </tbody>
</table>
<br>　　对话框的顶层窗口上有一个大的静态文本控件，也就是我们要绘制时间的地方。代码设置了控件的owner-draw风格，因此，我们可把所有的文本绘制代码都放在OnDrawItem()中：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>//设置静态文本控件的owner-draw<br><br>m_wndTimeLabel.Attach ( GetDlgItem(IDC_CLOCK) );<br>m_wndTimeLabel.ModifyStyle ( SS_TYPEMASK, SS_OWNERDRAW );</td>
        </tr>
    </tbody>
</table>
<br>　　最后，调用EnableThemeDialogTexture()以便对话框背景使用当前主题来绘制。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>//其他初始化代码<br><br>EnableThemeDialogTexture ( ETDT_ENABLE );<br><br>//设置计时器的时间间隔为1秒，以在每个秒钟内都能更新时钟<br><br>SetTimer ( 1, 1000 );<br>return TRUE;<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　<strong>打开毛玻璃效果</strong><br><br>　　如前面一样，我们需要用黑色画刷来填充毛玻璃区域，以便营造一种透视效果。因为内置的对话框窗口处理过程会响应WM_ERASEBKGND消息，来处理诸如非矩形或半透明控件，所以，我们需要在OnPaint()而不是OnEraseBkgnd()中做绘图。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>void CMainDlg::OnPaint ( HDC hdc )<br>{<br>　CPaintDC dc(m_hWnd);<br>　CRect rcGlassArea;<br><br>　if ( IsCompositionEnabled() )<br>　{<br>　　GetClientRect ( rcGlassArea );<br>　　rcGlassArea.bottom = 150;<br>　　dc.FillSolidRect(rcGlassArea, RGB(0,0,0));<br>　}<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　<strong>绘制文本</strong><br><br>　　在OnTimer()中，获取当前时间，并以此设置静态控件的文本：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>void CMainDlg::OnTimer ( UINT uID, TIMERPROC pProc )<br>{<br>　//获取当前时间<br>　TCHAR szTime[64];<br>　GetTimeFormat ( LOCALE_USER_DEFAULT, 0, NULL, NULL,szTime, _countof(szTime) );<br>　m_wndTimeLabel.SetWindowText ( szTime )<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　SetWindowText()函数会使静态控件重绘，导致OnDrawItem()函数的调用。OnDrawItem()函数中的代码与前面框架窗口例子中的类似，在此不再赘述，以下是程序外观：<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://dev.yesky.com/imagelist/06/43/ky21eyqa7kjb.jpg" border=1></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　<strong>在毛玻璃效果上绘制图形</strong> <br><br>　　先前已提到，在毛玻璃区域中进行绘图需要用到可识别alpha的API，如GDI+函数。下面的例子用到GDI+中的Image类在对话框的左上角绘制了一个Logo，如图示：<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://dev.yesky.com/imagelist/06/43/df2mqedu7n79.jpg" border=1></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　这个Logo是从与exe文件在同一目录的mylogo.png文件中读取的，请注意，因为使用了GDI+绘制Logo，所以Logo周围的透明度已被保留，并且看上去显示得很正确。<br><br>　　<strong>使整个窗口毛玻璃化</strong><br><br>　　我们还可以让整个窗口看上去都像块毛玻璃，以下有一段简短代码，只需把MARGINS结构的第一个成员设为 -1就行了：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>
    <tbody>
        <tr>
            <td>MARGINS mar = {-1};<br>DwmExtendFrameIntoClientArea ( m_hWnd, &amp;mar );</td>
        </tr>
    </tbody>
</table>
<br>　　如果在我们的对话框程序中加入这段代码，那么程序最终将看上去像这样：<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" src="http://dev.yesky.com/imagelist/06/43/2i7q96402bt3.jpg" border=1></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　留意观察，4个按钮上的文本颜色显示不正确，并且每个按钮外围都有一个不透明的矩形。通常来说，透明性与子窗口不会配合得非常好，如果想要一个全为毛玻璃效果的对话框，那么控件部分就需要以一个不透明的背景来绘制，如"Windows Mobility Center"程序：<br><br>
<table width="90%" align=center>
    <tbody>
        <tr>
            <td>
            <div align=center><a href="http://dev.yesky.com/TLimages/picview/?/imagelist/06/43/av597ol9414h.jpg" target=_blank><img style="BORDER-LEFT-COLOR: #000000; BORDER-BOTTOM-COLOR: #000000; BORDER-TOP-COLOR: #000000; BORDER-RIGHT-COLOR: #000000" alt=点击放大此图片 src="http://dev.yesky.com/imagelist/06/43/av597ol9414hs.jpg" border=1></a></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　<strong>结论</strong><br><br>　　在程序中添加毛玻璃效果可使程序在视觉上显得非常与众不同，而且能提供一个比通用控件中状态栏更好的状态显示区域，本文主要是起到一个抛砖引玉的作用，也有助于大家在使用本地C++添加毛玻璃效果时，对DWM API有一个初步的了解。<br>
<img src ="http://www.cppblog.com/eday/aggbug/33694.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-10-07 16:37 <a href="http://www.cppblog.com/eday/articles/33694.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>P2P之UDP穿透NAT的原理与实现</title><link>http://www.cppblog.com/eday/articles/33208.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Sat, 29 Sep 2007 09:26:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/33208.html</guid><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 论坛上经常有对P2P原理的讨论，但是讨论归讨论，很少有实质的东西产生（源代码）。呵呵，在这里我就用自己实现的一个源代码来说明UDP穿越NAT的原理。首先先介绍一些基本概念：NAT(Network Address Translators)，网络地址转换：网络地址转换是在IP地址日益缺乏的情况下产生的，它的主要目的就是为了能够地址重用。NAT分为两大类，基本的NAT和NAPT(Network Addr...&nbsp;&nbsp;<a href='http://www.cppblog.com/eday/articles/33208.html'>阅读全文</a><img src ="http://www.cppblog.com/eday/aggbug/33208.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-09-29 17:26 <a href="http://www.cppblog.com/eday/articles/33208.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ASP.NET(c#)中取得当前计算机CPU 内存使用率等相关信息</title><link>http://www.cppblog.com/eday/articles/32458.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Wed, 19 Sep 2007 02:56:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/32458.html</guid><description><![CDATA[在Visual C#中调用API的基本过程： <br>　　首先，在调用API之前，你必须先导入System.Runtime.InteropServices这个名称空间。该名称空间包含了在Visual C#中调用API的一些必要集合，具体的方法如下： <br>　　　using System.Runtime.InteropServices; <br>　　在导入了名称空间后，我们要声明在程序中所要用到的API函数。我们的程序主要是获取系统的相关信息，所以用到的API函数都是返回系统信息的。先给出在Visual C#中声明API的方法： <br>[DllImport("kernel32")]&nbsp;&nbsp; <br>public static extern void GetWindowsDirectory(StringBuilder WinDir,int count);
<p>　　其中，"DllImport"属性用来从不可控代码中调用一个方法，它指定了DLL的位置，该DLL中包含调用的外部方法；"kernel32"设定了类库名；"public"指明函数的访问类型为公有的；"static"修饰符声明一个静态元素，而该元素属于类型本身而不是指定的对象；"extern"表示该方法将在工程外部执行，同时使用DllImport导入的方法必须使用"extern"修饰符；最后GetWindowsDirectory函数包含了两个参数，一个为StringBuilder类型的，另一个为int类型的，该方法返回的内容存在于StringBuilder类型的参数中。同时，因为我们在这里使用到了StringBuilder类，所以在程序的开始处，我们还得添加System.Text这个名称空间，方法同上。 <br>　　其他几个API函数的声明如下： <br>[DllImport("kernel32")]&nbsp;&nbsp; <br>public static extern void GetSystemDirectory(StringBuilder SysDir,int count); <br>[DllImport("kernel32")]&nbsp;&nbsp; <br>public static extern void GetSystemInfo(ref CPU_INFO cpuinfo);&nbsp;&nbsp; <br>[DllImport("kernel32")]&nbsp;&nbsp; <br>public static extern void GlobalMemoryStatus(ref MEMORY_INFO meminfo);&nbsp;&nbsp; <br>[DllImport("kernel32")]&nbsp;&nbsp; <br>public static extern void GetSystemTime(ref SYSTEMTIME_INFO stinfo); </p>
<p>　　以上几个API的作用分别是获取系统路径，获得CPU相关信息，获得内存的相关信息，获得系统时间等。 <br>在声明完所有的API函数后，我们发现后三个函数分别用到了CPU_INFO、MEMORY_INFO、SYSTEMTIME_INFO等结构，这些结构并非是.Net内部的，它们从何而来？其实，我们在用到以上API调用时均需用到以上结构，我们将函数调用获得的信息存放在以上的结构体中，最后返回给程序输出。这些结构体比较复杂，但是如果开发者能够熟练运用，那么整个API世界将尽在开发者的掌握之中。以下就是上述结构体的声明： <br>//定义以下各结构 <br>//定义CPU的信息结构 <br>[StructLayout(LayoutKind.Sequential)]&nbsp;&nbsp; <br>public struct CPU_INFO&nbsp;&nbsp; <br>{&nbsp;&nbsp; <br>public uint dwOemId;&nbsp;&nbsp; <br>public uint dwPageSize;&nbsp;&nbsp; <br>public uint lpMinimumApplicationAddress;&nbsp;&nbsp; <br>public uint lpMaximumApplicationAddress;&nbsp;&nbsp; <br>public uint dwActiveProcessorMask;&nbsp;&nbsp; <br>public uint dwNumberOfProcessors;&nbsp;&nbsp; <br>public uint dwProcessorType;&nbsp;&nbsp; <br>public uint dwAllocationGranularity;&nbsp;&nbsp; <br>public uint dwProcessorLevel;&nbsp;&nbsp; <br>public uint dwProcessorRevision;&nbsp;&nbsp; <br>} <br>//定义内存的信息结构 <br>[StructLayout(LayoutKind.Sequential)]&nbsp;&nbsp; <br>public struct MEMORY_INFO&nbsp;&nbsp; <br>{ <br>public uint dwLength; <br>public uint dwMemoryLoad;&nbsp;&nbsp; <br>public uint dwTotalPhys;&nbsp;&nbsp; <br>public uint dwAvailPhys;&nbsp;&nbsp; <br>public uint dwTotalPageFile;&nbsp;&nbsp; <br>public uint dwAvailPageFile;&nbsp;&nbsp; <br>public uint dwTotalVirtual;&nbsp;&nbsp; <br>public uint dwAvailVirtual;&nbsp;&nbsp; <br>} <br>//定义系统时间的信息结构 <br>[StructLayout(LayoutKind.Sequential)]&nbsp;&nbsp; <br>public struct SYSTEMTIME_INFO&nbsp;&nbsp; <br>{&nbsp;&nbsp; <br>public ushort wYear;&nbsp;&nbsp; <br>public ushort wMonth;&nbsp;&nbsp; <br>public ushort wDayOfWeek;&nbsp;&nbsp; <br>public ushort wDay;&nbsp;&nbsp; <br>public ushort wHour;&nbsp;&nbsp; <br>public ushort wMinute;&nbsp;&nbsp; <br>public ushort wSecond;&nbsp;&nbsp; <br>public ushort wMilliseconds;&nbsp;&nbsp; <br>} </p>
<p>　　结构体定义的主体部分和C++中的没多大差别，具体每个结构体内部成员的定义可参考联机帮助中的SDK文档。同时，我们还发现在每个结构体定义的上面都有一句用中括号括起来的说明性文字。这些说明都是有关结构体成员的布局的，共有三种选项，分别说明如下： <br>　　LayoutKind.Automatic：为了提高效率允许运行态对类型成员重新排序。&nbsp;&nbsp; <br>　　 　注意：永远不要使用这个选项来调用不受管辖的动态链接库函数。&nbsp;&nbsp; <br>　　LayoutKind.Explicit：对每个域按照FieldOffset属性对类型成员排序&nbsp;&nbsp; <br>　　LayoutKind.Sequential：对出现在受管辖类型定义地方的不受管辖内存中的类型成员进行排序。 <br>　　在上面的程序中，为了方便起见我们都用到了第三种方式所有的API函数以及相关的结构体声明完毕后，我们就运用这些API来实现我们的程序功能――获取系统的相关信息。 <br>　　界面可按如下方式布置，不过有兴趣的读者自然可以发挥自己的想象，将界面布局做得更好。 <br>简单的界面布置好后，我们添加一个按钮（"获取信息"按钮）的消息处理函数如下： <br>private void GetInfo_Click(object sender, System.EventArgs e) <br>{ <br>//调用GetWindowsDirectory和GetSystemDirectory函数分别取得Windows路径和系统路径 <br>const int nChars = 128; <br>StringBuilder Buff = new StringBuilder(nChars); <br>GetWindowsDirectory(Buff,nChars); <br>WindowsDirectory.Text = "Windows路径："+Buff.ToString(); <br>GetSystemDirectory(Buff,nChars); <br>SystemDirectory.Text = "系统路径："+Buff.ToString(); <br>//调用GetSystemInfo函数获取CPU的相关信息 <br>CPU_INFO CpuInfo; <br>CpuInfo = new CPU_INFO(); <br>GetSystemInfo(ref CpuInfo); <br>NumberOfProcessors.Text = "本计算机中有"+CpuInfo.dwNumberOfProcessors.ToString()+"个CPU"; <br>ProcessorType.Text = "CPU的类型为"+CpuInfo.dwProcessorType.ToString(); <br>ProcessorLevel.Text = "CPU等级为"+CpuInfo.dwProcessorLevel.ToString(); <br>OemId.Text = "CPU的OEM ID为"+CpuInfo.dwOemId.ToString(); <br>PageSize.Text = "CPU中的页面大小为"+CpuInfo.dwPageSize.ToString(); <br>//调用GlobalMemoryStatus函数获取内存的相关信息 <br>MEMORY_INFO MemInfo; <br>MemInfo = new MEMORY_INFO(); <br>GlobalMemoryStatus(ref MemInfo); <br>MemoryLoad.Text = MemInfo.dwMemoryLoad.ToString()+"%的内存正在使用"; <br>TotalPhys.Text = "物理内存共有"+MemInfo.dwTotalPhys.ToString()+"字节"; <br>AvailPhys.Text = "可使用的物理内存有"+MemInfo.dwAvailPhys.ToString()+"字节"; <br>TotalPageFile.Text = "交换文件总大小为"+MemInfo.dwTotalPageFile.ToString()+"字节"; <br>AvailPageFile.Text = "尚可交换文件大小为"+MemInfo.dwAvailPageFile.ToString()+"字节"; <br>TotalVirtual.Text = "总虚拟内存有"+MemInfo.dwTotalVirtual.ToString()+"字节"; <br>AvailVirtual.Text = "未用虚拟内存有"+MemInfo.dwAvailVirtual.ToString()+"字节"; <br>//调用GetSystemTime函数获取系统时间信息 <br>SYSTEMTIME_INFO StInfo; <br>StInfo = new SYSTEMTIME_INFO(); <br>GetSystemTime(ref StInfo); <br>Date.Text = StInfo.wYear.ToString()+"年"+StInfo.wMonth.ToString()+"月"+StInfo.wDay.ToString()+"日"; <br>Time.Text = (StInfo.wHour+8).ToString()+"点"+StInfo.wMinute.ToString()+"分"+StInfo.wSecond.ToString()+"秒"; <br>}&nbsp;&nbsp; </p>
<img src ="http://www.cppblog.com/eday/aggbug/32458.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-09-19 10:56 <a href="http://www.cppblog.com/eday/articles/32458.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编写高性能Web应用程序的10个入门技巧</title><link>http://www.cppblog.com/eday/articles/32421.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 18 Sep 2007 08:06:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/32421.html</guid><description><![CDATA[　　使用 ASP.NET 编写 Web 应用程序的简单程度令人不敢相信。正因为如此简单，所以很多开发人员就不会花时间来设计其应用程序的结构，以获得更好的性能了。在本文中，我将讲述 10 个用于编写高性能 Web 应用程序的技巧。但是我并不会将这些建议仅局限于ASP.NET 应用程序，因为这些应用程序只是 Web 应用程序的一部分。本文不作为对 Web应用程序进行性能调整的权威性指南 — 一整本书恐怕都无法轻松讲清楚这个问题。请将本文视作一个很好的起点。<br><br>　　成为工作狂之前，我原来喜欢攀岩。在进行任何大型攀岩活动之前，我都会首先仔细查看指南中的路线，阅读以前游客提出的建议。但是，无论指南怎么好，您都需要真正的攀岩体验，然后才能尝试一个特别具有挑战性的攀登。与之相似，当您面临修复性能问题或者运行一个高吞吐量站点的问题时，您只能学习如何编写高性能 Web 应用程序。<br><br>　　我的个人体验来自在 Microsoft 的 ASP.NET 部门作为基础架构程序经理的经验，在此期间我运行和管理 www.ASP.NET，帮助设计社区服务器的结构，社区服务器是几个著名 <br>ASP.NET 应用程序（组合到一个平台的 ASP.NET Forums、.Text 和 nGallery）。我确信有些曾经帮助过我的技巧对您肯定也会有所帮助。<br><br>　　您应该考虑将应用程序分为几个逻辑层。您可能听说过 3 层（或者 n 层）物理体系结构一词。这些通常都是规定好的体系结构方式，将功能在进程和/或硬件之间进行了物理分离。当系统需要扩大时，可以很轻松地添加更多的硬件。但是会出现一个与进程和机器跳跃相关的性能下降，因此应该避免。所以，如果可能的话，请尽量在同一个应用程序中一起运行 ASP.NET 页及其相关组件。<br><br>　　因为代码分离以及层之间的边界，所以使用 Web 服务或远程处理将会使得性能下降 20% 甚至更多。<br><br>　　数据层有点与众不同，因为通常情况下，最好具有专用于数据库的硬件。然而进程跳跃到数据库的成本依然很高，因此数据层的性能是您在优化代码时首先要考虑的问题。<br><br>　　在深入应用程序的性能修复问题之前，请首先确保对应用程序进行剖析，以便找出具体的问题所在。主要性能计数器（如表示执行垃圾回收所需时间百分比的计数器）对于找出应用程序在哪些位置花费了其主要时间也非常有用。然而花费时间的位置通常非常不直观。<br><br>　　本文讲述了两种类型的性能改善：大型优化（如使用 ASP.NET 缓存），和进行自身重复的小型优化。这些小型优化有时特别有意思。您对代码进行一点小小的更改，就会获得很多很多时间。使用大型优化，您可能会看到整体性能的较大飞跃。而使用小型优化时，对于某个特定请求可能只会节省几毫秒的时间，但是每天所有请求加起来，则可能会产生巨大的改善。<br><br>　　<strong>数据层性能</strong><br><br>　　谈到应用程序的性能调整，有一个试纸性的测试可用来对工作进行优先级划分：代码是否访问数据库？如果是，频率是怎样的？请注意，这一相同测试也可应用于使用 Web 服务或远程处理的代码，但是本文对这些内容未做讲述。<br><br>　　如果某个特定的代码路径中必需进行数据库请求，并且您认为要首先优化其他领域（如字符串操作），则请停止，然后执行这个试纸性测试。如果您的性能问题不是非常严重的话，最好花一些时间来优化一下与数据库、返回的数据量、进出数据库的往返频率相关的花费时间。<br><br>　　了解这些常规信息之后，我们来看一下可能会有助于提高应用程序性能的十个技巧。首先，我要讲述可能会引起最大改观的更改。<br><br>　　<strong>技巧 1 — 返回多个结果集</strong><br><br>　　仔细查看您的数据库代码，看是否存在多次进入数据库的请求路径。每个这样的往返都会降低应用程序可以提供的每秒请求数量。通过在一个数据库请求中返回多个结果集，可以节省与数据库进行通信所需的总时间长度。同时因为减少了数据库服务器管理请求的工作，还会使得系统伸缩性更强。<br><br>　　虽然可以使用动态 SQL 返回多个结果集，但是我首选使用存储过程。关于业务逻辑是否应该驻留于存储过程的问题还存在一些争议，但是我认为，如果存储过程中的逻辑可以约束返回数据的话（缩小数据集的大小、缩短网络上所花费时间，不必筛选逻辑层的数据），则应赞成这样做。<br><br>　　使用 SqlCommand 实例及其 ExecuteReader 方法填充强类型的业务类时，可以通过调用NextResult 将结果集指针向前移动。图 1 显示了使用类型类填充几个 ArrayList 的示例会话。只从数据库返回您需要的数据将进一步减少服务器上的内存分配。 <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e6e6e3 border=1>
    <tbody>
        <tr>
            <td>Figure 1 Extracting Multiple Resultsets from a DataReader<br>// read the first resultset<br>reader = command.ExecuteReader();<br><br>// read the data from that resultset<br>while (reader.Read()) {<br>suppliers.Add(PopulateSupplierFromIDataReader( reader ));<br>}<br><br>// read the next resultset<br>reader.NextResult();<br><br>// read the data from that second resultset<br>while (reader.Read()) {<br>products.Add(PopulateProductFromIDataReader( reader ));<br>}</td>
        </tr>
    </tbody>
</table>
<br>　　<strong>技巧 2 — 分页的数据访问</strong><br><br>　　ASP.NET DataGrid 具有一个很好的功能：数据分页支持。在 DataGrid 中启用分页时，一次会显示固定数量的记录。另外，在 DataGrid 的底部还会显示分页 UI，以便在记录之间进行导航。该分页 UI 使您能够在所显示的数据之间向前和向后导航，并且一次显示固定数量的记录。<br><br>　　还有一个小小的波折。使用 DataGrid 的分页需要所有数据均与网格进行绑定。例如，您的数据层需要返回所有数据，那么 DataGrid 就会基于当前页筛选显示的所有记录。如果通过 DataGrid 进行分页时返回了 100,000 个记录，那么针对每个请求会放弃 99,975 个记录（假设每页大小为 25 个记录）。当记录的数量不断增加时，应用程序的性能就会受到影响，因为针对每个请求必须发送越来越多的数据。<br><br>　　要编写性能更好的分页代码，一个极佳的方式是使用存储过程。图 2 显示了针对Northwind 数据库中的 Orders 表进行分页的一个示例存储过程。简而言之，您此时要做的只是传递页索引和页大小。然后就会计算合适的结果集，并将其返回。 <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e6e6e3 border=1>
    <tbody>
        <tr>
            <td>Figure 2 Paging Through the Orders Table<br>CREATE PROCEDURE northwind_OrdersPaged<br>(<br>@PageIndex int, <br>@PageSize int<br>)<br>AS<br>BEGIN<br>DECLARE @PageLowerBound int<br>DECLARE @PageUpperBound int<br>DECLARE @RowsToReturn int<br><br>-- First set the rowcount<br>SET @RowsToReturn = @PageSize * (@PageIndex + 1)<br>SET ROWCOUNT @RowsToReturn<br><br>-- Set the page bounds<br>SET @PageLowerBound = @PageSize * @PageIndex<br>SET @PageUpperBound = @PageLowerBound + @PageSize + 1<br><br>-- Create a temp table to store the select results<br>CREATE TABLE #PageIndex <br>(<br>IndexId int IDENTITY (1, 1) NOT NULL,<br>OrderID int<br>)<br><br>-- Insert into the temp table<br>INSERT INTO #PageIndex (OrderID)<br>SELECT <br>OrderID<br>FROM <br>Orders<br>ORDER BY <br>OrderID DESC<br><br>-- Return total count<br>SELECT COUNT(OrderID) FROM Orders<br><br>-- Return paged results<br>SELECT <br>O.*<br>FROM <br>Orders O,<br>#PageIndex PageIndex<br>WHERE <br>O.OrderID = PageIndex.OrderID AND<br>PageIndex.IndexID ＞ @PageLowerBound AND<br>PageIndex.IndexID ＜ @PageUpperBound<br>ORDER BY <br>PageIndex.IndexID<br><br>END</td>
        </tr>
    </tbody>
</table>
<br>　　在社区服务器中，我们编写了一个分页服务器控件，以完成所有的数据分页。您将会看到，我使用的就是技巧 1 中讨论的理念，从一个存储过程返回两个结果集：记录的总数和请求的数据。<br><br>　　返回记录的总数可能会根据所执行查询的不同而有所变化。例如，WHERE 子句可用来约束返回的数据。为了计算在分页 UI 中显示的总页数，必须了解要返回记录的总数。例如，如果总共有 1,000,000 条记录，并且要使用一个 WHERE 子句将其筛选为 1000 条记录，那么分页逻辑就需要了解记录的总数才能正确呈现分页 UI。<br><br>　　<strong>技巧 3 — 连接池</strong><br><br>　　在 Web 应用程序和 SQL Server之间设置 TCP 连接可能是一个非常消耗资源的操作。Microsoft 的开发人员到目前为止能够使用连接池已经有一段时间了，这使得他们能够重用数据库连接。他们不是针对每个请求都设置一个新的 TCP 连接，而是只在连接池中没有任何连接时才设置新连接。当连接关闭时，它会返回连接池，在其中它会保持与数据库的连接，而不是完全破坏该 TCP 连接。<br><br>　　当然，您需要小心是否会出现泄漏连接。当您完成使用连接时，请一定要关闭这些连接。再重复一遍：无论任何人对 Microsoft?.NET Framework 中的垃圾回收有什么评论，请一定要在完成使用连接时针对该连接显式调用 Close 或 Dispose。不要相信公共语言运行库(CLR) 会在预先确定的时间为您清除和关闭连接。尽管 CLR 最终会破坏该类，并强制连接关闭，但是当针对对象的垃圾回收真正发生时，并不能保证。 <br><br>　　要以最优化的方式使用连接池，需要遵守一些规则。首先打开连接，执行操作，然后关闭该连接。如果您必须如此的话，可以针对每个请求多次打开和关闭连接（最好应用技巧 1），但是不要一直将连接保持打开状态并使用各种不同的方法对其进行进出传递。第二，使用相同的连接字符串（如果使用集成身份验证的话，还要使用相同的线程标识）。如果不使用相同的连接字符串，例如根据登录的用户自定义连接字符串，那么您将无法得到连接池提供的同一个优化值。如果您使用集成身份验证，同时还要模拟大量用户，连接池的效率也会大大下降。尝试跟踪与连接池相关的任何性能问题时，.NET CLR 数据性能计数器可能非常有用。 <br><br>　　每当应用程序连接资源时，如在另一个进程中运行的数据库，您都应该重点考虑连接该资源所花时间、发送或检索数据所花时间，以及往返的数量，从而进行优化。优化应用程序中任何种类的进程跳跃都是获得更佳性能的首要一点。<br><br>　　应用层包含了连接数据层、将数据转换为有意义类实例和业务流程的逻辑。例如社区服务器，您要在其中填充Forums 或 Threads集合，应用业务规则（如权限）；最重要的是要在其中执行缓存逻辑。<br><br>　　<strong>技巧 4 — ASP.NET 缓存 API</strong><br><br>　　编写应用程序代码行之前，一个首要完成的操作是设计应用层的结构，以便最大化利用ASP.NET 缓存功能。<br><br>　　如果您的组件要在 ASP.NET 应用程序中运行，则只需在该应用程序项目中包括一个System.Web.dll 引用。当您需要访问该缓存时，请使用 HttpRuntime.Cache 属性（通过Page.Cache 和 HttpContext.Cache 也可访问这个对象）。<br><br>　　对于缓存数据，有几个规则。首先，如果数据可能会多次使用时，则这是使用缓存的一个很好的备选情况。第二，如果数据是通用的，而不特定于某个具体的请求或用户时，则也是使用缓存的一个很好的备选情况。如果数据是特定于用户或请求的，但是寿命较长的话，仍然可以对其进行缓存，但是这种情况可能并不经常使用。第三，一个经常被忽略的规则是，有时可能您缓存得太多。通常在一个 x86 计算机上，为了减少内存不足错误出现的机会，您会想使用不高于 800MB 的专用字节运行进程。因此缓存应该有个限度。换句话说，您可能能够重用某个计算结果，但是如果该计算采用 10 个参数的话，您可能要尝试缓存 10 个排列，这样有可能给您带来麻烦。一个要求 ASP.NET 的最常见支持是由于过度缓存引起的内存不足错误，尤其是对于大型数据集。<br><br>　　缓存有几个极佳的功能，您需要对它们有所了解。首先，缓存会实现最近最少使用的算法，使得 ASP.NET 能够在内存运行效率较低的情况下强制缓存清除 － 从缓存自动删除未使用过的项目。第二，缓存支持可以强制失效的过期依赖项。这些依赖项包括时间、密钥和文件。时间经常会用到，但是对于 ASP.NET 2.0，引入了一个功能更强的新失效类型：数据库缓存失效。它指的是当数据库中的数据发生变化时自动删除缓存中的项。有关数据库缓存失效的详细信息，请参阅 MSDN?Magazine 2004 年 7 月的 Dino Esposito Cutting Edge 专栏。要了解缓存的体系结构，请参阅下图。<br><br>
<table width="90%" align=center border=0>
    <tbody>
        <tr>
            <td>
            <div align=center><a href="http://byhh.net/f/DotNet/1160999024/us0501ASPNETPerformancefig03.gif" target=_blank name=expandurl><img alt="" src="http://dev.yesky.com/imagelist/06/44/90ooi68h5734.gif" onload="javascript:if(this.width>480)this.width=480" border=0></a></div>
            </td>
        </tr>
    </tbody>
</table>
<br>　　<strong>技巧 5 — 每请求缓存</strong><br><br>　　在本文前面部分，我提到了经常遍历代码路径的一些小改善可能会导致较大的整体性能收益。对于这些小改善，其中有一个绝对是我的最爱，我将其称之为"每请求缓存"。<br><br>　　缓存 API 的设计目的是为了将数据缓存较长的一段时间，或者缓存至满足某些条件时，但每请求缓存则意味着只将数据缓存为该请求的持续时间。对于每个请求，要经常访问某个特定的代码路径，但是数据却只需提取、应用、修改或更新一次。这听起来有些理论化，那么我们来举一个具体的示例。<br><br>　　在社区服务器的论坛应用程序中，页面上使用的每个服务器控件都需要个性化的数据来确定使用什么外观、使用什么样式表，以及其他个性化数据。这些数据中有些可以长期缓存，但是有些数据却只针对每个请求提取一次，然后在执行该请求期间对其重用多次，如要用于控件的外观。<br><br>　　为了达到每请求缓存，请使用 ASP.NET HttpContext。对于每个请求，都会创建一个HttpContext 实例，在该请求期间从 HttpContext.Current 属性的任何位置都可访问该实例。该 HttpContext 类具有一个特殊的 Items 集合属性；添加到此 Items 集合的对象和数据只在该请求持续期间内进行缓存。正如您可以使用缓存来存储经常访问的数据一样，您也可以使用 HttpContext.Items 来存储只基于每个请求使用的数据。它背后的逻辑非常简单：数据在它不存在的时候添加到 HttpContext.Items 集合，在后来的查找中，只是返回 HttpContext.Items 中的数据。<br><br>　　<strong>技巧 6 — 后台处理</strong><br><br>　　通往代码的路径应该尽可能快速，是吗？可能有时您会觉得针对每个请求执行的或者每n 个请求执行一次的任务所需资源非常多。发送电子邮件或者分析和验证传入数据就是这样的一些例子。<br><br>　　剖析 ASP.NET Forums 1.0 并重新构建组成社区服务器的内容时，我们发现添加新张贴的代码路径非常慢。每次添加新张贴时，应用程序首先需要确保没有重复的张贴，然后必须使用"坏词"筛选器分析该张贴，分析张贴的字符图释，对张贴添加标记并进行索引，请求时将张贴添加到合适的队列，验证附件，最终张贴之后，立即向所有订阅者发出电子邮件通知。很清楚，这涉及很多操作。<br><br>　　经研究发现，大多数时间都花在了索引逻辑和发送电子邮件上。对张贴进行索引是一个非常耗时的操作，人们发现内置的 System.Web.Mail 功能要连接 SMYP 服务器，然后连续发送电子邮件。当某个特定张贴或主题领域的订阅者数量增加时，执行 AddPost 功能所需的时间也越来越长。<br><br>　　并不需要针对每个请求都进行电子邮件索引。理想情况下，我们想要将此操作进行批处理，一次索引 25 个张贴或者每五分钟发送一次所有电子邮件。我们决定使用以前用于对数据缓存失效进行原型设计的代码，这个失效是用于最终进入 Visual Studio? 2005 的内容的。<br><br>　　System.Threading 命名空间中的 Timer 类非常有用，但是在 .NET Framework 中不是很有名，至少对于 Web 开发人员来说是这样。创建之后，这个 Timer 类将以一个可配置的间隔针对 ThreadPool 中的某个线程调用指定的回调。这就表示，您可以对代码进行设置，使其能够在没有对 ASP.NET 应用程序进行传入请求的情况下得以执行，这是后台处理的理想情况。您还可以在此后台进程中执行如索引或发送电子邮件之类的操作。 <br><br>　　但是，这一技术有几个问题。如果应用程序域卸载，该计时器实例将停止触发其事件。另外，因为 CLR 对于每个进程的线程数量具有一个硬性标准，所以可能会出现这样的情形：服务器负载很重，其中计时器可能没有可在其基础上得以完成的线程，在某种程度上可能会造成延迟。ASP.NET 通过在进程中保留一定数量的可用线程，并且仅使用总线程的一部分用于请求处理，试图将上述情况发生的机会降到最低。但是，如果您具有很多异步操作时，这可能就是一个问题了。 <br><br>　　这里没有足够的空间来放置该代码，但是您可以下载一个可以看懂的示例，网址是www.rob-howard.net。请了解一下 Blackbelt TechEd 2004 演示中的幻灯片和演示。<br><br>　　<strong>技巧 7 — 页输出缓存和代理服务器</strong><br><br>　　ASP.NET 是您的表示层（或者说应该是您的表示层）；它由页、用户控件、服务器控件（HttpHandlers 和 HttpModules）以及它们生成的内容组成。如果您具有一个 ASP.NET 页，它会生成输出（HTML、XML、图像或任何其他数据），并且您针对每个请求运行此代码时，它都会生成相同的输出，那么您就拥有一个可用于页输出缓存的绝佳备选内容。 <br><br>　　将此行内容添加页的最上端 ＜%@ Page OutputCache VaryByParams="none" Duration="60" %＞ <br><br>　　就可以高效地为此页生成一次输出，然后对它进行多次重用，时间最长为 60 秒，此时该页将重新执行，输出也将再一次添加到 ASP.NET 缓存。通过使用一些低级程序化 API 也可以完成此行为。对于输出缓存有几个可配置的设置，如刚刚讲到的 VaryByParams 属性。VaryByParams 刚好被请求到，但还允许您指定 HTTP GET 或 HTTP POST 参数来更改缓存项。例如，只需设置 VaryByParam="Report" 即可对 default.aspx?Report=1 或 default.aspx?Report=2 进行输出缓存。通过指定一个以分号分隔的列表，还可以指定其他参数。 <br><br>　　很多人都不知道何时使用输出缓存，ASP.NET 页还会生成一些位于缓存服务器下游的HTTP 标头，如 Microsoft Internet Security and Acceleration Server 或 Akamai 使用的标头。设置了 HTTP 缓存标头之后，可以在这些网络资源上对文档进行缓存，客户端请求也可在不必返回原始服务器的情况下得以满足。<br><br>　　因此，使用页输出缓存不会使得您的应用程序效率更高，但是它可能会减少服务器上的负载，因为下游缓存技术会缓存文档。当然，这可能只是匿名内容；一旦它成为下游之后，您就再也不会看到这些请求，并且再也无法执行身份验证以阻止对它的访问了。<br><br>　　<strong>技巧 8 — 运行 IIS 6.0（只要用于内核缓存）<br></strong><br>　　如果您未运行 IIS 6.0 (Windows Server? 2003)，那么您就错过了 Microsoft Web 服务器中的一些很好的性能增强。在技巧 7 中，我讨论了输出缓存。在 IIS 5.0 中，请求是通过 IIS 然后进入 ASP.NET 的。涉及到缓存时，ASP.NET 中的 HttpModule 会接收该请求，并返回缓存中的内容。<br><br>　　如果您正在使用 IIS 6.0，就会发现一个很好的小功能，称为内核缓存，它不需要对ASP.NET 进行任何代码更改。当请求由 ASP.NET 进行输出缓存时，IIS 内核缓存会接收缓存数据的一个副本。当请求来自网络驱动程序时，内核级别的驱动程序（无上下文切换到用户模式）就会接收该请求，如果经过了缓存，则会将缓存的数据刷新到响应，然后完成执行。这就表示，当您将内核模式缓存与 IIS 和 ASP.NET 输出缓存一起使用时，就会看到令人不敢相信的性能结果。在 ASP.NET 的 Visual Studio 2005 开发过程中，我一度是负责 ASP.NET 性能的程序经理。开发人员完成具体工作，但是我要看到每天进行的所有报告。内核模式缓存结果总是最有意思的。最常见的特征是网络充满了请求/响应，而 IIS 运行时的 CPU 使用率只有大约 5%。这太令人震惊了！当然使用 IIS 6.0 还有一些其他原因，但是内核模式缓存是其中最明显的一个。<br><br>　　<strong>技巧 9 — 使用 Gzip 压缩</strong><br><br>　　虽然使用 gzip 并不一定是服务器性能技巧（因为您可能会看到 CPU 使用率的提高），但是使用 gzip 压缩可以减少服务器发送的字节数量。这就使人们觉得页速度加快了，并且还减少了带宽的用量。根据所发送数据、可以压缩的程度以及客户端浏览器是否支持（IIS只会向支持 gzip 压缩的客户端发送经过 gzip 压缩的内容，如 Internet Explorer 6.0 和 Firefox），您的服务器每秒可以服务于更多的请求。实际上，几乎每当您减少所返回数据的数量时，都会增加每秒请求数。 <br><br>　　Gzip 压缩已经内置到 IIS 6.0 中，并且其性能比 IIS 5.0 中使用的 gzip 压缩要好的多，这是好消息。但不幸的是，当尝试在 IIS 6.0 中打开 gzip 压缩时，您可能无法在IIS 的属性对话中找到该设置。IIS 小组在该服务器中置入了卓越的 gzip 功能，但是忘了包括一个用于启用该功能的管理 UI。要启用 gzip 压缩，您必须深入到 IIS 6.0 的 XML 配置设置内部（这样不会引起心脏虚弱）。顺便提一句，这归功于 OrcsWeb 的 Scott Forsyth，他帮助我提出了在 OrcsWeb 上宿主的 www.asp.net 服务器的这个问题。<br><br>　　本文就不讲述步骤了，请阅读 Brad Wilson 的文章，网址是 IIS6 Compression。还有一篇有关为 ASPX 启用压缩的知识库文章，网址是 Enable ASPX Compression in IIS。但是您应该注意，由于一些实施细节，IIS 6.0 中不能同时存在动态压缩和内核缓存。<br><br>　　<strong>技巧 10 — 服务器控件视图状态</strong><br><br>　　视图状态是一个有趣的名称，用于表示在所生成页的隐藏输出字段中存储一些状态数据的ASP.NET。当该页张贴回服务器时，服务器可以分析、验证、并将此视图状态数据应用回该页的控件树。视图状态是一个非常强大的功能，因为它允许状态与客户端一起保持，并且它不需要 cookie 或服务器内存即可保存此状态。很多 ASP.NET 服务器控件都使用视图状态来保持在与页元素进行交互期间创建的设置，例如保存对数据进行分页时显示的当前页。 <br><br>　　然而使用视图状态也有一些缺点。首先，服务或请求页时，它都会增加页的总负载。对张贴回服务器的视图状态数据进行序列化或取消序列化时，也会发生额外的开销。最后，视图状态会增加服务器上的内存分配。<br><br>　　几个服务器控件有着过度使用视图状态的趋势，即使在并不需要的情况下也要使用它，其中最著名的是 DataGrid。ViewState 属性的默认行为是启用，但是如果您不需要，则可以在控件或页级别关闭。在控件内，只需将 EnableViewState 属性设置为 false，或者在页中使用下列设置即可对其进行全局设置： <br><br>＜%@ Page EnableViewState="false" %＞<br><br>　　如果您不回发页，或者总是针对每个请求重新生成页上的控件，则应该在页级别禁用视图状态。 <br><br>　　我为您讲述了一些我认为在编写高性能 ASP.NET 应用程序时有所帮助的技巧。正如我在本文前面部分提到的那样，这是一个初步指南，并不是 ASP.NET 性能的最后结果。（有关改善 ASP.NET 应用程序性能的信息，请参阅 Improving ASP.NET Performance。）只有通过自己的亲身体验才能找出解决具体性能问题的最好方法。但是，在您的旅程中，这些技巧应该会为您提供一些好的指南。在软件开发中，几乎没有绝对的东西；每个应用程序都是唯一的。 <br>
<img src ="http://www.cppblog.com/eday/aggbug/32421.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-09-18 16:06 <a href="http://www.cppblog.com/eday/articles/32421.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ASP.NET 2.0 异步页面技术</title><link>http://www.cppblog.com/eday/articles/32420.html</link><dc:creator>松*</dc:creator><author>松*</author><pubDate>Tue, 18 Sep 2007 08:04:00 GMT</pubDate><guid>http://www.cppblog.com/eday/articles/32420.html</guid><description><![CDATA[　　ASP.NET 2.0 提供了大量新功能，其中包括声明性数据绑定和母版页，成员和角色管理服务等。但我认为最棒的功能是异步页，接下来让我告诉您其中的原因。<br>　　当 ASP.NET 接收针对页的请求时，它从线程池中提取一个线程并将请求分配给该线程。一个普通的（或同步的）页在该请求期间保留线程，从而防止该线程用于处理其他请求。如果一个同步请求成为 I/O 绑定（例如，如果它调用一个远程 Web 服务或查询一个远程数据库，并等待调用返回），那么分配给该请求的线程在调用返回之前处于挂起状态。这影响了可伸缩性，原因是线程池的可用线程是有限的。如果所有请求处理线程全部阻塞以等待 I/O 操作完成，则其他请求排入队列等待线程释放。最好的情况是吞吐量减少，因为请求等待较长的时间才能得到处理。最坏的情况则是该队列填满，并且 ASP.NET 因 503&#8220;Server Unavailable&#8221;错误使后续请求失败。<br><br>　　异步页为由 I/O 绑定的请求引起的问题提供优秀的解决方案。页处理从线程池线程开始，但是当一个异步 I/O 操作开始响应 ASP.NET 的信号之后，该线程返回线程池。当该操作完成时，ASP.NET 从线程池提取另一个线程，并完成该请求的处理。由于线程池线程得到了更高效的使用，因此提高了可伸缩性。那些挂起等待 I/O 完成的线程现在可用于服务其他请求。直接的受益方是不执行长时间 I/O 操作并因此可以快速进出管线的请求。长时间等待进入管线会对此类请求的性能带来不小的负面影响。<br>　　ASP.NET 2.0 Beta 2 异步页基础结构的相关文档很少。让我们展望一下异步页的前景，从而弥补这点不足。请记住，本专栏涉及 ASP.NET 2.0 和 .NET Framework 2.0 的测试版本。。<br><br>　　<strong>ASP.NET 1.x 中的异步页</strong> <br><br>　　ASP.NET 1.<em>x</em> 本质上不支持异步页，但是通过坚韧的努力和不懈地创新可以生成异步页。有关更多概述信息，请参阅相关资料<br><br>　　这里的技巧是，在一个页的代码隐藏类中实现 IhttpAsyncHandler，从而提示 ASP.NET 通过调用 IHttpAsyncHandler.BeginProcessRequest 来处理请求，而不是通过调用该页的 IHttpHandler.ProcessRequest 方法。然后，您的 BeginProcessRequest 实现可以启动另一个线程。该线程调用 base.ProcessRequest，使得页进入其常规请求处理生命周期（完成诸如 Load 和 Render 的事件），但是在非 ThreadPool 线程上例外。同时，启动新线程之后 BeginProcessRequest 立即返回，从而允许执行 BeginProcessRequest 的线程返回线程池。<br><br>　　这是基本思想，但细节中还有很多注意事项。其中，您需要实现 IAsyncResult，并从 BeginProcessRequest 中返回它。这通常意味着创建一个 ManualResetEvent 对象，并且当 ProcessRequest 在后台线程中返回时向其发送信号。此外，您必须提供调用 base.ProcessRequest 的线程。遗憾的是，多数用于将工作移到后台线程的常规技术（包括 Thread.Start、ThreadPool.QueueUserWorkItem 和异步委托）在 ASP.NET 应用程序中都是起反作用的，因为它们或者从线程池&#8220;偷盗&#8221;线程，或者有不受限制的线程增长的危险。正确的异步页实现使用自定义线程池，但自定义线程池类不容易编写。<br><br>　　主要是在 ASP.NET 1.<em>x</em> 中生成异步页并非不可能，而是有些乏味。在尝试一、两次之后，您不禁会想一定会有更好的方法。目前，这个好方法就是 ASP.NET 2.0。<br><br>　　<strong>ASP.NET 2.0 中的异步页 </strong><br><br>　　ASP.NET 2.0 极大地简化了生成异步页的方式。首先使用该页的 @ Page 指令引入 Async=&#8220;true&#8221; 属性，如下所示： <br><br>　　在后台，这会通知 ASP.NET 在该页中实现 IhttpAsyncHandler。接下来，您在该页生存期的早期（例如，在 Page_Load 时）调用新的 Page.AddOnPreRenderCompleteAsync 方法来注册一个 Begin 方法和一个 End 方法，如以下代码所示： <br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>
            <pre class=codeSample>AddOnPreRenderCompleteAsync (
            new BeginEventHandler(MyBeginMethod),
            new EndEventHandler (MyEndMethod)
            );</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>　　接下来的操作比较有趣。该页经历其常规处理生命周期，直到 PreRender 事件刚刚引发之后。然后，ASP.NET 调用使用 AddOnPreRenderCompleteAsync 注册的 Begin 方法。Begin 方法的任务是启动诸如数据库查询或 Web 服务调用的异步操作，并立即返回。此时，分配给该请求的线程返回到线程池。此外，Begin 方法返回 IAsyncResult，它允许 ASP.NET 确定异步操作完成的时间，这个时候 ASP.NET 从线程池提取线程并调用 End 方法。当 End 返回之后，ASP.NET 执行该页生命周期其余的部分，包括呈现阶段。在 Begin 返回以及调用 End 之间，该请求处理线程可以自由地服务于其他请求，直至调用 End 且延迟呈现为止。由于 2.0 版的 .NET Framework 提供多种执行异步操作的方式，因此，您甚至无需实现 IasyncResult。反之，Framework 替您实现。<br><br>　　图 1 中的代码隐藏类提供一个示例。响应页包含一个 ID 为&#8220;Output&#8221;的 Label 控件。该页使用 System.Net.HttpWebRequest 类提取 http://MSDN.microsoft.com 的内容。然后，它分析返回的 HTML，并将它发现的全部 HREF 目标列表写出到 Label 控件。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>图1<br><br>using System;<br>using System.Web;<br>using System.Web.UI;<br>using System.Web.UI.WebControls;<br>using System.Net;<br>using System.IO;<br>using System.Text;<br>using System.Text.RegularExpressions;
            <p>public partial class AsyncPage : System.Web.UI.Page<br>{<br>　private WebRequest _request;</p>
            <p>　void Page_Load (object sender, EventArgs e)<br>　{<br>　　AddOnPreRenderCompleteAsync (<br>　　　new BeginEventHandler(BeginAsyncOperation),<br>　　　new EndEventHandler (EndAsyncOperation)<br>　　);<br>　}</p>
            <p>　IAsyncResult BeginAsyncOperation (object sender, EventArgs e, <br>AsyncCallback cb, object state)<br>　{<br>　　_request = WebRequest.Create("http://msdn.microsoft.com");<br>　　return _request.BeginGetResponse (cb, state);<br>　}<br>　void EndAsyncOperation (IAsyncResult ar)<br>　{<br>　　string text;<br>　　using (WebResponse response = _request.EndGetResponse(ar))<br>　　{<br>　　　using (StreamReader reader = new StreamReader(response.GetResponseStream()))<br>　　　{<br>　　　　text = reader.ReadToEnd();<br>　　　}<br>　　}</p>
            <p>　　Regex regex = new Regex ("href\\s*=\\s*\"([^\"]*)\"", RegexOptions.IgnoreCase);<br>　　MatchCollection matches = regex.Matches(text);</p>
            <p>　　StringBuilder builder = new StringBuilder(1024);<br>　　foreach (Match match in matches)<br>　　{<br>　　　builder.Append (match.Groups[1]);<br>　　　builder.Append("&lt;br/&gt;");<br>　　}</p>
            <p>　　Output.Text = builder.ToString ();<br>　}<br>}</p>
            <p>&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
<br>　　由于 HTTP 请求需要较长时间才能返回，因此，AsyncPage.aspx.cs 异步执行对它的处理。它在 Page_Load 中注册 Begin 和 End 方法，并且在 Begin 方法中，它调用 HttpWebRequest.BeginGetResponse 启用一个异步 HTTP 请求。BeginAsyncOperation 将由 BeginGetResponse 返回的 IAsyncResult 返回到 ASP.NET，导致当 HTTP 请求完成时，ASP.NET 调用 EndAsyncOperation。EndAsyncOperation 进而分析该内容并将结果写入 Label 控件，之后进行呈现，并且 HTTP 响应返回到浏览器。<br><br><img height=365 alt="" src="http://dev.yesky.com/imagelist/06/19/6hn43kd22343.gif" width=354 border=0><br>
<p class=figureCaption>图 2 同步和异步页处理<br><br>　　图 2 说明 ASP.NET 2.0 同步和异步页之间的区别。当请求同步页时，ASP.NET 为该请求分配线程池中的一个线程，并在该线程上执行页。如果该请求停止执行 I/O 操作，则挂起线程，直到完成操作，从而可以完成该页的生命周期。相反，异步页通常通过 PreRender 事件执行。然后，调用使用 AddOnPreRenderCompleteAsync 注册的 Begin 方法，之后，该请求处理线程返回线程池。Begin 启动一个异步 I/O 操作，当该操作完成时，ASP.NET 从线程池提取另一个线程并调用 End 方法，并且在该线程上执行该页生命周期的其余部分。<br><br><img height=255 alt="" src="http://dev.yesky.com/imagelist/06/19/aq88dfsw17w7.gif" width=400 border=0><br>
<p class=figureCaption>图 3 跟踪输出显示异步页的异步点<br><br>　　对 Begin 的调用标记该页的&#8220;异步点&#8221;。图 3 中的跟踪准确显示异步点发生在何处。如果调用，则必须在异步点之前调用 AddOnPreRenderCompleteAsync — 即，不晚于该页的 PreRender 事件。<br><br>　　<strong>异步数据绑定</strong><br><br>　　通常情况下，ASP.NET 页并不使用 HttpWebRequest 直接请求其他页，但它们通常查询数据库并对结果进行数据绑定。因此，您将如何使用异步页执行异步数据绑定呢？图 4 中的代码隐藏类显示进行此操作的一种方式。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>using System;<br>using System.Data;<br>using System.Data.SqlClient;<br>using System.Web;<br>using System.Web.UI;<br>using System.Web.UI.WebControls;<br>using System.Web.Configuration;
            <p>public partial class AsyncDataBind : System.Web.UI.Page<br>{<br>　private SqlConnection _connection;<br>　private SqlCommand _command;<br>　private SqlDataReader _reader;</p>
            <p>　protected void Page_Load(object sender, EventArgs e)<br>　{<br>　　if (!IsPostBack)<br>　　{<br>　　　// Hook PreRenderComplete event for data binding<br>　　　this.PreRenderComplete += new EventHandler(Page_PreRenderComplete);</p>
            <p>　　　// Register async methods<br>　　　AddOnPreRenderCompleteAsync(<br>　　　　new BeginEventHandler(BeginAsyncOperation),<br>　　　　new EndEventHandler(EndAsyncOperation)<br>　　　);<br>　　}<br>　}<br>　IAsyncResult BeginAsyncOperation (object sender, EventArgs e, AsyncCallback cb, object state)<br>　{<br>　　string connect = WebConfigurationManager.ConnectionStrings<br>["PubsConnectionString"].ConnectionString;<br>　　_connection = new SqlConnection(connect);<br>　　_connection.Open();<br>　　_command = new SqlCommand("SELECT title_id, title, price FROM titles", _connection);<br>　　return _command.BeginExecuteReader (cb, state);<br>　}</p>
            <p>　void EndAsyncOperation(IAsyncResult ar)<br>　{<br>　　_reader = _command.EndExecuteReader(ar);<br>　}</p>
            <p>　protected void Page_PreRenderComplete(object sender, EventArgs e)<br>　{<br>　　Output.DataSource = _reader;<br>　　Output.DataBind();<br>　}</p>
            <p>　public override void Dispose()<br>　{<br>　　if (_connection != null) _connection.Close();<br>　　base.Dispose();<br>　}<br>}</p>
            <p>&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p class=figureCaption>　　AsyncDataBind.aspx.cs 与 AsyncPage.aspx.cs 使用相同的 AddOnPreRenderCompleteAsync 模式。但是，AsyncDataBind.aspx.cs 的 BeginAsyncOperation 方法调用 ADO.NET 2.0 中的新方法 SqlCommand.BeginExecuteReader（而非 HttpWebRequest.BeginGetResponse），以执行一个异步数据库查询。当调用完成时，EndAsyncOperation 调用 SqlCommand.EndExecuteReader 以获取 SqlDataReader，然后将其存储在私有字段中。在用于 PreRenderComplete 事件（在异步操作完成但呈现该页之前引发）的事件处理程序中，AsyncDataBind.aspx.cs 之后将 SqlDataReader 绑定到 Output GridView 控件。从外观上看，该页类似于使用 GridView 呈现数据库查询结果的普通（同步）页。但是在内部，该页更具可伸缩性，因为它并不挂起线程池线程以等待查询返回。<br><br>　　<strong>异步调用 Web 服务</strong><br><br>　　另一个通常由 ASP.NET Web 页执行的、与 I/O 相关的任务是调出 Web 服务。由于 Web 服务调用花费较长时间才能返回，因此，执行它们的页是用于异步处理的理想选择。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>图5<br><br>using System;<br>using System.Data;<br>using System.Configuration;<br>using System.Web;<br>using System.Web.UI;<br>using System.Web.UI.WebControls;
            <p>public partial class AsyncWSInvoke1 : System.Web.UI.Page<br>{<br>　private WS.PubsWebService _ws;<br>　private DataSet _ds;</p>
            <p>　protected void Page_Load(object sender, EventArgs e)<br>　{<br>　　if (!IsPostBack)<br>　　{<br>　　　// Hook PreRenderComplete event for data binding<br>　　　this.PreRenderComplete += new EventHandler(Page_PreRenderComplete);</p>
            <p>　　　// Register async methods<br>　　　AddOnPreRenderCompleteAsync(new BeginEventHandler(BeginAsyncOperation),<br>new EndEventHandler(EndAsyncOperation)<br>　　　);<br>　　}<br>　}</p>
            <p>　IAsyncResult BeginAsyncOperation (object sender, EventArgs e, AsyncCallback cb, object state)<br>　{<br>　　_ws = new WS.PubsWebService();<br>　　// Fix up URL for call to local VWD-hosted Web service<br>　　_ws.Url = new Uri(Request.Url, "Pubs.asmx").ToString();<br>　　_ws.UseDefaultCredentials = true;<br>　　return _ws.BeginGetTitles (cb, state);<br>　}</p>
            <p>　void EndAsyncOperation(IAsyncResult ar)<br>　{<br>　　_ds = _ws.EndGetTitles(ar);<br>　}</p>
            <p>　protected void Page_PreRenderComplete(object sender, EventArgs e)<br>　{<br>　　Output.DataSource = _ds;<br>　　Output.DataBind();<br>　}</p>
            <p>　public override void Dispose()<br>　{<br>　　if (_ws != null) _ws.Dispose();<br>　　　base.Dispose();<br>　}<br>}</p>
            <p>&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p class=figureCaption>　　图 5 显示生成调出 Web 服务的异步页的方式。它使用图 1 和 图 4 中相同的 AddOnPreRenderCompleteAsync 机制。该页的 Begin 方法通过调用 Web 服务代理的异步 Begin 方法启动一个异步 Web 服务调用。该页的 End 方法在私有字段中缓存对 Web 方法返回的 DataSet 的引用，并且 PreRenderComplete 处理程序将 DataSet 绑定到 GridView。作为参考，该调用的目标 Web 方法如以下代码所示：<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>
            <p class=figureCaption>
            <pre class=codeSample>[WebMethod]
            public DataSet GetTitles ()
            {
            string connect = WebConfigurationManager.ConnectionStrings
            ["PubsConnectionString"].ConnectionString;
            SqlDataAdapter adapter = new SqlDataAdapter
            ("SELECT title_id, title, price FROM titles", connect);
            DataSet ds = new DataSet();
            adapter.Fill(ds);
            return ds;
            }</pre>
            </td>
        </tr>
    </tbody>
</table>
<br>　　这只是其中一种方式，但并不是唯一的方式。.NET Framework 2.0 Web 服务代理支持两种对 Web 服务进行异步调用的机制。一个是 .NET Framework 1.<em>x</em> 和 2.0 Web 服务代理中的每方法 Begin 和 End 方法。另一个是仅由 .NET Framework 2.0 的 Web 服务代理提供的新 MethodAsync 方法和 MethodCompleted 事件。<br><br>　　如果一个 Web 服务有一个名为 Foo 的方法，那么除了具有名为 Foo、BeginFoo 和 EndFoo 的方法外，.NET Framework 版本 2.0 Web 服务代理还包括名为 FooAsync 的方法和名为 FooCompleted 的事件。可以通过注册 FooCompleted 事件的处理程序并调用 FooAsync 来异步调用 Foo，如下所示： <br>
<p class=figureCaption>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>
            <pre class=codeSample>proxy.FooCompleted += new FooCompletedEventHandler (OnFooCompleted);
            proxy.FooAsync (...);
            ...
            void OnFooCompleted (Object source, FooCompletedEventArgs e)
            {
            // Called when Foo completes
            }
            </pre>
            </td>
        </tr>
    </tbody>
</table>
<br>　　当异步调用由于 FooAsync 完成而开始时，将引发 FooCompleted 事件，从而导致调用 FooCompleted 事件处理程序。包装该事件处理程序 (FooCompletedEventHandler) 的委托和传递给它的第二个参数 (FooCompletedEventArgs) 都随 Web 服务代理一起生成。可通过 FooCompletedEventArgs.Result 访问 Foo 的返回值。<br><br>　　图 6 展示使用 MethodAsync 模式异步调用 Web 服务的 GetTitles 方法的代码隐藏类。从功能上讲，该页等同于图 5 中的页。但其内部实现则大为不同。AsyncWSInvoke2.aspx 包括一个 @ Page Async=&#8220;true&#8221; 指令，类似于 AsyncWSInvoke1.aspx。但是，AsyncWSInvoke2.aspx.cs 并不调用 AddOnPreRenderCompleteAsync；它注册一个用于 GetTitlesCompleted 事件的处理程序，并调用 Web 服务代理上的 GetTitlesAsync。ASP.NET 仍然延迟呈现该页，直到 GetTitlesAsync 完成。在内部，当异步调用开始以及完成时，它使用 System.Threading.SynchronizationContext 的一个实例（2.0 的一个新类）接收通知。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td>图6<br><br>using System;<br>using System.Data;<br>using System.Configuration;<br>using System.Web;<br>using System.Web.UI;<br>using System.Web.UI.WebControls;
            <p>public partial class AsyncWSInvoke2 : System.Web.UI.Page<br>{<br>private WS.PubsWebService _ws;<br>private DataSet _ds;</p>
            <p>protected void Page_Load(object sender, EventArgs e)<br>{<br>　if (!IsPostBack)<br>　{<br>　　// Hook PreRenderComplete event for data binding<br>　　this.PreRenderComplete += new EventHandler(Page_PreRenderComplete);</p>
            <p>　　// Call the Web service asynchronously<br>　　_ws = new WS.PubsWebService();<br>　　_ws.GetTitlesCompleted += new <br>　　WS.GetTitlesCompletedEventHandler(GetTitlesCompleted);<br>　　_ws.Url = new Uri(Request.Url, "Pubs.asmx").ToString();<br>　　_ws.UseDefaultCredentials = true;<br>　　_ws.GetTitlesAsync();<br>　}<br>}</p>
            <p>void GetTitlesCompleted(Object source, <br>WS.GetTitlesCompletedEventArgs e)<br>{<br>　_ds = e.Result;<br>}</p>
            <p>protected void Page_PreRenderComplete(object sender, EventArgs e)<br>{<br>　Output.DataSource = _ds;<br>　Output.DataBind();<br>}</p>
            <p>public override void Dispose()<br>{<br>　if (_ws != null) _ws.Dispose();<br>　base.Dispose();<br>}<br>}</p>
            <p>&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
<br>　　使用 MethodAsync 而非 AddOnPreRenderCompleteAsync 实现异步页有两个优势。首先，MethodAsync 将模拟、区域性和 HttpContext.Current 注入 MethodCompleted 事件处理程序，而 AddOnPreRenderCompleteAsync 则不然。其次，如果该页进行多个异步调用，而且必须延迟呈现直到所有调用完成，则使用 AddOnPreRenderCompleteAsync 要求您生成一个在所有调用完成前保持无信号状态的 IasyncResult。使用 MethodAsync，这样的操作就不是必需的；您只需放置这些调用（数量不限），ASP.NET 引擎延迟该呈现阶段，直到最后一个调用返回。<br><br><br>　　<strong>异步任务</strong><br><br>　　MethodAsync 是从异步页进行多个异步 Web 服务调用并延迟呈现阶段直到所有调用完成的一个简便方法。但如果您想在一个异步页中执行若干异步 I/O 操作，而且这些操作不涉及 Web 服务，那该如何呢？ 这么说，可以反过来生成一个 IAsyncResult，它可以返回到 ASP.NET 以允许它了解最后一个调用何时完成的吗？ 幸运的是，答案是否定的。<br><br>　　在 ASP.NET 2.0 中，System.Web.UI.Page 类引入了另一个方法来简化异步操作： RegisterAsyncTask。RegisterAsyncTask 比 AddOnPreRenderCompleteAsync 具有四个优势。首先，除了 Begin 和 End 方法，RegisterAsyncTask 还允许您注册当异步操作长时间无法完成时调用的超时方法。您可以通过在该页的 @ Page 指令中包含 AsyncTimeout 属性以声明性方式设置超时。AsyncTimeout="5" 将超时设置为 5 秒。第二个优势是，您可以在一个请求中多次调用 RegisterAsyncTask 来注册若干异步操作。和使用 MethodAsync 一样，ASP.NET 延迟呈现该页，直到所有操作完成。第三，您可以使用 RegisterAsyncTask 的第四个参数将状态传递给 Begin 方法。最后，RegisterAsyncTask 将模拟、区域性和 HttpContext.Current 注入 End 和 Timeout 方法。正如本文前面提到的，使用 AddOnPreRenderCompleteAsync 注册的 End 方法的情况则不然。<br><br>　　在其他方面，依赖于 RegisterAsyncTask 的异步页与依赖于 AddOnPreRenderCompleteAsync 的异步页相类似。它仍然需要 @ Page 指令（或等效的编程指令，它会将该页的 AsyncMode 属性设置为 true）中的 Async=&#8220;true&#8221; 属性，而且它仍然与平时一样通过 PreRender 事件执行，此时调用使用 RegisterAsyncTask 注册的 Begin 方法，而且进一步保持请求处理直到最后一个操作完成。例如，图 7 中的代码隐藏类在功能上与图 1 中的等效，但是它使用 RegisterTaskAsync 而非使用 AddOnPreRenderCompleteAsync。请注意名为 TimeoutAsyncOperation 的超时处理程序，如果 HttpWebRequest.BeginGetRequest 长时间无法完成，将调用该处理程序。相应的 .aspx 文件包括一个将超时间隔设置为 5 秒的 AsyncTimeout 属性。还请注意传给 RegisterAsyncTask 的第四个参数（可用于将数据传送到 Begin 方法）的 null。<br><br>
<table borderColor=#cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
    <tbody>
        <tr>
            <td height=19>图7<br><br>using System;<br>using System.Web;<br>using System.Web.UI;<br>using System.Web.UI.WebControls;<br>using System.Net;<br>using System.IO;<br>using System.Text;<br>using System.Text.RegularExpressions;
            <p>public partial class AsyncPageTask : System.Web.UI.Page<br>{<br>　private WebRequest _request;</p>
            <p>　protected void Page_Load(object sender, EventArgs e)<br>　{<br>　　PageAsyncTask task = new PageAsyncTask(<br>　　　new BeginEventHandler(BeginAsyncOperation),<br>　　　new EndEventHandler(EndAsyncOperation),<br>　　　new EndEventHandler(TimeoutAsyncOperation),<br>　　null<br>　);<br>　RegisterAsyncTask(task);<br>　}</p>
            <p>　IAsyncResult BeginAsyncOperation(object sender, EventArgs e, <br>AsyncCallback cb, object state)<br>　{<br>　　_request = WebRequest.Create("http://msdn.microsoft.com");<br>　　return _request.BeginGetResponse(cb, state);<br>　}</p>
            <p>　void EndAsyncOperation(IAsyncResult ar)<br>　{<br>　　string text;<br>　　using (WebResponse response = _request.EndGetResponse(ar))<br>　　{<br>　　　using (StreamReader reader = new StreamReader(response.GetResponseStream()))<br>　　　　{<br>　　　　　text = reader.ReadToEnd();<br>　　　　}<br>　　}</p>
            <p>　　Regex regex = new Regex("href\\s*=\\s*\"([^\"]*)\"", RegexOptions.IgnoreCase);<br>　　MatchCollection matches = regex.Matches(text);</p>
            <p>　　StringBuilder builder = new StringBuilder(1024);<br>　　foreach (Match match in matches)<br>　　{<br>　　　builder.Append(match.Groups[1]);<br>　　　builder.Append("&lt;br/&gt;");<br>　　}</p>
            <p>　　Output.Text = builder.ToString();<br>　}</p>
            <p>　void TimeoutAsyncOperation(IAsyncResult ar)<br>　{<br>　　Output.Text = "Data temporarily unavailable";<br>　}<br>}<br></p>
            </td>
        </tr>
    </tbody>
</table>
<br>　　RegisterAsyncTask 的主要优势在于，它允许异步页引发多个异步调用，并延迟呈现直到所有调用完成。它也很好地适用于单个异步调用，而且它提供了 AddOnPreRenderCompleteAsync 不具有的超时选项。如果生成一个只进行一个异步调用的异步页，您可以使用 AddOnPreRenderCompleteAsync 或 RegisterAsyncTask。但对于放置两个以上异步调用的异步页，RegisterAsyncTask 极大地简化了您的操作。<br><br>　　由于超时值是每页而非每调用设置，因此您可能想知道是否能改变单个调用的超时值。简单的回答是否。您可以通过以编程方式修改页的 AsyncTimeout 属性，逐个请求地更改超时，但是您无法将不同超时分配给从同一请求初始化的不同调用。<br>包装它<br><br>　　现在，您已经了解了 ASP.NET 2.0 中异步页的实质。它们在即将推出的 ASP.NET 版本中非常易于实现，并且其体系结构允许您在一个请求中批处理多个异步 I/O 操作，并延迟该页的呈现直到所有操作完成。通过与异步 ADO.NET 和 .NET Framework 中的其他新异步功能相结合，异步 ASP.NET 页针对因充满线程池而限制可伸缩性的 I/O 绑定请求问题提供了解决方案。<br><br>　　当生成异步页时最后需要注意的一点是，不应该启动来自 ASP.NET 使用的同一线程池的异步操作。例如，在页的异步点调用 ThreadPool.QueueUserWorkItem 会起反作用，因为该方法来自线程池，从而导致纯粹获取用于处理请求的零线程。相反，调用内置于 Framework 中的异步方法（例如，方法 HttpWebRequest.BeginGetResponse 和 SqlCommand.BeginExecuteReader）通常认为是安全的，因为这些方法倾向于使用完成端口实现异步行为。</p>
<img src ="http://www.cppblog.com/eday/aggbug/32420.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/eday/" target="_blank">松*</a> 2007-09-18 16:04 <a href="http://www.cppblog.com/eday/articles/32420.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>