common/Service/MeterProcessState/Areas/HelpPage/XmlDocumentationProvider.cs
2026-04-23 17:50:07 +02:00

162 lines
6.9 KiB
C#

using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Web.Http.Controllers;
using System.Web.Http.Description;
using System.Xml.XPath;
using Service.MeterProcessState.Areas.HelpPage.ModelDescriptions;
namespace Service.MeterProcessState.Areas.HelpPage
{
/// <summary>
/// A custom <see cref="IDocumentationProvider"/> that reads the API documentation from an XML documentation file.
/// </summary>
public class XmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
{
private 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 XmlDocumentationProvider(String documentPath)
{
if (documentPath == null)
{
throw new ArgumentNullException("documentPath");
}
XPathDocument xpath = new XPathDocument(documentPath);
_documentNavigator = 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 = _documentNavigator.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 _documentNavigator.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 _documentNavigator.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;
}
}
}