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
} Property Description @foreach (var propInfo in modelType.Value.PropertyDocumentation) { @propInfo.Name (@propInfo.Type) @propInfo.Documentation
}
}
约瑟夫的答案很有效。 但我确实发现它有点过分热心。 我发现它报告了简单的事情,比如字符串作为模型,并将它们报告为带有长度字段的Char数组!
我们只需要这个模型,所以我将此代码添加到GetModelDocumentation方法的末尾:
if (parameterDescriptor.ParameterName == "value" || parameterDescriptor.ParameterName == "model") { retDictionary.Add(parameterDescriptor.ParameterName, typeDocs); }
现在它只返回非简单类型的参数详细信息。