web-dev-qa-db-fra.com

API Web ASP.NET Générer tous les paramètres du modèle - pages d’aide

Je suis en train de créer une API Web (dans une application asp mvc4). J'utilise la bibliothèque suggérée sur le site asp.net pour générer de la documentation ( http://www.asp.net/web-api/overview/creating-web-apis/creating-api-help-pages ) .

Mon problème est que si mon paramètre est un modèle, je ne peux pas spécifier les propriétés que le modèle contient dans les pages d'aide générées.

Voici un exemple:

MODÈLE:

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

ACTION:

/// <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)
{
  ...
}

Seul le paramètre du modèle est généré.

J'ai jeté un coup d'oeil au document XML qui est généré pour la documentation et ajoute les autres paramètres.

<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>

Mais sur les pages d’aide, il ne génère que le modèle de paramètre.

Je l'ai tracé jusqu'à la méthode où il obtient les paramètres du XML.

Collection<ApiDescription> apiDescriptions = config.Services.GetApiExplorer().ApiDescriptions;

Cela se trouve dans le fichier HelpPageConfigurationExtentions.cs qui est généré automatiquement.

Est-ce que je m'approche de la mauvaise façon? Quelqu'un connaît-il une solution de rechange?

Toute suggestion ou solution sera appréciée.

23
Jeandre Pentz

La fonction de documentation de l'API Web MVC parcourt vos classes et méthodes d'API à l'aide de la réflexion. Cela construira la structure de la documentation, mais donnera une documentation plus ou moins vide (et inutile) à moins que vous n'ayez ajouté des commentaires à la documentation. 

Le corps de la documentation est rempli à l'aide du fichier XML généré à l'aide de /// commentaires de la documentation, qui possède une structure spécifique à suivre. Cela signifie que vous ne pouvez pas remplir votre fichier XML avec ce que vous voulez qu'il affiche, il doit en réalité être connecté à quelque chose qui se trouve dans votre API et doit suivre la structure de vos classes et propriétés.

Donc, dans votre cas, vous ne pouvez pas mettre de documentation de propriétés de modèle dans une méthode api. Vous devez le mettre dans le modèle où la propriété existe.

MODÈLE:

  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;} 
  }

ACTION:

  /// <summary>
  /// This is a test action
  /// </summary>
  /// <param name="model">this is the model</param> 
  public HttpResponseMessage Post(my.namespace.models.TestModel model)
  {
    ...
  }

Modifier les pages d'aide

Les pages d'aide par défaut générées automatiquement n'incluent pas la documentation de modèle. Seules les méthodes api sont documentées. Afin d'afficher plus d'informations sur les paramètres de votre API, une personnalisation est nécessaire. Les instructions qui suivent constituent un moyen d’ajouter une documentation sur les paramètres.

Créez deux nouveaux types dans Aires/HelpPage/Models

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; }
}

Ajouter une nouvelle propriété à HelpPageApiModel.cs

public IDictionary<string, TypeDocumentation> ParameterModels{ get; set; } 

Créer une nouvelle interface

internal interface IModelDocumentationProvider
{
    IDictionary<string, TypeDocumentation> GetModelDocumentation(HttpActionDescriptor actionDescriptor);
}

Modifier XmlDocumentationProvider pour implémenter la nouvelle interface

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;
    }
}

Ajouter du code à HelpPageConfigurationExtension dans la méthode GenerateApiModel

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

Modifiez HelpPageApiModel.cshtml en ajoutant les éléments suivants à l'endroit où vous souhaitez afficher la documentation du modèle.

bool hasModels = Model.ParameterModels.Count > 0;
if (hasModels)
{
     <h2>Parameter Information</h2>
  @Html.DisplayFor(apiModel => apiModel.ParameterModels, "Models")

}

Ajouter un 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>
}
27
agilejoshua

la réponse de josant fonctionne très bien. J'ai cependant trouvé que c'était un peu trop zélé. J'ai trouvé qu'il signalait des choses simples, telles que des chaînes en tant que modèles, et qu'il s'agissait d'un tableau de caractères avec un champ de longueur!

Nous n'avions besoin de cela que pour les modèles, alors j'ai ajouté ce code à la fin de la méthode GetModelDocumentation:

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

À présent, il ne renvoie que les détails des paramètres pour les types non simples.

0
Maxcelcat