ASP.NET Web API Генерация всех параметров из модели - страницы помощи
Я занят созданием веб-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;}
}
ДЕЙСТВИЕ:
/// <summary>
/// This is a test action
/// </summary>
/// <param name="model">this is the model</param> <-- this works
/// <param name="FirstName">This is the first name </param> <-- doesn't work
/// <param name ="model.Surname">This is the surname</param> <-- doesn't work
public HttpResponseMessage Post(my.namespace.models.TestModel model)
{
...
}
Генерируется только параметр для модели.
Я посмотрел на XML-документ, который генерируется для документации, и он добавляет другие параметры.
<member name="my.namespace.api.Post(my.namespace.models.TestModel)">
<summary>
this is a test action
</summary>
<param name="model>this is the model</param>
<param name="FirstName">This is the first name </param>
<param name="model.Surname">This is the surname</param>
</member>
Но на страницах справки он только генерирует модель параметров.
Я проследил это до метода, где он получает параметры из XML.
Collection<ApiDescription> apiDescriptions = config.Services.GetApiExplorer().ApiDescriptions;
Это находится в HelpPageConfigurationExtentions.cs, который генерируется автоматически.
Я подхожу к этому неправильно? Кто-нибудь знает об обходной путь?
Любые предложения или решения будут оценены.
2 ответа
Функция документирования MVC Web API просматривает ваши классы и методы API, используя рефлексию. Это создаст структуру документации, но приведет к более или менее пустой (и бесполезной) документации, если вы не добавили комментарии к документации.
Тело документации заполняется с использованием XML-файла, созданного с использованием /// комментариев к документации, который имеет особую структуру, которой необходимо следовать. Это означает, что вы не можете заполнить свой XML тем, что хотите, чтобы он отображался, он на самом деле должен быть связан с чем-то, что находится в вашем API и должно соответствовать структуре ваших классов и свойств.
Так что в вашем случае вы не можете поместить документацию свойств модели в метод API. Вы должны поместить его в модель, где существует свойство.
МОДЕЛЬ:
public class TestModel
{
/// <summary>This is the first name </summary>
property String FirstName {get;set;}
/// <summary>This is the surname</summary>
property String Surname {get; set;}
property Boolean Active {get;set;}
}
ДЕЙСТВИЕ:
/// <summary>
/// This is a test action
/// </summary>
/// <param name="model">this is the model</param>
public HttpResponseMessage Post(my.namespace.models.TestModel model)
{
...
}
Изменить страницы справки
Страницы справки по умолчанию, которые генерируются автоматически, не включают документацию модели, только документированы методы API. Чтобы отобразить больше информации о параметрах в вашем API, необходима настройка. Следующие инструкции являются одним из способов добавления документации параметров.
Создайте два новых типа в Области /HelpPage/ Модели
public class TypeDocumentation
{
public TypeDocumentation()
{
PropertyDocumentation = new Collection<PropertyDocumentation>();
}
public string Summary { get; set; }
public ICollection<PropertyDocumentation> 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<string, TypeDocumentation> ParameterModels{ get; set; }
Создать новый интерфейс
internal interface IModelDocumentationProvider
{
IDictionary<string, TypeDocumentation> 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<string, TypeDocumentation> GetModelDocumentation(HttpActionDescriptor actionDescriptor)
{
var retDictionary = new Dictionary<string, TypeDocumentation>();
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;
}
}
Добавьте код в HelpPageConfigurationExtension в методе GenerateApiModel
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)
{
<h2>Parameter Information</h2>
@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<string, TypeDocumentation>
@foreach (var modelType in Model)
{
<h3>@modelType.Key</h3>
if (modelType.Value.Summary != null)
{
<p>@modelType.Value.Summary</p>
}
<table class="help-page-table">
<thead>
<tr>
<th>Property</th>
<th>Description</th>
</tr>
</thead>
<tbody>
@foreach (var propInfo in modelType.Value.PropertyDocumentation)
{
<tr>
<td class="parameter-name"><b>@propInfo.Name</b> (@propInfo.Type)</td>
<td class="parameter-documentation">
<pre>@propInfo.Documentation</pre>
</td>
</tr>
}
</tbody>
</table>
}
Ответ Джозанта прекрасно работает. Однако я обнаружил, что это было немного усердно. Я обнаружил, что он сообщает о простых вещах, таких как строки, как модели, и сообщает, что они представляют собой массив Char с полем длины!
Нам это нужно только для моделей, поэтому я добавил этот код в конец метода GetModelDocumentation:
if (parameterDescriptor.ParameterName == "value" || parameterDescriptor.ParameterName == "model")
{
retDictionary.Add(parameterDescriptor.ParameterName, typeDocs);
}
Теперь он возвращает данные только для непростых типов.