ASP.NET Web API从模型 – 帮助页面生成所有参数

我正忙着创建Web API(在asp mvc4应用程序中)。 我正在使用asp.net网站上建议的库来生成文档( http://www.asp.net/web-api/overview/creating-web-apis/creating-api-help-pages )。

我的问题是,如果我的参数是模型,那么我无法在生成的帮助页面中指定模型包含的属性。

这是一个例子:

模型:

public class TestModel { property String FirstName {get;set;} property String Surname {get; set;} property Boolean Active {get;set;} } 

行动:

 ///  /// This is a test action ///  /// this is the model <-- this works /// This is the first name  <-- doesn't work /// This is the surname <-- doesn't work public HttpResponseMessage Post(my.namespace.models.TestModel model) { ... } 

仅生成模型的参数。

我看了一下为文档生成的xml文档,它确实添加了其他参数。

   this is a test action  this is the model This is the first name  This is the surname  

但是在帮助页面上它只生成参数模型。

我已经将它追溯到从xml获取参数的方法。

 Collection apiDescriptions = config.Services.GetApiExplorer().ApiDescriptions; 

它位于自动生成的HelpPageConfigurationExtentions.cs中。

我接近这个错误的方式吗? 有谁知道一个工作?

任何建议或解决方案将不胜感激。

MVC Web API文档function使用reflection遍历您的API类和方法。 这将构建文档的结构,但除非您添加了文档注释,否则将导致或多或少的空(和无用)文档。

使用使用///文档注释生成的XML文件填充文档正文,文档注释具有必须遵循的特定结构。 这意味着你不能用你希望它显示的任何东西填充你的xml,它实际上必须连接到你的API中的东西,并且必须遵循你的类和属性的结构。

因此,在您的情况下,您不能将模型属性文档放在api方法中。 您必须将它放入属性存在的模型中。

模型:

  public class TestModel { /// This is the first name  property String FirstName {get;set;} /// This is the surname property String Surname {get; set;} property Boolean Active {get;set;} } 

行动:

  ///  /// This is a test action ///  /// this is the model public HttpResponseMessage Post(my.namespace.models.TestModel model) { ... } 

修改帮助页面

自动生成的默认帮助页面不包括模型文档,只记录了api方法。 为了在api中显示有关参数的更多信息,需要进行自定义。 以下说明是添加参数文档的一种方法。

在Areas / HelpPage / Models中创建两个新类型

 public class TypeDocumentation { public TypeDocumentation() { PropertyDocumentation = new Collection(); } public string Summary { get; set; } public ICollection PropertyDocumentation { get; set; } } public class PropertyDocumentation { public PropertyDocumentation(string name, string type, string docs) { Name = name; Type = type; Documentation = docs; } public string Name { get; set; } public string Type { get; set; } public string Documentation { get; set; } } 

向HelpPageApiModel.cs添加新属性

 public IDictionary ParameterModels{ get; set; } 

创建一个新界面

 internal interface IModelDocumentationProvider { IDictionary GetModelDocumentation(HttpActionDescriptor actionDescriptor); } 

修改XmlDocumentationProvider以实现新接口

 public class XmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider { private const string TypeExpression = "/doc/members/member[@name='T:{0}']"; private const string PropertyExpression = "/doc/members/member[@name='P:{0}']"; ///... ///... existing code ///... private static string GetPropertyName(PropertyInfo property) { string name = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", property.DeclaringType.FullName, property.Name); return name; } public IDictionary GetModelDocumentation(HttpActionDescriptor actionDescriptor) { var retDictionary = new Dictionary(); ReflectedHttpActionDescriptor reflectedActionDescriptor = actionDescriptor as ReflectedHttpActionDescriptor; if (reflectedActionDescriptor != null) { foreach (var parameterDescriptor in reflectedActionDescriptor.GetParameters()) { if (!parameterDescriptor.ParameterType.IsValueType) { TypeDocumentation typeDocs = new TypeDocumentation(); string selectExpression = String.Format(CultureInfo.InvariantCulture, TypeExpression, GetTypeName(parameterDescriptor.ParameterType)); var typeNode = _documentNavigator.SelectSingleNode(selectExpression); if (typeNode != null) { XPathNavigator summaryNode; summaryNode = typeNode.SelectSingleNode("summary"); if (summaryNode != null) typeDocs.Summary = summaryNode.Value; } foreach (var prop in parameterDescriptor.ParameterType.GetProperties()) { string propName = prop.Name; string propDocs = string.Empty; string propExpression = String.Format(CultureInfo.InvariantCulture, PropertyExpression, GetPropertyName(prop)); var propNode = _documentNavigator.SelectSingleNode(propExpression); if (propNode != null) { XPathNavigator summaryNode; summaryNode = propNode.SelectSingleNode("summary"); if (summaryNode != null) propDocs = summaryNode.Value; } typeDocs.PropertyDocumentation.Add(new PropertyDocumentation(propName, prop.PropertyType.Name, propDocs)); } retDictionary.Add(parameterDescriptor.ParameterName, typeDocs); } } } return retDictionary; } } 

在GenerateApiModel方法中将代码添加到HelpPageConfigurationExtension

 IModelDocumentationProvider modelProvider = config.Services.GetDocumentationProvider() as IModelDocumentationProvider; if (modelProvider != null) { apiModel.ParameterModels = modelProvider.GetModelDocumentation(apiDescription.ActionDescriptor); } 

修改HelpPageApiModel.cshtml添加到您希望显示模型文档的位置。

 bool hasModels = Model.ParameterModels.Count > 0; if (hasModels) { 

Parameter Information

@Html.DisplayFor(apiModel => apiModel.ParameterModels, "Models") }

将一个Models.cshtml添加到DisplayTemplates

 @using System.Web.Http @using System.Web.Http.Description @using MvcApplication2.Areas.HelpPage.Models @model IDictionary @foreach (var modelType in Model) { 

@modelType.Key

if (modelType.Value.Summary != null) {

@modelType.Value.Summary

} @foreach (var propInfo in modelType.Value.PropertyDocumentation) {

}

Property Description
@propInfo.Name (@propInfo.Type)
@propInfo.Documentation

}

约瑟夫的答案很有效。 但我确实发现它有点过分热心。 我发现它报告了简单的事情,比如字符串作为模型,并将它们报告为带有长度字段的Char数组!

我们只需要这个模型,所以我将此代码添加到GetModelDocumentation方法的末尾:

 if (parameterDescriptor.ParameterName == "value" || parameterDescriptor.ParameterName == "model") { retDictionary.Add(parameterDescriptor.ParameterName, typeDocs); } 

现在它只返回非简单类型的参数详细信息。