增加功能:增加swagger webapi文档

This commit is contained in:
Argo-MacBookPro 2018-10-24 17:12:16 +08:00
parent e66f5e0fdf
commit 8a38d58aef
10 changed files with 416 additions and 507 deletions

1
.gitignore vendored
View File

@ -346,6 +346,7 @@ ASALocalRun/
[Kk]eys/ [Kk]eys/
lib/ lib/
*.db *.db
Bootstrap.Admin.xml
###### -- Custom Ignore Section, Make sure all files you add to the git repo are below this line -- ###### ###### -- Custom Ignore Section, Make sure all files you add to the git repo are below this line -- ######

View File

@ -7,12 +7,17 @@
<MvcRazorCompileOnPublish>true</MvcRazorCompileOnPublish> <MvcRazorCompileOnPublish>true</MvcRazorCompileOnPublish>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>Z:\src\Longbow\BootstrapAdmin\Bootstrap.Admin\Bootstrap.Admin.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Bootstrap.Security.Mvc" Version="1.0.1" /> <PackageReference Include="Bootstrap.Security.Mvc" Version="1.0.1" />
<PackageReference Include="Longbow.Logging" Version="1.0.2" /> <PackageReference Include="Longbow.Logging" Version="1.0.2" />
<PackageReference Include="Longbow.Web" Version="1.0.1" /> <PackageReference Include="Longbow.Web" Version="1.0.1" />
<PackageReference Include="Microsoft.AspNetCore.App" /> <PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.0" PrivateAssets="All" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.0" PrivateAssets="All" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -141,13 +141,5 @@ namespace Bootstrap.Admin.Controllers
{ {
return View(new NavigatorBarModel(this)); return View(new NavigatorBarModel(this));
} }
/// <summary>
///
/// </summary>
/// <returns></returns>
public ActionResult Api()
{
return View(new NavigatorBarModel(this));
}
} }
} }

View File

@ -0,0 +1,36 @@
using Microsoft.AspNetCore.Authorization;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;
using System.Linq;
using Operation = Swashbuckle.AspNetCore.Swagger.Operation;
namespace Bootstrap.Admin
{
/// <summary>
///
/// </summary>
public class HttpHeaderOperation : IOperationFilter
{
/// <summary>
///
/// </summary>
/// <param name="operation"></param>
/// <param name="context"></param>
public void Apply(Operation operation, OperationFilterContext context)
{
if (operation.Parameters == null) operation.Parameters = new List<IParameter>();
if (context.MethodInfo.GetCustomAttributes(typeof(AllowAnonymousAttribute), true).Count() == 0)
{
operation.Parameters.Add(new NonBodyParameter()
{
Name = "Authorization", //添加Authorization头部参数
In = "header",
Type = "string",
Required = false
});
}
}
}
}

View File

@ -18,22 +18,35 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
using Swashbuckle.AspNetCore.Swagger;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
namespace Bootstrap.Admin namespace Bootstrap.Admin
{ {
/// <summary>
///
/// </summary>
public class Startup public class Startup
{ {
/// <summary>
///
/// </summary>
/// <param name="configuration"></param>
public Startup(IConfiguration configuration) public Startup(IConfiguration configuration)
{ {
Configuration = configuration; Configuration = configuration;
} }
/// <summary>
///
/// </summary>
public IConfiguration Configuration { get; } public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container. // This method gets called by the runtime. Use this method to add services to the container.
/// <summary>
///
/// </summary>
/// <param name="services"></param>
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
services.Configure<CookiePolicyOptions>(options => services.Configure<CookiePolicyOptions>(options =>
@ -65,9 +78,26 @@ namespace Bootstrap.Admin
JsonConvert.DefaultSettings = () => options.SerializerSettings; JsonConvert.DefaultSettings = () => options.SerializerSettings;
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => options.Cookie.Path = "/"); services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => options.Cookie.Path = "/");
} services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new Info
{
Version = "v1",
Title = "BootstrapAdmin API"
});
//Set the comments path for the swagger json and ui.
var xmlPath = Path.Combine(AppContext.BaseDirectory, "Bootstrap.Admin.xml");
options.IncludeXmlComments(xmlPath);
options.OperationFilter<HttpHeaderOperation>(); // 添加httpHeader参数
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
/// <summary>
///
/// </summary>
/// <param name="app"></param>
/// <param name="env"></param>
public void Configure(IApplicationBuilder app, IHostingEnvironment env) public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{ {
if (env.IsDevelopment()) if (env.IsDevelopment())
@ -93,6 +123,11 @@ namespace Bootstrap.Admin
name: "default", name: "default",
template: "{controller=Home}/{action=Index}/{id?}"); template: "{controller=Home}/{action=Index}/{id?}");
}); });
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "BootstrapAdmin API V1");
});
} }
} }
} }

