简介
一直听说Swagger是做Web API文档的好工具,正好手头一个项目使用WebApi,决定使用Swagger来文档化接口,作为和前端交流的基础。下面是使用Swashbuckle.net 给ASP.net web API添加文档的简要步骤。
使用中如果碰到任何问题欢迎评论,一起讨论解决
项目引入Swagger
Swashbuckle是Swagger在dotnet环境中的实现,在ASP.net项目中加入后即可支持Swagger/UI。5.X版本支持ASP.net, 6.X(beta)版本支持ASP.net Core. 目前项目使用ASP.net for IIS,所以使用了5.4的版本。 关于selfhost和Owin Swashbuckle 的readme有很清楚的描述,可以自行查看。
使用nuget加入Swashbuckle的引用。
安装好以后,在App_Start目录下,会有一个SwaggerConfig.cs文件,SwaggerConfig类通过[assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
启动时运行。
nuget添加完引用,无须任何配置,编译后,访问 http://yoururl/swagger 即可看到所有API的文档说明,当然说明都很简单,没有太大价值。
SwaggerConfig简单介绍
SwaggerConfig.cs文件会自动添加到项目的App_Start目录下,代码本身包含大量注释掉的代码,清除后,代码如下:
public class SwaggerConfig
{
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c =>//用于启用和设置Swagger的配置信息。
{
c.SingleApiVersion("v1", "Cxx.xxx.Web");
//a#
})
.EnableSwaggerUi(c =>
{//用于启用UI界面上的东西。
//b#
});
}
}
支持XML注释
使用Swagger的目的就是希望把代码中方法和类型的注释自动导出来。在Swashbuckle中,很简单。
-
相关工程需要生成XML文档
在Swagger.Config的Register方法的EnableSwagger匿名函数中加上对应的XML文件(可以添加在//a#代码后面。)
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory +"\\bin\\"; var commentsFileName = Assembly.GetExecutingAssembly().GetName().Name + ".XML"; var commentsFile = Path.Combine(baseDirectory, commentsFileName); c.IncludeXmlComments(commentsFile);
上述代码把Web工程的XML注释加入到Swagger中。一般我们会把viewmodel或者其他类型定义在不同的工程中,通过下面的代码可以继续加入其它xml注释文件。(对应功能需要启用XML文档文件生成)
c.IncludeXmlComments(Path.Combine(baseDirectory, "CrXX.XX.xml"));
实现默认调用参数
Swagger本身支持直接调用,但是调用参数需要手动编写,一个比较简单的办法是自定义一个attribute,给viewmodel的参数加上默认参数。
-
首先增加一个Swagger属性如下图:
public class SwaggerDefaultValue : Attribute { public string Name { get; set; } public string Value { get; set; } public SwaggerDefaultValue(string value) { this.Value = value; } public SwaggerDefaultValue(string name, string value) : this(value) { this.Name = name; } }
增加一个AddDefaultValues类,如下面代码
public class AddDefaultValues : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
IDictionary<string, object> parameterValuePairs =
GetParameterValuePairs(apiDescription.ActionDescriptor);
if (operation?.parameters != null)
{
foreach (var param in operation.parameters)
{
if (param.schema != null && param.schema.@ref != null)
{
string schemaName = param.schema.@ref.Split('/').LastOrDefault();
if (schemaRegistry.Definitions.ContainsKey(schemaName))
foreach (var props in schemaRegistry.Definitions[schemaName].properties)
{
if (parameterValuePairs.ContainsKey(props.Key.ToLower()))//默认会转换为camelcase,所以强行转为小写
props.Value.@default = parameterValuePairs[props.Key.ToLower()];//默认会转换为camelcase,所以强行转为小写
}
}
var parameterValuePair = parameterValuePairs.FirstOrDefault(p => p.Key.IndexOf(param.name, StringComparison.InvariantCultureIgnoreCase) >= 0);
param.@default = parameterValuePair.Value;
}
}
}
private IDictionary<string, object> GetParameterValuePairs(HttpActionDescriptor actionDescriptor)
{
IDictionary<string, object> parameterValuePairs = new Dictionary<string, object>();
foreach (SwaggerDefaultValue defaultValue in actionDescriptor.GetCustomAttributes<SwaggerDefaultValue>())
{
parameterValuePairs.Add(defaultValue.Name, defaultValue.Value);
}
foreach (var parameter in actionDescriptor.GetParameters())
{
if (!parameter.ParameterType.IsPrimitive)
{
InitialType(parameterValuePairs, parameter.ParameterType);
}
}
return parameterValuePairs;
}
void InitialType(IDictionary<string, object> parameterValuePairs, Type t)
{
foreach (PropertyInfo property in t.GetProperties())
{
var defaultValue = GetDefaultValue(property);
if (defaultValue != null)
{
parameterValuePairs.Add(property.Name.ToLower(), defaultValue);//默认会转换为camelcase,所以强行转为小写
}
}
}
private static object GetDefaultValue(PropertyInfo property)
{
var customAttribute = property.GetCustomAttributes<SwaggerDefaultValue>().FirstOrDefault();
if (customAttribute != null)
{
return customAttribute.Value;
}
return null;
}
}
在Swagger.Config的Register方法的EnableSwagger匿名函数中对应的过滤器(可以添加在//a#代码后面。)
c.OperationFilter<AddDefaultValues>();
在具体的调用参数上加上默认参数,在swagger的界面上就会有默认参数啦。
public class CheckMobile
{
[SwaggerDefaultValue("13482894351")]
[Required]
public string Mobile { get; set; }
}
实现Oauth2 API的调用
我们的WebAPI基于OAuth2的验证,所以Swagger上并不能直接调用。如果希望Swagger能直接调用OAuth2保护的API。
-
增加一个js到Web工程中, zhe
*js的内容如下
$('#input_apiKey').change(function () {
var key = $('#input_apiKey')[0].value;
var credentials = key.split(':'); //username:password expected
$.ajax({
url: "/Token",
type: "post",
contenttype: 'x-www-form-urlencoded',
data: "grant_type=password&username=" + credentials[0] + "&password=" + credentials[1],
success: function (response) {
var bearerToken = 'Bearer ' + response.access_token;
swaggerUi.api.clientAuthorizations.add('key', new SwaggerClient.ApiKeyAuthorization('Authorization', bearerToken, 'header'));
},
error: function (xhr, ajaxoptions, thrownerror) {
alert("输入的用户名密码不对,不能登陆!");
}
});
});```
*在Swagger.config 的Register方法的EanbleSwaggerUI匿名函数中加上对应的JS,可以加在//b#后面
`c.InjectJavaScript(typeof(SwaggerConfig).Assembly, "CrXXX.XX.SwaggerLogin.js");`
>CrXXX.XX 需要改成web工程的名字
在Swagger界面上的API_Key输入框输入oauth2的用户名密码即可登录.
上面描述的是使用ASP.net 自带的OAuth认证库,不是真正的oauth2,如果采用IdenittyServer3的认证方法,需要参照[教程](http://knowyourtoolset.com/2015/08/secure-web-apis-with-swagger-swashbuckle-and-oauth2-part-2/) 来实现, 我会尽快翻译.
使用上面的方法要注意的是,在IdentityServer中的设置里面,Client需要
允许重定向到 "http://WebAPI地址/swagger/ui/o2c-html"
##### Swagger API文档的效果图
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1697920-057deb18522917ce.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)