Forked from dinowang/MultipleXmlDocumentationProvider.cs
Last active
August 29, 2015 14:10
-
-
Save kkbruce/bbd45625a4c42bb2fc47 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MultipleXmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider | |
{ | |
// 多個 XPathNavigator | |
private IList<XPathNavigator> _documentNavigators = new List<XPathNavigator>(); | |
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">The physical path to XML document.</param> | |
public MultipleXmlDocumentationProvider(params string[] documentPaths) | |
{ | |
if (documentPaths == null) | |
{ | |
throw new ArgumentNullException("documentPaths"); | |
} | |
// 建構函式採用可變數目引數 | |
foreach (var documentPath in documentPaths) | |
{ | |
var filePath = Path.GetDirectoryName(documentPath); | |
var fileSpec = Path.GetFileName(documentPath); | |
// 使用 wildcard 方式,如:"Mvc.*.xml" 以取得指涉檔案 | |
foreach (var file in Directory.GetFiles(filePath, fileSpec)) | |
{ | |
XPathDocument xpath = new XPathDocument(file); | |
_documentNavigators.Add(xpath.CreateNavigator()); | |
} | |
} | |
} | |
private XPathNavigator SelectSingleNode(string selectExpression) | |
{ | |
foreach (var navigator in _documentNavigators) | |
{ | |
var propertyNode = navigator.SelectSingleNode(selectExpression); | |
if (propertyNode != null) | |
{ | |
return propertyNode; | |
} | |
} | |
return null; | |
} | |
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 = SelectSingleNode(selectExpression); | |
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 SelectSingleNode(selectExpression); | |
} | |
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 SelectSingleNode(selectExpression); | |
} | |
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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment