当控件或模型在不同的程序集中时,HelpPage xml文档

时间:2014-01-27 23:16:15

标签: asp.net-mvc asp.net-web-api

使用新的webapi 2.1位。出于某种原因,当我打开帮助页面时,没有任何属性的描述细节,例如

/// <summary>
/// Some summary that shows correct
/// </summary>
[DataContract]
public class MyClass
{

    /// <summary>
    /// Display something.....
    /// </summary>
    [DataMember(Name = "Great")]
    public string MyGreatProperty { get; set; }

当我打开帮助页面时,我可以看到摘要“显示正确的一些摘要”但是对于此模型的属性,没有任何摘要显示。

webapi 2不支持属性描述吗?

2 个答案:

答案 0 :(得分:13)

您可以使用以下IDocumentationProvider实现,它是XmlDocumentationProvider的副本,只需稍加修改。

HelpPageConfig.cs中的用法示例:

config.SetDocumentationProvider(new MultipleXmlDocumentationProvider(
            HttpContext.Current.Server.MapPath("~/bin/App.DataContracts.XML"),
            HttpContext.Current.Server.MapPath("~/bin/App.Controllers.XML")));

MultipleXmlDocumentationProvider类:

public class MultipleXmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
{
    private IList<XPathNavigator> _documentNavigators;
    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="documentPaths">List of physical paths to XML documents.</param>
    public MultipleXmlDocumentationProvider(params string[] documentPaths)
    {
        if (!documentPaths.Any())
        {
            throw new ArgumentNullException("documentPaths");
        }

        var documents = documentPaths.Where(p => File.Exists(p)).ToList();

        _documentNavigators = documents.Select(p => new XPathDocument(p).CreateNavigator()).ToList();
    }

    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);
        var propertyNode = _documentNavigators.Select(n => n.SelectSingleNode(selectExpression)).FirstOrDefault(n => n != null);
        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));
            return _documentNavigators.Select(n => n.SelectSingleNode(selectExpression)).FirstOrDefault(n => n != null);
        }

        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);
        return _documentNavigators.Select(n => n.SelectSingleNode(selectExpression)).FirstOrDefault(n => n != 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;
    }
}

答案 1 :(得分:1)

感谢您的详细信息。我不确定我是否会将此称为Web API中的错误,因为它本身并不依赖于xml文件来获取文档。例如,如果您已安装HelpPage,则会在XmlDocumentationProvider.cs下看到名为Areas\HelpPage的文件。 这个提供程序实现查看单个xml文件。

对于您的方案,您可以创建IDocumentationProvider&amp;的自定义实现。 IModelDocumentationProvider基于C#类型,您可以查看不同的xml文档文件。您可以重用默认XmlDocumentationProvider中的大部分代码。