ASP.NETWebAPI项⽬⾃动⽣成接⼝⽂档和测试页⾯
在开发接⼝的时候,写接⼝⽂档已是⼀件不可忽视的事情,有了更新也要同步更新很⿇烦。ASP.NET 创建的Web API项⽬可以⾃⼰配置接⼝⽂档的XML显⽰,这样接⼝更新和注释更新了重新发布就有了,确实⽅便不少,下来就介绍下怎么配置⽣成API接⼝注释⽂档。另外,如果在接⼝⽣成的同时能够⼀并⽣成测试页⾯也是不错的选择,能节省不少开发时间和⼈⼒成本。
创建Web API项⽬
请参考:这⾥我们以WebAPI项⽬为例。
修改默认的API路由配置
为什么要修改呢?因为每⼀个Controller的默认路由都是指定到"api/{controller}/{id}"的,所以默认⽣成的控制器类似下⾯:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace WebAPI.Controllers
{
public class ValuesController : ApiController
{
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}
/
/ POST api/<controller>
public void Post([FromBody]string value)
{
}
// PUT api/<controller>/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/<controller>/5
public void Delete(int id)
{
}
}
}
我们需要⼀个⽅法提供多种HTTP访问⽅式,所以应该将action的配置加⼊,如:"api/{controller}/{action}/{id}"。修改WebApiConfig.cs⽂件:
代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace WebAPI
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
/
/ Web API 配置和服务
// Web API 路由
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
修改HelpPage配置启动
修改HelpPageConfig.cs⽂件,代码如下:
// Uncomment the following to provide samples for PageResult<T>. Must also add the Microsoft.AspNet.WebApi.OData // package to your project.
#define Handle_PageResultOfT
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net.Http.Headers;
using System.Reflection;
using System.Reflection;
using System.Web;
using System.Web.Http;
using WebAPI.Utils;
namespace WebAPI.Areas.HelpPage
{
/// <summary>
/// Use this class to customize the Help Page.
/// For example you can set a custom <see cref="System.Web.Http.Description.IDocumentationProvider"/> to supply the documentation
/// or you can provide the samples for the requests/responses.
/// </summary>
public static class HelpPageConfig
{
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters",
MessageId = "WebAPI.Areas.HelpPage.TextSample.#ctor(System.String)",
Justification = "End users may choose to merge this string with existing localized resources.")]
[SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly",
MessageId = "bsonspec",
Justification = "Part of a URI.")]
public static void Register(HttpConfiguration config)
{
Uncomment the following to use the documentation from XML documentation file.
//config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_l")));
#region *************************XML显⽰接⼝参数和注释***************************************
// 添加本项⽬或其他引⽤项⽬的XML配置:可加多个
config.SetDocumentationProvider(new MultiXmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/bin/WebAPI.XML")));
#endregion
Uncomment the following to use "sample string" as the sample for all actions that have string as the body parameter or return type.
Also, the string arrays will be used for IEnumerable<string>. The sample objects will be serialized into different media type
formats by the available formatters.
//config.SetSampleObjects(new Dictionary<Type, object>
//{
//    {typeof(string), "sample string"},
//    {typeof(IEnumerable<string>), new string[]{"sample 1", "sample 2"}}
/
/});
// Extend the following to provide factories for types not handled automatically (those lacking parameterless
// constructors) or for which you prefer to use non-default property values. Line below provides a fallback
// since automatic handling will fail and GeneratePageResult handles only a single type.
#if Handle_PageResultOfT
config.GetHelpPageSampleGenerator().SampleObjectFactories.Add(GeneratePageResult);
#endif
// Extend the following to use a preset object directly as the sample for all actions that support a media
// type, regardless of the body parameter or return type. The lines below avoid display of binary content.
// The BsonMediaTypeFormatter (if available) is not used to serialize the TextSample object.
#region *************************默认JSON显⽰接⼝***************************************
//config.SetSampleForMediaType(
//    new TextSample("Binary JSON content. See for details."),
//    new MediaTypeHeaderValue("application/bson"));
#endregion
Uncomment the following to use "[0]=foo&[1]=bar" directly as the sample for all actions that support form URL encoded format
and have IEnumerable<string> as the body parameter or return type.
//config.SetSampleForType("[0]=foo&[1]=bar", new MediaTypeHeaderValue("application/x-www-form-urlencoded"), typeof(IEnumerable<string>));
Uncomment the following to use "1234" directly as the request sample for media type "text/plain" on t
he controller named "Values"
and action named "Put".
//config.SetSampleRequest("1234", new MediaTypeHeaderValue("text/plain"), "Values", "Put");
Uncomment the following to use the image on "../images/aspNetHome.png" directly as the response sample for media type "image/png"
on the controller named "Values" and action named "Get" with parameter "id".
//config.SetSampleResponse(new ImageSample("../images/aspNetHome.png"), new MediaTypeHeaderValue("image/png"), "Values", "Get", "id");
Uncomment the following to correct the sample request when the action expects an HttpRequestMessage with ObjectContent<string>.
The sample will be generated as if the controller named "Values" and action named "Get" were having string as the body parameter.
//config.SetActualRequestType(typeof(string), "Values", "Get");
Uncomment the following to correct the sample response when the action returns an HttpResponseMessage with ObjectContent<string>.
The sample will be generated as if the controller named "Values" and action named "Post" were returning a string.
//config.SetActualResponseType(typeof(string), "Values", "Post");
}
#if Handle_PageResultOfT
webserver接口开发private static object GeneratePageResult(HelpPageSampleGenerator sampleGenerator, Type type)
{
if (type.IsGenericType)
{
Type openGenericType = type.GetGenericTypeDefinition();
if (openGenericType == typeof(PageResult<>))
{
// Get the T in PageResult<T>
Type[] typeParameters = type.GetGenericArguments();
Debug.Assert(typeParameters.Length == 1);
// Create an enumeration to pass as the first parameter to the PageResult<T> constuctor
Type itemsType = typeof(List<>).MakeGenericType(typeParameters);
object items = sampleGenerator.GetSampleObject(itemsType);
// Fill in the other information needed to invoke the PageResult<T> constuctor
Type[] parameterTypes = new Type[] { itemsType, typeof(Uri), typeof(long?), };
object[] parameters = new object[] { items, null, (long)ObjectGenerator.DefaultCollectionSize, };
/
/ Call PageResult(IEnumerable<T> items, Uri nextPageLink, long? count) constructor
ConstructorInfo constructor = type.GetConstructor(parameterTypes);
return constructor.Invoke(parameters);
}
}
return null;
}
#endif
}
}
这⾥修改⽀持了多个XML⽂档⽅法,扩展类如下:
using System;
using System.Linq;
using System.Reflection;
using System.Web.Http.Controllers;
using System.Web.Http.Description;
using WebAPI.Areas.HelpPage;
using WebAPI.Areas.HelpPage.ModelDescriptions;
namespace WebAPI.Utils
{
/// <summary>A custom <see cref='IDocumentationProvider'/> that reads the API documentation from a collection of XML documentation files.</summary>    public class MultiXmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
{
/*********
** Properties
*********/
/// <summary>The internal documentation providers for specific files.</summary>
private readonly XmlDocumentationProvider[] Providers;