【问题标题】:ASP.NET Web API Generate all parameters from model - help pagesASP.NET Web API 从模型生成所有参数 - 帮助页面
【发布时间】:2013-09-07 12:57:34
【问题描述】:

我正忙于创建一个 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;} 
}

动作:

/// <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 中。

我是不是以错误的方式处理这个问题?有谁知道解决方法吗?

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

【问题讨论】:

标签: c# asp.net-mvc asp.net-mvc-4 asp.net-web-api asp.net-mvc-apiexplorer


【解决方案1】:

josant 的回答效果很好。然而,我确实发现它有点过分热心。我发现它报告了简单的东西,比如字符串作为模型,并将它们报告为带有长度字段的 Char 数组!

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

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

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

【讨论】:

    【解决方案2】:

    MVC Web API 文档功能使用反射遍历您的 API 类和方法。这将构建文档的结构,但会导致或多或少的空(无用)文档,除非您添加了文档 cmets。

    文档的正文使用 XML 文件填充,该文件是使用 /// 文档 cmets 生成的,该文件具有必须遵循的特定结构。这意味着您不能用您希望它显示的任何内容填充您的 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 中显示有关参数的更多信息,需要进行自定义。以下说明是添加参数文档的一种方法。

    在 Areas/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; }
    }
    

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

    在 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)
    {
         <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>
    }
    

    【讨论】:

    • 这成功了!唯一的问题是我必须放在 GenerateApiModel 方法中的代码,没有配置对象。我通过在 GenerateApiModel 中为其添加参数来解决此问题,然后在 GetHelpPageApiModel 方法中传递配置对象
    • 我一定是错过了说明中的一步,其他想要这样做的人应该看看 Jeandre 对 config 对象的评论。
    • 对于模型存在于外部项目中的情况,有没有人想出答案,或者这不是常见的做法?
    • 此 api 文档设置将从单个 XmlDocument.xml 文件中读取,它不关心文档与哪些程序集相关。您可以轻松地将外部模型项目中的文档 XML 合并到 XmlDocument.xml 文件中,以获取项目外部类型的文档。
    • 这行得通。但是我发现这个功能已经包含在 2015 年 2 月 9 日发布的至少 5.2.3 中。我的 xml 文档没有显示为描述是由泛型引起的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-08
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2014-12-27
    • 1970-01-01
    相关资源
    最近更新 更多