利用 SandCastle 编写软件 SDK 文档
周融,2007 年 7 月
(C) 2001-2007 保留所有权利。
一直以来,独立软件开发商 (ISV) 开发的第三方程序集为了简化开发流程,往往会同时提供一套软件开发工具包 (SDK) 和文档库,该文档库包含它们发布的程序集的所有供开发人员使用的类型和模块,并且对如何使用它们做了详细的说明。Microsoft Developer Network (MSDN) 文档库就是这样一个包含几乎所有 Windows 开发资源的综合文档集合。本文描述一种利用 Microsoft 提供的软件快速生成帮助文档集合的方法。
本文适用于: Microsoft Sandcastle July 2007 CTP, .NET Framework 2.0, HTML Workshop。
在本文中的内容
Sandcastle 概述
获取 Sandcastle
XML 文档注释
生成示例文档
利用 Sandcastle Help File Builder
结论
1. Sandcastle 概述
为了满足这部分文档编写开发人员的需要,Microsoft 推出了一种用于快速生成 .NET 类库文档的工具,代号为 Sandcastle,该工具用来通过代码中的 XML 文档注释快速生成类似 MSDN 样式的帮助文档。它的文档输出格式支持 Help 1.x (*.chm),Help 2.0 (HxS) 和网站 (ASP.NET 和 HTML),您在编写文档上仅仅需要做的工作,就是努力的写好所有 XML 文档注释,并最终利用 Sandcastle 进行批量生成。
Sandcastle 被 Microsoft 内部用来直接生成 .NET Framework 核心类库参考文档,它是 MSDN 和 .NET Framework SDK 的一部分。
目前,Sandcastle 没有图形界面,但它提供了强大的功能,包括支持 prototype 样式、Visual Studio 2005 样式和 Visual Studio 2008 新的文档设计样式;它能对代码示例进行语法高亮,自动生成多种语言的过滤、语法、生成索引、内容目录、搜索;除此之外,它提供的命令行工具和批处理文件能够帮助我们生成自定义的帮助文档的本地化版本。
Sandcastle 提供的主要命令行工具有两个:BuildAssembler.exe 和 XslTransform.exe。BuildAssembler 用来对帮助文档源 (*.dll, *.exe, *.xml) 进行反射,找到所有的可用于生成文档的程序集、命名空间和类型,以及它们附加的 XML 文档注释,生成待转换的 XML 文件;XslTransform 用来对 BuildAssembler 生成的 XML 文件转换成特定的输出格式,如 Visual Studio 2005 样式的 chm 文件。
Sandcastle 提供一个执行以上两个步骤地批处理文件,在 \Examples\Sandcastle 目录中的 Build_Sandcastle.bat 文件就为您写好了一个示例代码。要生成这个示例帮助,请打开命令行,并执行:
build_sandcastle vs2005
其中,vs2005 是需要生成的文档样式,它可以是 prototype, vs2005 和 hana。
网站 http://61.87.201.105 (如果不能访问,说明我的计算机没有打开,请谅解) 就是利用 Sandcastle 生成的文档示例站点,怎么样,和 Microsoft Developer Network 的文档库样式是不是完全一致?
2. 获取 Sandcastle
我们可以从 Microsoft 下载中心获取 2007 年 7 月的社区技术预览版本 (CTP) 的 Sandcastle。
http://www.microsoft.com/downloads/info.aspx?na=22&p=1&SrcDisplayLang=en&SrcCategoryId=&SrcFamilyId=&u=%2fdownloads%2fdetails.aspx%3fFamilyID%3de82ea71d-da89-42ee-a715-696e3a4873b2%26DisplayLang%3den
目前,Sandcastle 仅提供了英文版本的可执行文件和文档样式,要生成本地化的帮助主题和样式,则需要等到 RTM,或者使用第三方工具本地化 \Presentation 目录下的 XML 文件。但庆幸的是,我们已经为您本地化了 vs2005 样式文档的所有呈现 XML 为简体中文 (语言代码: zh-CN, 语言 ID: 2052 (0x0804)),可以通过本文提供的下载地址直接下载得到。
简体中文本地化的 vs2005 样式的文件包:下载后替换 \Presentation\vs2005\Content 中的同名文件。
http://dl2.csdn.net/down4/20070720/20144855233.zip
如果您希望使用 Sandcastle 带有图形用户界面 (GUI) 的程序,则请转到 http://www.sandcastledocs.com 找到相应的 GUI 提供程序下载。我们建议您使用 CodePlex 上的 Sandcastle Help File Builder。这里是下载地址。
http://www.codeplex.com/SHFB。
3. XML 文档注释
前面提到,SandCastle 是利用 XML 文档注释来生成文档的,这就要求开发人员在编写自己的程序集时同步编写 XML 文档注释。在 .NET Framework 2.0 中,所有的 CLR 语言 (VB, C#, J#, C++/CLI) 都支持 XML 文档注释。例如,以下的文档注释会生成带有 Test 类摘要的文档。
/// 此类仅仅用来测试 XML 文档注释,并包含 <c>Test</c> 类的所有成员,有关 XML 文档注释的详细信息,
/// 请参见 <see cref="T:System.Rumtime.ComplierServices.CodeDom" />。
/// <note type="caution">此类不可继承。</note>
/// </summary>
public class Test { }
<summary> 表示摘要说明,<c> 表示标记中的文本是代码引用。<see> 标记可以引用外部资源或者类型的超级链接,<note> 标记则可以在文档中产生一个“注意”的段。
以下列出一部分在 Sandcstle 可用文档注释。如果需要获取全部可用文档注释,则请参考 C# XML 文档注释和 NDoc 标记。Sandcastle 支持所有 C# XML 文档注释和部分 NDoc 标记,暂不支持用户自定义标记。
标记 | 说明 |
<a> |
<a href="url">Sample</a>表示一个超级链接。 |
<b> | <b>...</b> 表示加粗。 |
<c> | <c>...</c> 代码引用。 |
<code> | <code [ lang="VB | VB.NET | C# | C++ | J#" source="path" region="region" ]>...</code> 表示一段代码引用。 |
<example> | <example>...</example> 表示示例。 |
<note> | <note type="caution | implementnotes | callers | inheriters">...</note> 表示备注。 |
<list> | <list type="bullet | number | table">...</list> 表示一个列表。 |
<para> | <para> 表示一个段落。 |
<param> | <param name="">...</param> 表示参数说明。 |
<paramref> | <paramref cref="" /> 表示一个参数的引用。 |
<summary> | <summary> 表示摘要。 |
<typeparam>, <typeparamref> | <typeparam name="T"> 表示一个类型参数。 |
<event> | <event> 表示方法触发的一个事件说明。 |
<remarks> | <remarks> 表示额外的备注。 |
<threadsafety> | <threadsafety instance="true | false" static="true | false"> 表示线程安全说明。 |
<value> | <value> 表示属性的值说明。 |
<returns> | <returns type="type"> 表示方法的返回值说明。 |
<preliminary> | 表示该文档是预发行版本。 |
<overload> | 表示方法被重载。 |
4. 生成示例文档
以下的一段代码可以生成如同 http://61.87.201.105/ 的帮助文档 http://61.87.201.105/library/html/10154868-d3f2-74d4-4a8a-cf4aaa68aeba.htm。
注意:我们强烈建议您在需要生成帮助文件的程序集代码中的 AssemblyInfo.cs 中加入属性
以便使 XML 文档注释符合 CLS 规范。
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Data.OracleClient;
using System.Data.Common;
namespace Heading.Data
{
/// <summary>
/// 存放应用程序全局资源和公共函数的静态类。
/// </summary>
/// <remarks>
/// <c>DataHelper</c> 包含对数据库的全局操作集合,包括打开和关闭连接、创建事务等。此类支持以下 Microsoft SQL Server 和 Oracle 版本。
/// <list type="table">
/// <listheader><item>Microsoft SQL Server 版本</item><description>Oracle 版本</description></listheader>
/// <item><item><list type="bullet">
/// <item>Microsoft SQL Server 2000</item>
/// <item>Microsoft SQL Server 2005</item>
/// <item>Microsoft SQL Server 2008</item>
/// </list></item>
/// <description><list type="bullet">
/// <item>Oracle 8i</item><item>Oracle 9i</item><item>Oracle 10g</item><item>Oracle 11g</item>
/// </list></description></item>
/// </list>
/// </remarks>
/// <example>
/// 以下示例展示如何使用 <c>DataHelper</c> 类执行数据库事务操作。
/// <code lang="C#" source="Code SamplesCSharpDataHelper.cs" region="DataHelper" />
/// <code lang="VB.NET" title="Visual Basic" source="Code SamplesVBDataHelper.vb" region="DataHelper" />
/// <code lang="C++" source="Code SamplesC++DataHelper.cpp" />
/// <note type="caution">
/// <para>
/// 此类是静态类。可在应用程序全局范围内使用,在使用此类的任何方法之前,您必须先初始化 <c>DataHelper</c>.Connection 属性。
/// 有关 Connection 属性的信息,请参见 <see cref="T:System.Data.Common.DbConnection" />。
/// </para>
/// </note>
/// </example>
/// <seealso cref="DbmsType" />
public static class DataHelper
{
// 为数据库设置连接字符串。
private static DbConnection connection;
/// <summary>
/// 获取用于存储事务的 DbTransaction。
/// </summary>
public static DbTransaction Transaction { get { return transaction; } }
private static DbTransaction transaction;
/// <summary>
/// 获取或设置数据库连接。
/// </summary>
public static DbConnection Connection { get { return connection; } set { connection = value; } }
/// <summary>
/// 获取或设置数据库连接类型。
/// </summary>
public static DbmsType ConnectionType
{
get { return connectionType; }
set
{
switch (value)
{
case DbmsType.Oracle:
CloseConnection();
connection = new OracleConnection();
break;
case DbmsType.SqlServer:
CloseConnection();
connection = new SqlConnection();
break;
}
connectionType = value;
}
}
private static DbmsType connectionType;
/// <summary>
/// 在指定的连接上下文中执行 SQL 命令。
/// </summary>
/// <param name="command">需要执行的 T-SQL 语句。</param>
/// <returns>执行语句后影响的行数。</returns>
public static int ExecuteSqlCommand(string command)
{
RaiseConnectionNotOpenedException();
using (DbCommand cmd = Connection.CreateCommand())
{
cmd.Transaction = transaction;
cmd.CommandText = command;
return cmd.ExecuteNonQuery();
}
}
/// <summary>
/// 在指定的连接上下文中执行 SQL 命令。
/// </summary>
/// <param name="command">需要执行的 T-SQL 语句。</param>
/// <param name="param">格式化字符串。</param>
/// <returns>执行语句后影响的行数。</returns>
public static int ExecuteSqlCommand(string command, params object[] param)
{
return ExecuteSqlCommand(string.Format(command, param));
}
/// <summary>
/// 在指定的连接上下文中执行 SQL 命令,并返回包含数据集的 DbDataReader。
/// </summary>
/// <param name="command">需要执行的 T-SQL 语句。</param>
/// <returns>存放执行结果的 DbDataReader。</returns>
public static DbDataReader ExecuteSqlReader(string command)
{
RaiseConnectionNotOpenedException();
using (DbCommand cmd = Connection.CreateCommand())
{
cmd.Transaction = transaction;
cmd.CommandText = command;
return cmd.ExecuteReader();
}
}
/// <summary>
/// 在指定的连接上下文中执行 SQL 命令,并返回包含数据集的 DbDataReader。
/// </summary>
/// <param name="command">需要执行的 T-SQL 语句。</param>
/// <param name="param">格式化字符串。</param>
/// <returns>存放执行结果的 DbDataReader。</returns>
public static DbDataReader ExecuteSqlReader(string command, params object[] param)
{
return ExecuteSqlReader(string.Format(command, param));
}
/// <summary>
/// 打开数据库连接,如果连接已经打开,则不会再次打开。
/// </summary>
public static void OpenConnection()
{
if (connection != null && connection.State == ConnectionState.Closed)
connection.Open();
}
/// <summary>
/// 关闭数据库连接。如果连接已经关闭,则不会再次关闭。
/// </summary>
public static void CloseConnection()
{
if (connection != null && connection.State == ConnectionState.Open)
connection.Close();
}
/// <summary>
/// 开始一个 SQL 事务,并将 Transaction 属性设置为当前活动的 DbTransaction。
/// </summary>
public static void BeginTransaction()
{
RaiseConnectionNotOpenedException();
transaction = Connection.BeginTransaction();
}
/// <summary>
/// 回滚当前活动的 SQL 事务。
/// </summary>
public static void Rollback()
{
RaiseTransactionException();
transaction.Rollback();
}
/// <summary>
/// 提交当前活动的 SQL 事务。
/// </summary>
public static void Commit()
{
RaiseTransactionException();
transaction.Commit();
try
{
transaction.Dispose();
}
finally { transaction = null; }
}
/// <summary>
/// 检查当前数据库连接是否存在指定的表。
/// </summary>
/// <param name="tableName">表名称。</param>
/// <returns>如果存在此对象则返回 true。否则返回 false。</returns>
public static bool TableExists(string tableName)
{
RaiseConnectionNotOpenedException();
string command = null;
switch (connectionType)
{
case DbmsType.Oracle:
command = @"SELECT 1 FROM user_objects WHERE UPPER(object_name) = UPPER('{0}') " +
"AND object_type = 'TABLE'";
break;
case DbmsType.SqlServer:
command = @"SELECT 1 FROM sysobjects WHERE Name = N'{0}' AND Type = N'U'";
break;
}
using (DbDataReader dr = ExecuteSqlReader(command, tableName))
{
return dr.HasRows;
}
}