4、使用WebAPITestClient
一、使用NuGet安装WebAPITestClient
注:可以是单独的项目,也可以安装于Api项目中,下面以安装于Api项目中为例
1、Api 右键管理Nuget
2、安装WebAPITestClient
3、检查XmlDocumentationProvider.cs(以下为调试正常的程序)
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; namespace WebApiTestClient.Areas.HelpPage { /// <summary> /// A custom <see cref="IDocumentationProvider"/> that reads the API documentation from an XML documentation file. /// </summary> public class XmlDocumentationProvider : IDocumentationProvider { private XPathNavigator _documentNavigator; private const string MethodExpression = "/doc/members/member[@name='M:{0}']"; private const string ParameterExpression = "param[@name='{0}']"; private const string TypeExpression = "/doc/members/member[@name='T:{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 virtual string GetDocumentation(HttpActionDescriptor actionDescriptor) { XPathNavigator methodNode = GetMethodNode(actionDescriptor); if (methodNode != null) { XPathNavigator summaryNode = methodNode.SelectSingleNode("summary"); if (summaryNode != null) { return summaryNode.Value.Trim(); } } return null; } 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; } 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}", method.DeclaringType.FullName, 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 GetTypeName(Type type) { 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 typeName = genericType.FullName; // Trim the generic parameter counts from the name typeName = typeName.Substring(0, typeName.IndexOf('`')); string[] argumentTypeNames = genericArguments.Select(t => GetTypeName(t)).ToArray(); return String.Format(CultureInfo.InvariantCulture, "{0}{{{1}}}", typeName, String.Join(",", argumentTypeNames)); } return type.FullName; } public string GetDocumentation(HttpControllerDescriptor controllerDescriptor) { XPathNavigator typeNode = GetTypeNode(controllerDescriptor.ControllerType); return GetTagValue(typeNode, "summary"); } public string GetResponseDocumentation(HttpActionDescriptor actionDescriptor) { XPathNavigator methodNode = GetMethodNode(actionDescriptor); if (methodNode != null) { XPathNavigator summaryNode = methodNode.SelectSingleNode("summary"); if (summaryNode != null) { return summaryNode.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 GetTagValue(XPathNavigator parentNode, string tagName) { if (parentNode != null) { XPathNavigator node = parentNode.SelectSingleNode(tagName); if (node != null) { return node.Value.Trim(); } } return null; } } }
二、配置注释文档Xml的生成路径
1、Api项目
2、在生成页中设置输出路径
与你共亲到无可亲密时,便知友谊万岁是尽头。