2

早上好,

我有一个由两个项目组成的解决方案。一个是类库,包含将在其他项目中使用的通用类。另一个是 WebAPI 2.1 项目。

我正在使用自动帮助页面生成器为 API 生成帮助文件,但我注意到当它引用 Common 项目中的类时,它不使用摘要。

有没有办法让它做到这一点?我在网上搜索过,但找不到任何解决方案。我也尝试在 Common 项目中安装帮助页面生成器,但无济于事。

4

1 回答 1

3

我遇到了同样的问题,这只是因为文档提供者只需要一个 xml 文档,该文档是从当前项目生成的(如果您按照说明进行操作,您可能还记得添加:

config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/[YOUR XML DOCUMENT]"));

其余的类及其元数据被添加到不同的 xml 文档中。我所做的是我修改了 xml 文档提供程序以接受多个 xml 文档路径,并在每个文档中搜索与所查询的类相关的元数据。您需要从您引用的各种 dll 中添加 xml 文档,但这绝对解决了我的问题。有关 XmlDocumentationProvider 的变体,请参见下文:

public class XmlMultiDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
{
    private List<XPathNavigator> _documentNavigator;
    private const string TypeExpression = "/doc/members/member[@name='T:{0}']";
    private const string MethodExpression = "/doc/members/member[@name='M:{0}']";
    private const string PropertyExpression = "/doc/members/member[@name='P:{0}']";
    private const string FieldExpression = "/doc/members/member[@name='F:{0}']";
    private const string ParameterExpression = "param[@name='{0}']";

    /// <summary>
    /// Initializes a new instance of the <see cref="XmlDocumentationProvider"/> class.
    /// </summary>
    /// <param name="documentPath">The physical path to XML document.</param>
    public XmlMultiDocumentationProvider(params string[] documentPath)
    {
        if (documentPath == null)
        {
            throw new ArgumentNullException("documentPath");
        }
        _documentNavigator = new List<XPathNavigator>();
        foreach (string s in documentPath)
        {
            XPathDocument xpath = new XPathDocument(s);
            _documentNavigator.Add(xpath.CreateNavigator());
        }
    }

    public string GetDocumentation(HttpControllerDescriptor controllerDescriptor)
    {
        XPathNavigator typeNode = GetTypeNode(controllerDescriptor.ControllerType);
        return GetTagValue(typeNode, "summary");
    }

    public virtual string GetDocumentation(HttpActionDescriptor actionDescriptor)
    {
        XPathNavigator methodNode = GetMethodNode(actionDescriptor);
        return GetTagValue(methodNode, "summary");
    }

    public virtual string GetDocumentation(HttpParameterDescriptor parameterDescriptor)
    {
        ReflectedHttpParameterDescriptor reflectedParameterDescriptor = parameterDescriptor as ReflectedHttpParameterDescriptor;
        if (reflectedParameterDescriptor != null)
        {
            XPathNavigator methodNode = GetMethodNode(reflectedParameterDescriptor.ActionDescriptor);
            if (methodNode != null)
            {
                string parameterName = reflectedParameterDescriptor.ParameterInfo.Name;
                XPathNavigator parameterNode = methodNode.SelectSingleNode(String.Format(CultureInfo.InvariantCulture, ParameterExpression, parameterName));
                if (parameterNode != null)
                {
                    return parameterNode.Value.Trim();
                }
            }
        }

        return null;
    }

    public string GetResponseDocumentation(HttpActionDescriptor actionDescriptor)
    {
        XPathNavigator methodNode = GetMethodNode(actionDescriptor);
        return GetTagValue(methodNode, "returns");
    }

    public string GetDocumentation(MemberInfo member)
    {
        string memberName = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", GetTypeName(member.DeclaringType), member.Name);
        string expression = member.MemberType == MemberTypes.Field ? FieldExpression : PropertyExpression;
        string selectExpression = String.Format(CultureInfo.InvariantCulture, expression, memberName);
        XPathNavigator propertyNode = null;
        foreach(XPathNavigator navigator in _documentNavigator )
        {
          XPathNavigator temp  = navigator.SelectSingleNode(selectExpression);
          if (temp != null)
          {
              propertyNode = temp;
              break;
          }
        }
        return GetTagValue(propertyNode, "summary");
    }

    public string GetDocumentation(Type type)
    {
        XPathNavigator typeNode = GetTypeNode(type);
        return GetTagValue(typeNode, "summary");
    }

    private XPathNavigator GetMethodNode(HttpActionDescriptor actionDescriptor)
    {
        ReflectedHttpActionDescriptor reflectedActionDescriptor = actionDescriptor as ReflectedHttpActionDescriptor;
        if (reflectedActionDescriptor != null)
        {
            string selectExpression = String.Format(CultureInfo.InvariantCulture, MethodExpression, GetMemberName(reflectedActionDescriptor.MethodInfo));
            foreach (XPathNavigator navigator in _documentNavigator)
            {
                XPathNavigator temp = navigator.SelectSingleNode(selectExpression);
                if (temp != null)
                {
                    return temp;
                }
            }

        }

        return null;
    }

    private static string GetMemberName(MethodInfo method)
    {
        string name = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", GetTypeName(method.DeclaringType), method.Name);
        ParameterInfo[] parameters = method.GetParameters();
        if (parameters.Length != 0)
        {
            string[] parameterTypeNames = parameters.Select(param => GetTypeName(param.ParameterType)).ToArray();
            name += String.Format(CultureInfo.InvariantCulture, "({0})", String.Join(",", parameterTypeNames));
        }

        return name;
    }

    private static string GetTagValue(XPathNavigator parentNode, string tagName)
    {
        if (parentNode != null)
        {
            XPathNavigator node = parentNode.SelectSingleNode(tagName);
            if (node != null)
            {
                return node.Value.Trim();
            }
        }

        return null;
    }

    private XPathNavigator GetTypeNode(Type type)
    {
        string controllerTypeName = GetTypeName(type);
        string selectExpression = String.Format(CultureInfo.InvariantCulture, TypeExpression, controllerTypeName);
        foreach (XPathNavigator navigator in _documentNavigator)
        {
            XPathNavigator temp = navigator.SelectSingleNode(selectExpression);
            if (temp != null)
            {
                return temp;
            }
        }
        return null;
    }

    private static string GetTypeName(Type type)
    {
        string name = type.FullName;
        if (type.IsGenericType)
        {
            // Format the generic type name to something like: Generic{System.Int32,System.String}
            Type genericType = type.GetGenericTypeDefinition();
            Type[] genericArguments = type.GetGenericArguments();
            string genericTypeName = genericType.FullName;

            // Trim the generic parameter counts from the name
            genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf('`'));
            string[] argumentTypeNames = genericArguments.Select(t => GetTypeName(t)).ToArray();
            name = String.Format(CultureInfo.InvariantCulture, "{0}{{{1}}}", genericTypeName, String.Join(",", argumentTypeNames));
        }
        if (type.IsNested)
        {
            // Changing the nested type name from OuterType+InnerType to OuterType.InnerType to match the XML documentation syntax.
            name = name.Replace("+", ".");
        }

        return name;
    }
}

你可以得到这个想法,或者只是根据你的判断简单地使用整个班级。只需记住在您的 HelpPageConfig -> SetDocumentationProvider 中替换调用类名并添加各种 xml 文档的路径。

于 2015-03-23T21:00:45.247 回答