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

C# ASP.NET Web API从模型帮助页生成所有参数,c#,asp.net-mvc,asp.net-mvc-4,asp.net-web-api,asp.net-mvc-apiexplorer,C#,Asp.net Mvc,Asp.net Mvc 4,Asp.net Web Api,Asp.net Mvc Apiexplorer,我正忙于创建一个Web API(在asp mvc4应用程序中)。我正在使用asp.net网站上建议的库生成文档() 我的问题是,如果我的参数是一个模型,那么我无法在生成的帮助页面中指定该模型包含的属性 以下是一个例子: 型号: public class TestModel { property String FirstName {get;set;} property String Surname {get; set;} property Boolean Active {g

我正忙于创建一个Web API(在asp mvc4应用程序中)。我正在使用asp.net网站上建议的库生成文档()

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

以下是一个例子:

型号:

public class TestModel
{
    property String FirstName {get;set;}
    property String Surname {get; set;}
    property Boolean Active {get;set;} 
}
  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> <-- 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)
{
  ...
}
  /// <summary>
  /// This is a test action
  /// </summary>
  /// <param name="model">this is the model</param> 
  public HttpResponseMessage Post(my.namespace.models.TestModel model)
  {
    ...
  }
//
///这是一个测试动作
/// 

///这是一个模型&mdash;mvcwebapi文档特性使用反射遍历API类和方法。这将构建文档的结构,但除非您添加了文档注释,否则会导致或多或少的空文档(和无用的文档)

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

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

型号:

public class TestModel
{
    property String FirstName {get;set;}
    property String Surname {get; set;}
    property Boolean Active {get;set;} 
}
  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;} 
  }
修改HelpPageApiModel.cshtml,将其添加到要显示模型文档的以下位置

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

}
bool hasModels=Model.ParameterModels.Count>0;
if(型号)
{
参数信息
@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>
}
@使用System.Web.Http
@使用System.Web.Http.Description
@使用MVCAPApplication2.Areas.HelpPage.Models
@模型词典
@foreach(模型中的var模型类型)
{
@modelType.Key
if(modelType.Value.Summary!=null)
{
@modelType.Value.Summary

} 财产 描述 @foreach(modelType.Value.PropertyDocumentation中的var propInfo) { @propInfo.Name(@propInfo.Type) @propInfo.文件 } }
约桑特的答案非常有效。然而,我确实发现它有点过于热情。我发现它将字符串作为模型报告,并将它们报告为带有长度字段的字符数组

我们只在模型中需要它,所以我在GetModelDocumentation方法的末尾添加了以下代码:


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

读一下这个答案,你也尝试过记录模型类吗?这很有效!唯一的问题是我必须将代码放在GenerateApiModel方法中,因为没有配置对象。我通过在GenerateApiModel中为其添加一个参数来修复此问题,然后在GetHelpPageApiModel方法中传递配置对象我一定错过了说明中的一个步骤,其他任何想这样做的人都应该看看Jeandre对config对象的评论。有人对模型位于外部项目中的情况给出了答案吗,或者这不是常见做法吗?此api文档设置将从单个XmlDocument.xml文件读取,它不关心文档与哪些程序集相关。您可以轻松地将外部模型项目中的文档XML合并到XmlDocument.XML文件中,以获取项目外部类型的文档。但我发现这个特性已经包含在2015年2月9日发布的至少5.2.3中。我的xml文档没有显示为描述是由泛型引起的。
internal interface IModelDocumentationProvider
{
    IDictionary<string, TypeDocumentation> GetModelDocumentation(HttpActionDescriptor actionDescriptor);
}
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;
    }
}
IModelDocumentationProvider modelProvider =
            config.Services.GetDocumentationProvider() as IModelDocumentationProvider;
if (modelProvider != null)
{
    apiModel.ParameterModels = modelProvider.GetModelDocumentation(apiDescription.ActionDescriptor);
}
bool hasModels = Model.ParameterModels.Count > 0;
if (hasModels)
{
     <h2>Parameter Information</h2>
  @Html.DisplayFor(apiModel => apiModel.ParameterModels, "Models")

}
@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>
}
if (parameterDescriptor.ParameterName == "value" || parameterDescriptor.ParameterName == "model")
{
    retDictionary.Add(parameterDescriptor.ParameterName, typeDocs);
}