View File

@ -1,20 +0,0 @@
@model NavigatorBarModel
@{
ViewBag.Title = "Api 文档";
}
@section javascript {
<script src="~/js/apidoc.js" asp-append-version="true"></script>
}
@section css {
<link href="~/css/api.css" rel="stylesheet" asp-append-version="true" />
}
<section>
<div><h3>接口返回值定义</h3></div>
<div><label class="control-label">布尔值:</label><div>成功返回True失败返回False</div></div>
<div><label class="control-label">对象:</label><div>Json字符串</div></div>
</section>
<section>
<div><h3>接口请求定义</h3></div>
<div><label class="control-label">内容类型</label><div>Content-Type:application/json; charset=utf-8</div></div>
<div><label class="control-label">授权Token</label><div>Token:362a4733-341a-464d-ab12-e01554338839</div></div>
</section>

View File

@ -1,35 +0,0 @@
h3 {
margin-top: 0;
color: #000;
}
.btn {
text-shadow: none;
}
.control-label {
width: 80px;
}
.main-content {
padding: 15px;
}
.main-content > section:not(:first-child) {
padding-top: 10px;
}
.main-content > section > div {
line-height: 26px;
}
.main-content > section > div > div {
display: inline-block;
word-break: break-all;
}
.test {
display: none;
padding: 10px 0 0 0;
color: #5cb85c;
}

View File

