我看園子裏關於Web API的註釋都是關於方法的,並無顯示實體註釋的方法,今天花了一些時間搞了一下node
其實註釋的顯示就是根據類庫的XML文檔文件生成的。express
首先你要將所用到的類庫生成XML文檔文件:ide
在HelpPageConfig這個類中修改以下,添加多個用到的類庫XML文件,原來只能添加一個spa
MultipleXmlDocumentationProvider代碼,和XmlDocumentationProvider基本相似code
/// <summary> /// 多個XML註釋 /// </summary> 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"); } //讀取所有XML文檔 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; } }
成功顯示圖:orm
參考連接:xml
http://stackoverflow.com/questions/21393754/helppage-xml-documentation-when-controllers-or-models-in-different-assemblyblog