• 为ASP.NET WEB API生成人性化说明文档


    一、为什么要生成说明文档

    我们大家都知道,自己写的API要供他人调用,就需要用文字的方式将调用方法和注意事项等写成一个文档以更好的展示我们设计时的想法和思路,便于调用者更加高效的使用我们的API。

    当然,您可以不借助任何工具,自己手工写文档,然后做成chm或者html的形式交给客户,就是效率有点低,并且在API更改后有需要手工更改说明文档。

    那有没有一种既方便,又能在API发生改变时,自动更新说明文档呢?答案是肯定的。

    二、自动生成说明文档的具体实现

    我们这里主要是将GlobalConfiguration.Configuration.Services的描述的实现换一种实现,具体是实现IDocumentationProvider这个接口,然后在调用Replace方法替换实现。

    百度搜XmlCommentDocumentationProvider,有很多结果哦。这些都源于微软官方的大牛这篇文章:

    http://blogs.msdn.com/b/yaohuang1/archive/2012/05/21/asp-net-web-api-generating-a-web-api-help-page-using-apiexplorer.aspx

    下面是XmlCommentDocumentationProvider的实现:

    using System.Linq;
    using System.Reflection;
    using System.Text.RegularExpressions;
    using System.Web.Http;
    using System.Web.Http.Controllers;
    using System.Web.Http.Description;
    using System.Web.Mvc;
    using System.Xml.XPath;
    
    namespace Deepleo.API
    {
        /// <summary>
        /// XmlCommentDocumentationProvider
        /// </summary>
        public class XmlCommentDocumentationProvider : IDocumentationProvider
        {
            readonly XPathNavigator _documentNavigator;
            private const string _methodExpression = "/doc/members/member[@name='M:{0}']";
            private static readonly Regex _nullableTypeNameRegex = new Regex(@"(.*.Nullable)" + Regex.Escape("`1[[") + "([^,]*),.*");
    
            /// <summary>
            /// ctor
            /// </summary>
            /// <param name="documentPath">document path</param>
            public XmlCommentDocumentationProvider(string documentPath)
            {
                XPathDocument xpath = new XPathDocument(documentPath);
                _documentNavigator = xpath.CreateNavigator();
            }
    
            public virtual string GetDocumentation(HttpActionDescriptor actionDescriptor)
            {
                XPathNavigator memberNode = GetMemberNode(actionDescriptor);
                if (memberNode != null)
                {
                    XPathNavigator summaryNode = memberNode.SelectSingleNode("summary");
                    if (summaryNode != null)
                    {
                        return summaryNode.Value.Trim();
                    }
                }
    
                return "";
            }
    
            public virtual string GetDocumentation(HttpParameterDescriptor parameterDescriptor)
            {
                ReflectedHttpParameterDescriptor reflectedParameterDescriptor = parameterDescriptor as ReflectedHttpParameterDescriptor;
                if (reflectedParameterDescriptor != null)
                {
                    XPathNavigator memberNode = GetMemberNode(reflectedParameterDescriptor.ActionDescriptor);
                    if (memberNode != null)
                    {
                        string parameterName = reflectedParameterDescriptor.ParameterInfo.Name;
                        XPathNavigator parameterNode = memberNode.SelectSingleNode(string.Format("param[@name='{0}']", parameterName));
                        if (parameterNode != null)
                        {
                            return parameterNode.Value.Trim();
                        }
                    }
                }
    
                return "";
            }
    
            private XPathNavigator GetMemberNode(HttpActionDescriptor actionDescriptor)
            {
                ReflectedHttpActionDescriptor reflectedActionDescriptor = actionDescriptor as ReflectedHttpActionDescriptor;
                if (reflectedActionDescriptor != null)
                {
                    string selectExpression = string.Format(_methodExpression, GetMemberName(reflectedActionDescriptor.MethodInfo));
                    XPathNavigator node = _documentNavigator.SelectSingleNode(selectExpression);
                    if (node != null)
                    {
                        return node;
                    }
                }
    
                return null;
            }
    
            private static string GetMemberName(MethodInfo method)
            {
                if (method.DeclaringType == null)
                    return string.Empty;
    
                string name = string.Format("{0}.{1}", method.DeclaringType.FullName, method.Name);
                var parameters = method.GetParameters();
                if (parameters.Length != 0)
                {
                    string[] parameterTypeNames = parameters.Select(param => ProcessTypeName(param.ParameterType.FullName)).ToArray();
                    name += string.Format("({0})", string.Join(",", parameterTypeNames));
                }
    
                return name;
            }
    
            private static string ProcessTypeName(string typeName)
            {
                //handle nullable
                var result = _nullableTypeNameRegex.Match(typeName);
                if (result.Success)
                {
                    return string.Format("{0}{{{1}}}", result.Groups[1].Value, result.Groups[2].Value);
                }
                return typeName;
            }
        }
    }
    View Code

    这个代码是通用的,直接copy过去就ok了。

    这篇博客园大牛张善友老师的博客有更详细的说明:http://www.cnblogs.com/shanyou/archive/2012/06/02/2532370.html

    我主要说说后面的怎么实现:

    第一步:需要在Project的Build里面打开生成xml注释文件选项,如下图所示:

     第二步:改造HomeController.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Http.Description;
    using System.Web.Http;
    
    namespace MvcApplication1.Controllers
    {
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                var config = GlobalConfiguration.Configuration;
                config.Services.Replace(typeof(IDocumentationProvider),
                                        new XmlCommentDocumentationProvider(HttpContext.Server.MapPath("~/bin/MvcApplication1.XML")));
                var apiExplorer = config.Services.GetApiExplorer();
                return View(apiExplorer);
            }
        }
    }

    代码的大意就是读取那个xml文件,然后替换掉以前的实现,换成我们的XmlCommentDocumentationProvider。

    下面最后一步,修改View.

    @model System.Web.Http.Description.IApiExplorer
    @{
        ViewBag.Title = "API说明文档";
    }
    <div id="body">
        <section class="featured">
            <div class="content-wrapper">
                <hgroup class="title">
                    <h1>API说明文档</h1>
                </hgroup>
            </div>
        </section>
        <section class="content-wrapper main-content clear-fix">
            <ul>
            @foreach (var api in Model.ApiDescriptions)
            {
                <li>
                    <p>@api.HttpMethod : <b>@ViewBag.Domain@api.RelativePath</b></p>
                    <blockquote>
                        <b>Description:</b>@api.Documentation<br />
                        @if (api.ParameterDescriptions.Count > 0)
                        {
                            <b>Parameters</b>
                            <ul>
                                @foreach (var parameter in api.ParameterDescriptions)
                                {
                                    <li>@parameter.Name: @parameter.Documentation {@parameter.Source}</li>
                                }
                            </ul>
                        }
                    </blockquote>
                </li>
                <hr/>
            }
            <li>
              <small>来源:http://www.cnblogs.com/deepleo/p/XmlCommentDocumentationProvider.html</small>  
            </li>
            </ul>
        </section>
    </div>

    大功告成,在线浏览效果:http://weishangapi.deepleo.com

    演示代码下载:http://files.cnblogs.com/deepleo/WebApplication1.rar

    可以看到,你在代码里面的注释,会自动显示到说明文档里面,这样你就可以专注于你的API设计和实现了,无需要手工更改说明文档。

  • 相关阅读:
    2_C语言中的数据类型 (九)逻辑运算符与if语句、switch、条件运算符?、goto语句与标号
    2_C语言中的数据类型 (八)运算符
    Python_sklearn机器学习库学习笔记(七)the perceptron(感知器)
    C++ STL 学习笔记__(7)Set和multiset容器
    2_C语言中的数据类型 (七)printf与scanf
    郑捷《机器学习算法原理与编程实践》学习笔记(第五章 梯度寻优)5.1 最优化与计算复杂度
    机器学习笔记(一)机器学习与数学分析
    2_C语言中的数据类型 (七)类型限定
    郑捷《机器学习算法原理与编程实践》学习笔记(第四章 推荐系统原理)(三)SVD
    [译]Javascript timing事件
  • 原文地址:https://www.cnblogs.com/deepleo/p/XmlCommentDocumentationProvider.html
Copyright © 2020-2023  润新知