@ -1,105 +0,0 @@
$(function () {
var ajax = function (options) {
options = $.extend({
test: false,
div: undefined,
anonymous: false,
title: '未录入',
url: '',
method: 'get',
data: '',
headers: {},
success: function (result) {
},
error: function (textStatus, errorThrown) {
}
}, options);
if (options.url == '') {
document.writeln("请求地址丢失!");
return;
}
$.ajax({
url: options.url,
data: options.data,
type: options.method,
headers: options.headers,
success: function (result) {
if (!options.test) {
var $body = $('#main-content');
$body.append('<section></section>');
var $section = $body.find('section').last();
$section.append($.format('<h3>{0}</h3>', options.title));
$section.append($.format('<div><label class="control-label">请求地址</label><div>{0}</div></div>', options.url));
$section.append($.format('<div><label class="control-label">允许匿名</label><div>{0}</div></div>', options.anonymous ? "允许" : "不允许"));
$section.append($.format('<div><label class="control-label">Headers</label><div>{0}</div></div>', JSON.stringify(options.headers)));
$section.append($.format('<div><label class="control-label">HTTP方法</label><div>{0}</div></div>', options.method));
$section.append($.format('<div><label class="control-label">传递参数</label><div>{0}</div></div>', JSON.stringify(options.data)));
$section.append($.format('<div><label class="control-label">返回值</label><div>{0}</div></div>', JSON.stringify(result)));
$section.append('<div><label class="control-label">试一试</label></div>');
$section.append($.format('<div class="input-group"><input type="text" class="form-control" value=\'{1}\' data-val=\'{0}\' /><span class="input-group-btn"><button class="btn btn-default btn-success" type="button">试一试</button></span></div>', JSON.stringify(options), JSON.stringify(options.data)));
$section.append('<div class="test"></div>')
options.success(result);
}
else {
if (options.div) {
options.div.html($.format('<label class="control-label">测试结果:</label><div>{0}</div>', JSON.stringify(result))).show();
}
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
var $body = $('body');
var $section = $body.find('section').last();
$section.append($.format('<div><label class="control-label">错误参数</label><div>textStatus:{0}</div><div>', textStatus));
$section.append($.format('<div><label class="control-label">错误参数</label><div>errorThrown:{0}</div><div>', errorThrown));
options.error(textStatus, errorThrown);
}
});
};
$('body').on('click', 'button', function () {
var $input = $(this).parent().prev();
var options = $.extend(JSON.parse($input.attr('data-val')), { data: JSON.parse($input.val()) }, { test: true, div: $(this).parent().parent().next() });
ajax(options);
});
// 接口调用
ajax({
title: '用户登陆调用接口',
anonymous: true,
url: '../api/login', method: 'POST', data: { userName: 'Test', password: '1' }, success: function (result) {
var token = result.Token;
ajax({
title: '用户登陆信息接口', url: '../api/login', headers: { Token: token },
method: 'GET'
});
ajax({
title: '指定用户信息接口', url: '../api/Users', headers: { Token: token },
method: 'GET', data: { userName: "Test" }
});
ajax({
title: '检查当前用户名是否可用接口', url: '../api/Users', headers: { Token: token },
method: 'PUT', data: { UserName: "101", UserStatus: 9 }
});
ajax({
title: '更改用户显示名称接口', url: '../api/Users', headers: { Token: token },
method: 'PUT', data: { UserName: "101", UserStatus: 1, DisplayName: "1010" }
});
ajax({
title: '更改用户密码接口', url: '../api/Users', headers: { Token: token },
method: 'PUT', data: { UserName: "101", UserStatus: 2, Password: "1", NewPassword: "2" }
});
ajax({
title: '新建用户接口', url: '../api/Users', headers: { Token: token },
method: 'POST', data: { ID: 0, UserName: "102", Password: "1", DisplayName: "102" }
});
ajax({
title: '更新用户接口', url: '../api/Users', headers: { Token: token },
method: 'POST', data: { ID: 21, UserName: "102", Password: "1", DisplayName: "102" }
});
ajax({
title: '删除用户接口', url: '../api/Users', headers: { Token: token },
method: 'DELETE', data: { "": "50,51" }
});
}
});
});

View File

@ -48,7 +48,7 @@ INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [C
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, N'程序异常', 140, N'fa fa-cubes', N'~/Admin/Exceptions', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, N'程序异常', 140, N'fa fa-cubes', N'~/Admin/Exceptions', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (16, 0, N'工具集合', 160, N'fa fa-gavel', N'#', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (16, 0, N'工具集合', 160, N'fa fa-gavel', N'#', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (17, 16, N'客户端测试', 10, N'fa fa-wrench', N'~/Admin/Mobile', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (17, 16, N'客户端测试', 10, N'fa fa-wrench', N'~/Admin/Mobile', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (18, 16, N'API文档', 10, N'fa fa-wrench', N'~/Admin/Api', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (18, 16, N'API文档', 10, N'fa fa-wrench', N'~/swagger', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (19, 16, N'图标集', 10, N'fa fa-dashboard', N'~/Admin/FAIcon', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (19, 16, N'图标集', 10, N'fa fa-dashboard', N'~/Admin/FAIcon', N'0')
SET IDENTITY_INSERT [dbo].[Navigations] OFF SET IDENTITY_INSERT [dbo].[Navigations] OFF

View File

@ -42,7 +42,7 @@ INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Ca
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, '程序异常', 140, 'fa fa-cubes', '~/Admin/Exceptions', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, '程序异常', 140, 'fa fa-cubes', '~/Admin/Exceptions', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (16, 0, '工具集合', 160, 'fa fa-gavel', '#', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (16, 0, '工具集合', 160, 'fa fa-gavel', '#', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (17, 16, '客户端测试', 10, 'fa fa-wrench', '~/Admin/Mobile', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (17, 16, '客户端测试', 10, 'fa fa-wrench', '~/Admin/Mobile', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (18, 16, 'API文档', 10, 'fa fa-wrench', '~/Admin/Api', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (18, 16, 'API文档', 10, 'fa fa-wrench', '~/swagger', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (19, 16, '图标集', 10, 'fa fa-dashboard', '~/Admin/FAIco', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (19, 16, '图标集', 10, 'fa fa-dashboard', '~/Admin/FAIco', '0');
DELETE FROM GROUPS WHERE ID = 1; DELETE FROM GROUPS WHERE ID = 1;