├── src ├── Microsoft.AspNetCore.ApiHelp │ ├── UI │ │ ├── Swagger │ │ │ ├── src │ │ │ │ ├── app │ │ │ │ │ ├── app.component.html │ │ │ │ │ ├── components │ │ │ │ │ │ ├── main │ │ │ │ │ │ │ ├── jsonHandle │ │ │ │ │ │ │ │ ├── json-handle.component.html │ │ │ │ │ │ │ │ ├── json-handle.component.css │ │ │ │ │ │ │ │ └── json-handle.component.ts │ │ │ │ │ │ │ ├── resource │ │ │ │ │ │ │ │ ├── point │ │ │ │ │ │ │ │ │ ├── method.enum.ts │ │ │ │ │ │ │ │ │ ├── content-type │ │ │ │ │ │ │ │ │ │ ├── content-type.component.css │ │ │ │ │ │ │ │ │ │ ├── content-type.component.html │ │ │ │ │ │ │ │ │ │ └── content-type.component.ts │ │ │ │ │ │ │ │ │ ├── request │ │ │ │ │ │ │ │ │ │ ├── request.component.html │ │ │ │ │ │ │ │ │ │ ├── method │ │ │ │ │ │ │ │ │ │ │ ├── method.component.css │ │ │ │ │ │ │ │ │ │ │ ├── method.component.ts │ │ │ │ │ │ │ │ │ │ │ └── method.component.html │ │ │ │ │ │ │ │ │ │ └── request.component.ts │ │ │ │ │ │ │ │ │ ├── schema │ │ │ │ │ │ │ │ │ │ ├── model-schema.component.css │ │ │ │ │ │ │ │ │ │ ├── model-schema.component.html │ │ │ │ │ │ │ │ │ │ └── model-schema.component.ts │ │ │ │ │ │ │ │ │ ├── pointModel.ts │ │ │ │ │ │ │ │ │ ├── point.component.css │ │ │ │ │ │ │ │ │ ├── point.service.ts │ │ │ │ │ │ │ │ │ ├── point.component.html │ │ │ │ │ │ │ │ │ └── point.component.ts │ │ │ │ │ │ │ │ ├── resource.component.css │ │ │ │ │ │ │ │ ├── resource.component.html │ │ │ │ │ │ │ │ └── resource.component.ts │ │ │ │ │ │ │ ├── resourceModel.ts │ │ │ │ │ │ │ ├── main.component.css │ │ │ │ │ │ │ ├── resourceNav │ │ │ │ │ │ │ │ ├── resource.component.html │ │ │ │ │ │ │ │ ├── resource.component.ts │ │ │ │ │ │ │ │ └── resource.component.css │ │ │ │ │ │ │ ├── resourceService.ts │ │ │ │ │ │ │ ├── main.component.html │ │ │ │ │ │ │ └── main.component.ts │ │ │ │ │ │ └── header │ │ │ │ │ │ │ ├── header.component.ts │ │ │ │ │ │ │ └── header.component.html │ │ │ │ │ ├── app.component.ts │ │ │ │ │ ├── rxjs-operators.ts │ │ │ │ │ └── app.routes.ts │ │ │ │ ├── favicon.ico │ │ │ │ ├── fonts │ │ │ │ │ ├── DroidSans.ttf │ │ │ │ │ └── DroidSans-Bold.ttf │ │ │ │ ├── images │ │ │ │ │ ├── Collapsed.gif │ │ │ │ │ ├── Expanded.gif │ │ │ │ │ └── logo_small.png │ │ │ │ ├── vendor.browser.ts │ │ │ │ ├── css │ │ │ │ │ ├── typography.css │ │ │ │ │ └── reset.css │ │ │ │ ├── main.browser.ts │ │ │ │ ├── polyfills.browser.ts │ │ │ │ ├── custom-typings.d.ts │ │ │ │ └── index.html │ │ │ ├── dist │ │ │ │ ├── favicon.ico │ │ │ │ ├── fonts │ │ │ │ │ ├── DroidSans.ttf │ │ │ │ │ └── DroidSans-Bold.ttf │ │ │ │ ├── images │ │ │ │ │ ├── Collapsed.gif │ │ │ │ │ ├── Expanded.gif │ │ │ │ │ └── logo_small.png │ │ │ │ ├── css │ │ │ │ │ ├── typography.css │ │ │ │ │ └── reset.css │ │ │ │ └── index.html │ │ │ ├── tsconfig.json │ │ │ ├── package.json │ │ │ └── webpack.config.js │ │ ├── JsonH │ │ │ ├── favicon.ico │ │ │ ├── css │ │ │ │ ├── treePic │ │ │ │ │ ├── arr.png │ │ │ │ │ ├── elm.png │ │ │ │ │ ├── num.png │ │ │ │ │ ├── obj.png │ │ │ │ │ ├── str.png │ │ │ │ │ ├── folder.png │ │ │ │ │ ├── line.png │ │ │ │ │ ├── node.png │ │ │ │ │ ├── null.png │ │ │ │ │ ├── object.png │ │ │ │ │ ├── open.png │ │ │ │ │ ├── boolean.png │ │ │ │ │ ├── nodeLast.png │ │ │ │ │ ├── nodeRoot.png │ │ │ │ │ ├── openLast.png │ │ │ │ │ ├── openRoot.png │ │ │ │ │ ├── folderFirst.png │ │ │ │ │ ├── folderLast.png │ │ │ │ │ ├── folderRoot.png │ │ │ │ │ ├── objectOpen.png │ │ │ │ │ └── openFirst.png │ │ │ │ ├── img │ │ │ │ │ ├── setting-btn.png │ │ │ │ │ └── setting-btn-act.png │ │ │ │ ├── opt.css │ │ │ │ ├── tree.css │ │ │ │ └── jsonH.css │ │ │ ├── js │ │ │ │ ├── JSON.js │ │ │ │ ├── ad.js │ │ │ │ ├── listenResizeWin.js │ │ │ │ ├── pageInit.js │ │ │ │ ├── jsonH │ │ │ │ │ └── nav.js │ │ │ │ ├── lang.js │ │ │ │ └── envSetting.js │ │ │ └── index.html │ │ └── JsonEditor │ │ │ ├── favicon.ico │ │ │ └── index.html │ ├── Properties │ │ └── InternalsVisibleTo.cs │ ├── IIndexPageStreamFactory.cs │ ├── ApiHelpUI.cs │ ├── StreamExtensions.cs │ ├── IndexPageStreamFactory.cs │ ├── ApiHelpUIOptions.cs │ ├── RedirectMiddleware.cs │ ├── Microsoft.AspNetCore.ApiHelp.csproj │ ├── IApplicationBuilderExtensions.cs │ └── ApiHelpMiddleware.cs ├── Microsoft.AspNetCore.ApiHelp.Core │ ├── Properties │ │ └── InternalsVisibleTo.cs │ ├── ApiHelpInputModel.cs │ ├── DocumentGenerateStrategy.cs │ ├── ApiHelpOptions.cs │ ├── ApiHelpApplicationModelConvention.cs │ ├── Microsoft.AspNetCore.ApiHelp.Core.csproj │ ├── IMvcBuilderExtensions.cs │ ├── IMvcCoreBuilderExtensions.cs │ ├── ApiDescriptionExtensions.cs │ ├── ClosedGenericMatcher.cs │ ├── TypeSharedExtensions.cs │ ├── HelpController.cs │ ├── TypeJsonExtensions.cs │ └── TypeXDocExtensions.cs └── Host │ ├── appsettings.json │ ├── web.config │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── Controllers │ └── ValuesController.cs │ ├── Host.csproj │ └── Startup.cs ├── test └── Microsoft.AspNetCore.ApiHelp.Core.Test │ ├── TimeSpan.json │ ├── Schema.json │ ├── NestedSchema.json │ ├── Scaffold.json │ ├── Microsoft.AspNetCore.ApiHelp.Core.Test.csproj │ ├── NestedScaffold.json │ └── TypeJsonExtensionsTest.cs ├── NuGet.config ├── LICENSE ├── README.md ├── .gitattributes ├── ApiHelp.sln └── .gitignore /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/favicon.ico -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/jsonHandle/json-handle.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonEditor/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonEditor/favicon.ico -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/favicon.ico -------------------------------------------------------------------------------- /test/Microsoft.AspNetCore.ApiHelp.Core.Test/TimeSpan.json: -------------------------------------------------------------------------------- 1 | { 2 | "TemplateId": 0, 3 | "Users": [ 4 | 0 5 | ], 6 | "Items": [ 7 | "00:00:00" 8 | ] 9 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/arr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/arr.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/elm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/elm.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/num.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/num.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/obj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/obj.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/str.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/str.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/favicon.ico -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/folder.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/line.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/node.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/null.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/null.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/object.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/open.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/img/setting-btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/img/setting-btn.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/boolean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/boolean.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/nodeLast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/nodeLast.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/nodeRoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/nodeRoot.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/openLast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/openLast.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/openRoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/openRoot.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/img/setting-btn-act.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/img/setting-btn-act.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/folderFirst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/folderFirst.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/folderLast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/folderLast.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/folderRoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/folderRoot.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/objectOpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/objectOpen.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/openFirst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/treePic/openFirst.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/fonts/DroidSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/fonts/DroidSans.ttf -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/images/Collapsed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/images/Collapsed.gif -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/images/Expanded.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/images/Expanded.gif -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/fonts/DroidSans.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/fonts/DroidSans.ttf -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/images/Collapsed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/images/Collapsed.gif -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/images/Expanded.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/images/Expanded.gif -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/images/logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/images/logo_small.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/Properties/InternalsVisibleTo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Microsoft.AspNetCore.ApiHelp.Core.Test")] 4 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/images/logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/images/logo_small.png -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/Properties/InternalsVisibleTo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Microsoft.AspNetCore.ApiHelp.Core.Test")] 4 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/fonts/DroidSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/fonts/DroidSans-Bold.ttf -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/method.enum.ts: -------------------------------------------------------------------------------- 1 | export enum MethodEnum{ 2 | GET = 0, 3 | POST = 1, 4 | PUT = 2, 5 | DELETE = 3 6 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/fonts/DroidSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arch/ApiHelp/master/src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/fonts/DroidSans-Bold.ttf -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/content-type/content-type.component.css: -------------------------------------------------------------------------------- 1 | .content-type{ 2 | line-height: 50px; 3 | } 4 | 5 | select{ 6 | /*width:160px;*/ 7 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/request/request.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resourceModel.ts: -------------------------------------------------------------------------------- 1 | export class ResourceModel{ 2 | constructor( 3 | public name:string, 4 | public point:Array 5 | ){} 6 | } -------------------------------------------------------------------------------- /src/Host/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/schema/model-schema.component.css: -------------------------------------------------------------------------------- 1 | div{ 2 | margin:0 !important; 3 | padding:0; 4 | display:inline; 5 | } 6 | 7 | .attribute{ 8 | color:#000; 9 | } -------------------------------------------------------------------------------- /test/Microsoft.AspNetCore.ApiHelp.Core.Test/Schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "PageIndex": 0, 3 | "PageSize": 0, 4 | "TotalCount": 0, 5 | "TotalPages": 0, 6 | "Items": [ 7 | { 8 | "UserName": "", 9 | "Password": "" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/resource.component.css: -------------------------------------------------------------------------------- 1 | .heading{ 2 | /*-webkit-user-select:none; 3 | -moz-user-select:none; 4 | -ms-user-select:none; 5 | user-select:none;*/ 6 | } 7 | 8 | .heading a{ 9 | cursor: pointer 10 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/content-type/content-type.component.html: -------------------------------------------------------------------------------- 1 |
2 | {{type_text}} 3 | 6 |
-------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/ApiHelpInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | namespace Microsoft.AspNetCore.ApiHelp.Core { 4 | public class ApiHelpInputModel { 5 | public string HttpMethod { get; set; } 6 | public string RelativePath { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | moduleId: module.id, 5 | selector: 'header-pager', 6 | templateUrl: 'header.component.html' 7 | }) 8 | export class HeaderComponent implements OnInit { 9 | constructor() { } 10 | 11 | ngOnInit() { } 12 | } -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/main.component.css: -------------------------------------------------------------------------------- 1 | @media only screen and (min-width:1400px) { 2 | .screen-wide0{ 3 | display:block; 4 | } 5 | .screen-wide1{ 6 | display:none; 7 | } 8 | } 9 | 10 | @media only screen and (max-width:1400px){ 11 | .screen-wide0{ 12 | display:none; 13 | } 14 | .screen-wide1{ 15 | display:block; 16 | } 17 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/resource.component.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{name}} 4 |

5 |
6 | -------------------------------------------------------------------------------- /test/Microsoft.AspNetCore.ApiHelp.Core.Test/NestedSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "TotalCount": 0, 3 | "TotalPages": 0, 4 | "Items": [ 5 | { 6 | "UserName": "", 7 | "Password": "" 8 | } 9 | ], 10 | "PagedList": { 11 | "PageIndex": 0, 12 | "PageSize": 0, 13 | "TotalCount": 0, 14 | "TotalPages": 0, 15 | "Items": [ 16 | { 17 | "UserName": "", 18 | "Password": "" 19 | } 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/request/method/method.component.css: -------------------------------------------------------------------------------- 1 | .tab.active{ 2 | color:black; 3 | } 4 | 5 | .tab{ 6 | color:#AAA; 7 | cursor: pointer; 8 | font-size:16px; 9 | display:inline-block; 10 | margin:5px; 11 | } 12 | .data-type{ 13 | width:400px; 14 | display:block; 15 | } 16 | 17 | textarea 18 | { 19 | width:100%; 20 | height:100%; 21 | resize:none; 22 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/vendor.browser.ts: -------------------------------------------------------------------------------- 1 | // Vendors 2 | 3 | // Angular 2 4 | import '@angular/platform-browser-dynamic'; 5 | import '@angular/platform-browser'; 6 | import '@angular/core'; 7 | import '@angular/http'; 8 | import '@angular/router'; 9 | 10 | 11 | // RxJS 5 12 | // import 'rxjs/Rx'; 13 | 14 | 15 | // For vendors for example jQuery, Lodash, angular2-jwt import them here 16 | // Also see src/typings.d.ts as you also need to run `typings install x` where `x` is your module 17 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/content-type/content-type.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit,Input } from '@angular/core'; 2 | 3 | @Component({ 4 | moduleId: module.id, 5 | selector: 'content-type', 6 | templateUrl: 'content-type.component.html', 7 | styleUrls:['content-type.component.css'] 8 | }) 9 | export class ContentTypeComponent implements OnInit { 10 | constructor() { } 11 | @Input() type_text:string; 12 | @Input() type_data:any; 13 | 14 | ngOnInit() { } 15 | 16 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/DocumentGenerateStrategy.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | namespace Microsoft.AspNetCore.ApiHelp.Core { 4 | /// 5 | /// Represents the document generate strategy. 6 | /// 7 | public enum DocumentGenerateStrategy { 8 | /// 9 | /// Indicating eager loading. 10 | /// 11 | Eager, 12 | /// 13 | /// Indicating lazy loading. 14 | /// 15 | Lazy, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/IIndexPageStreamFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System.IO; 4 | 5 | namespace Microsoft.AspNetCore.ApiHelp { 6 | /// 7 | /// Defines the interface(s) for creating the stream of Index.html file. 8 | /// 9 | public interface IIndexPageStreamFactory { 10 | /// 11 | /// Creates the stream of the Index.html file. 12 | /// 13 | /// Stream. 14 | Stream Create(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/css/typography.css: -------------------------------------------------------------------------------- 1 | /* Google Font's Droid Sans */ 2 | @font-face { 3 | font-family: 'Droid Sans'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: local('Droid Sans'), local('DroidSans'), url('../fonts/DroidSans.ttf') format('truetype'); 7 | } 8 | /* Google Font's Droid Sans Bold */ 9 | @font-face { 10 | font-family: 'Droid Sans'; 11 | font-style: normal; 12 | font-weight: 700; 13 | src: local('Droid Sans Bold'), local('DroidSans-Bold'), url('../fonts/DroidSans-Bold.ttf') format('truetype'); 14 | } 15 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/css/typography.css: -------------------------------------------------------------------------------- 1 | /* Google Font's Droid Sans */ 2 | @font-face { 3 | font-family: 'Droid Sans'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: local('Droid Sans'), local('DroidSans'), url('../fonts/DroidSans.ttf') format('truetype'); 7 | } 8 | /* Google Font's Droid Sans Bold */ 9 | @font-face { 10 | font-family: 'Droid Sans'; 11 | font-style: normal; 12 | font-weight: 700; 13 | src: local('Droid Sans Bold'), local('DroidSans-Bold'), url('../fonts/DroidSans-Bold.ttf') format('truetype'); 14 | } 15 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import './rxjs-operators'; 4 | 5 | import { HeaderComponent } from './components/header/header.component'; 6 | import { MainComponent } from './components/main/main.component'; 7 | 8 | @Component({ 9 | selector: 'app', 10 | pipes: [], 11 | providers: [], 12 | // directives: [ ROUTER_DIRECTIVES ], 13 | directives:[HeaderComponent,MainComponent], 14 | templateUrl: './app.component.html', 15 | }) 16 | export class App { 17 | constructor() {} 18 | } 19 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "outDir": "dist", 6 | "rootDir": ".", 7 | "sourceMap": false, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "moduleResolution": "node" 11 | }, 12 | "exclude": [ 13 | "node_modules" 14 | ], 15 | "awesomeTypescriptLoaderOptions": { 16 | "useWebpackText": true 17 | }, 18 | "compileOnSave": false, 19 | "buildOnSave": false, 20 | "atom": { "rewriteTsconfig": false } 21 | } 22 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/rxjs-operators.ts: -------------------------------------------------------------------------------- 1 | // import 'rxjs/Rx'; // adds ALL RxJS statics & operators to Observable 2 | 3 | // See node_module/rxjs/Rxjs.js 4 | // Import just the rxjs statics and operators we need for THIS app. 5 | 6 | // Statics 7 | import 'rxjs/add/observable/throw'; 8 | 9 | // Operators 10 | import 'rxjs/add/operator/catch'; 11 | import 'rxjs/add/operator/debounceTime'; 12 | import 'rxjs/add/operator/distinctUntilChanged'; 13 | import 'rxjs/add/operator/map'; 14 | import 'rxjs/add/operator/switchMap'; 15 | import 'rxjs/add/operator/toPromise'; 16 | -------------------------------------------------------------------------------- /src/Host/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/pointModel.ts: -------------------------------------------------------------------------------- 1 | export class PointModel{ 2 | Summary:string; 3 | Response:Response; 4 | Request:any; 5 | } 6 | 7 | export class Response{ 8 | Scaffold:any; 9 | Schema: any; 10 | SupportedMediaType: any; 11 | } 12 | 13 | export class ModelResponse{ 14 | ModelType:string; 15 | Model:any; 16 | } 17 | 18 | export class DataModel{ 19 | constructor(public name:string,public value){} 20 | } 21 | 22 | export class ValueModel{ 23 | IsOptional:boolean; 24 | Summary:string; 25 | Type:string; 26 | } 27 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/main.browser.ts: -------------------------------------------------------------------------------- 1 | import {LocationStrategy, HashLocationStrategy} from '@angular/common'; 2 | import {bootstrap} from '@angular/platform-browser-dynamic'; 3 | import {HTTP_PROVIDERS} from '@angular/http'; 4 | import {enableProdMode} from '@angular/core'; 5 | 6 | import {APP_ROUTER_PROVIDERS} from './app/app.routes'; 7 | import {App} from './app/app.component'; 8 | 9 | enableProdMode() 10 | 11 | bootstrap(App, [ 12 | HTTP_PROVIDERS, 13 | // APP_ROUTER_PROVIDERS, 14 | { provide: LocationStrategy, useClass: HashLocationStrategy } 15 | ]) 16 | .catch(err => console.error(err)); 17 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/request/request.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit,Input } from '@angular/core'; 2 | 3 | import { MethodComponent } from './method/method.component'; 4 | import { MethodEnum } from '../method.enum'; 5 | @Component({ 6 | moduleId: module.id, 7 | selector: 'request', 8 | templateUrl: 'request.component.html', 9 | directives:[MethodComponent] 10 | }) 11 | export class RequestComponent implements OnInit { 12 | constructor() { } 13 | 14 | @Input() method:MethodEnum; 15 | @Input() request:any; 16 | ngOnInit() { 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/ApiHelpUI.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | namespace Microsoft.AspNetCore.ApiHelp { 4 | /// 5 | /// Represents the Api help UI styles. 6 | /// 7 | public enum ApiHelpUI { 8 | /// 9 | /// Indicating use swagger-style UI. 10 | /// 11 | Swagger, 12 | /// 13 | /// Indicating use Json-Handle as UI. 14 | /// 15 | JsonH, 16 | /// 17 | /// Indicating use Json-Editory as UI. 18 | /// 19 | JsonEditor, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/point.component.css: -------------------------------------------------------------------------------- 1 | .signature-nav li{ 2 | 3 | } 4 | 5 | .heading{ 6 | /*-webkit-user-select:none; 7 | -moz-user-select:none; 8 | -ms-user-select:none; 9 | user-select:none;*/ 10 | cursor: pointer; 11 | } 12 | 13 | .heading a{ 14 | cursor: pointer 15 | } 16 | 17 | .signature-nav a{ 18 | cursor: pointer 19 | } 20 | 21 | .summary{ 22 | display: inline-block; 23 | /*width:400px;*/ 24 | float:right; 25 | line-height: 28px; 26 | /*text-align: right*/ 27 | margin-right:5px; 28 | } 29 | 30 | .heading h3{ 31 | width:100% !important; 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Host/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.AspNetCore.Builder; 8 | 9 | namespace Host 10 | { 11 | public class Program 12 | { 13 | public static void Main(string[] args) 14 | { 15 | var host = new WebHostBuilder() 16 | .UseKestrel() 17 | .UseContentRoot(Directory.GetCurrentDirectory()) 18 | .UseIISIntegration() 19 | .UseStartup() 20 | .Build(); 21 | 22 | host.Run(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/header/header.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/Microsoft.AspNetCore.ApiHelp.Core.Test/Scaffold.json: -------------------------------------------------------------------------------- 1 | { 2 | "PageIndex": { 3 | "Summary": "", 4 | "Type": "Int32", 5 | "IsOptional": false 6 | }, 7 | "PageSize": { 8 | "Summary": "", 9 | "Type": "Int32", 10 | "IsOptional": false 11 | }, 12 | "TotalCount": { 13 | "Summary": "", 14 | "Type": "Int32", 15 | "IsOptional": false 16 | }, 17 | "TotalPages": { 18 | "Summary": "", 19 | "Type": "Int32", 20 | "IsOptional": false 21 | }, 22 | "Items": [ 23 | { 24 | "UserName": { 25 | "Summary": "", 26 | "Type": "String", 27 | "IsOptional": false 28 | }, 29 | "Password": { 30 | "Summary": "", 31 | "Type": "String", 32 | "IsOptional": false 33 | } 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /src/Host/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:2859/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "api/values", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "Host": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "launchUrl": "http://localhost:5000/api/values", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resourceNav/resource.component.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Group Name 4 |

5 | 12 |
13 | 14 | 28 | -------------------------------------------------------------------------------- /test/Microsoft.AspNetCore.ApiHelp.Core.Test/Microsoft.AspNetCore.ApiHelp.Core.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp1.1 5 | $(NoWarn);CS1591 6 | true 7 | Microsoft.AspNetCore.ApiHelp.Core.Test 8 | Microsoft.AspNetCore.ApiHelp.Core.Test 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { provideRouter, RouterConfig } from '@angular/router'; 2 | 3 | // import {About} from './components/about/about'; 4 | // import {Home} from './components/home/home'; 5 | // import {RepoBrowser} from './components/repo-browser/repo-browser'; 6 | // import {RepoList} from './components/repo-list/repo-list'; 7 | // import {RepoDetail} from './components/repo-detail/repo-detail'; 8 | 9 | const routes: RouterConfig = [ 10 | // { path: '', redirectTo: 'home', terminal: true }, 11 | // { path: 'home', component: Home }, 12 | // { path: 'about', component: About }, 13 | // { path: 'github', component: RepoBrowser, children: [ 14 | // { path: ':org', component: RepoList, children: [ 15 | // { path: ':repo', component: RepoDetail }, 16 | // { path: '', component: RepoDetail } 17 | // ]}, 18 | // { path: '', component: RepoList} 19 | // ]} 20 | ]; 21 | 22 | export const APP_ROUTER_PROVIDERS = [ 23 | provideRouter(routes) 24 | ]; 25 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/js/JSON.js: -------------------------------------------------------------------------------- 1 | 2 | JH.mod.add('JSON', function (modName, JH) { 3 | var _pri_static = {}, _pro_static = {}, _interface = []; 4 | 5 | 6 | 7 | var _pub_static = function () { 8 | var _checkArgs, _parseDOM, _init, _uiEvt, _custEvt, _airEvt, _main, _this = this, _args = arguments, _pri = {}, _pro = {}, _pub = {__varyContext_:function (pro, pub) {_pro = pro;_pub = pub;}}, _mod, _base, _parent; 9 | 10 | _pub = JH.mergePropertyFrom(JSON, _pub); 11 | 12 | _main = function () { 13 | _pub = JH.mod.init(_pub_static, _this, _pro, _pub, _pro_static, _interface).pub; 14 | 15 | }; 16 | 17 | 18 | 19 | 20 | JH.mergePropertyFrom(_pri, { 21 | 22 | 23 | 24 | }); 25 | 26 | 27 | JH.mergePropertyFrom(_pub, { 28 | 29 | 30 | 31 | "destroy" : function(){ 32 | if(_pub) { 33 | 34 | _pri = _pro = _pub = null; 35 | } 36 | } 37 | //------------------------------------------- 38 | }); 39 | 40 | 41 | _main(); 42 | 43 | 44 | return _pub; 45 | 46 | }; 47 | 48 | return _pub_static; 49 | }); -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/StreamExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using System.IO; 5 | using System.Text; 6 | using Microsoft.AspNetCore.Http; 7 | 8 | namespace Microsoft.AspNetCore.ApiHelp { 9 | internal static class StreamExtensions { 10 | public static Stream AssignParameters(this Stream template, params Tuple[] templateParams) { 11 | using (var sr = new StreamReader(template)) { 12 | var sb = new StringBuilder(sr.ReadToEnd()); 13 | foreach (var param in templateParams) { 14 | sb.Replace(param.Item1, param.Item2); 15 | } 16 | 17 | return new MemoryStream(Encoding.UTF8.GetBytes(sb.ToString())); 18 | } 19 | } 20 | 21 | public static void ToResponse(this Stream content, HttpResponse response) { 22 | response.StatusCode = 200; 23 | response.ContentType = "text/html"; 24 | content.CopyTo(response.Body); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/polyfills.browser.ts: -------------------------------------------------------------------------------- 1 | // Polyfills 2 | 3 | import 'ie-shim'; // Internet Explorer 9 support 4 | 5 | // import 'core-js/es6'; 6 | // Added parts of es6 which are necessary for your project or your browser support requirements. 7 | import 'core-js/es6/symbol'; 8 | import 'core-js/es6/object'; 9 | import 'core-js/es6/function'; 10 | import 'core-js/es6/parse-int'; 11 | import 'core-js/es6/parse-float'; 12 | import 'core-js/es6/number'; 13 | import 'core-js/es6/math'; 14 | import 'core-js/es6/string'; 15 | import 'core-js/es6/date'; 16 | import 'core-js/es6/array'; 17 | import 'core-js/es6/regexp'; 18 | import 'core-js/es6/map'; 19 | import 'core-js/es6/set'; 20 | import 'core-js/es6/weak-map'; 21 | import 'core-js/es6/weak-set'; 22 | import 'core-js/es6/typed'; 23 | import 'core-js/es6/reflect'; 24 | // see issue https://github.com/AngularClass/angular2-webpack-starter/issues/709 25 | // import 'core-js/es6/promise'; 26 | 27 | import 'core-js/es7/reflect'; 28 | import 'zone.js/dist/zone'; 29 | import 'zone.js/dist/long-stack-trace-zone'; 30 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/opt.css: -------------------------------------------------------------------------------- 1 | 2 | .ad-help { 3 | position:relative; 4 | max-width:705px; 5 | float:left; 6 | margin:20px 0; 7 | width: auto; 8 | } 9 | .hide { 10 | border:none; 11 | } 12 | .hide .content, 13 | .hide #closeAdBtn { 14 | display:none; 15 | } 16 | #aboutAdBtn { 17 | cursor:pointer; 18 | } 19 | a { 20 | color:#577cff; 21 | } 22 | a:hover { 23 | text-decoration:none; 24 | } 25 | .ad-list ul { 26 | padding-left:15px; 27 | } 28 | .ad-list ul li{ 29 | margin:0 0 25px; 30 | color:#aaa; 31 | } 32 | .ad-list li h4 { 33 | margin-bottom:5px; 34 | } 35 | .ad-list li h4 span { 36 | font-weight:normal; 37 | } 38 | .ad-list li h4 .title { 39 | text-decoration:none; 40 | } 41 | .ad-list li p { 42 | margin:5px 0; 43 | } 44 | 45 | #closeAdBtn { 46 | position:absolute; 47 | width:14px; 48 | height:14px; 49 | line-height:14px; 50 | padding:0; 51 | text-align:center; 52 | right:4px; 53 | top:13px; 54 | border:none; 55 | background-color:transparent; 56 | color:#333; 57 | margin:0; 58 | cursor:pointer; 59 | } 60 | #closeAdBtn:hover { 61 | color:#577cff; 62 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 love.net 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Host/Controllers/ValuesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace Host.Controllers 8 | { 9 | [Route("api/[controller]")] 10 | public class ValuesController : Controller 11 | { 12 | // GET api/values 13 | [HttpGet] 14 | public IEnumerable Get() 15 | { 16 | return new string[] { "value1", "value2" }; 17 | } 18 | 19 | // GET api/values/5 20 | [HttpGet("{id}")] 21 | public string Get(int id) 22 | { 23 | return "value"; 24 | } 25 | 26 | // POST api/values 27 | [HttpPost] 28 | public void Post([FromBody]string value) 29 | { 30 | } 31 | 32 | // PUT api/values/5 33 | [HttpPut("{id}")] 34 | public void Put(int id, [FromBody]string value) 35 | { 36 | } 37 | 38 | // DELETE api/values/5 39 | [HttpDelete("{id}")] 40 | public void Delete(int id) 41 | { 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resourceService.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Headers, RequestOptions, Response, Http } from '@angular/http'; 3 | import { Observable } from 'rxjs/Observable'; 4 | 5 | @Injectable() 6 | export class ResourceService { 7 | private url = window.location.origin + "/api/help"; 8 | 9 | constructor(private http:Http) { } 10 | 11 | GetData():Observable{ 12 | return this.http.get(this.url) 13 | .map(this.extractData) 14 | .catch(this.handleError); 15 | } 16 | 17 | private extractData(res: Response) { 18 | let body = res.json(); 19 | return body || {}; 20 | } 21 | 22 | private handleError(error: any) { 23 | // In a real world app, we might use a remote logging infrastructure 24 | // We'd also dig deeper into the error to get a better message 25 | let errMsg = (error.message) ? error.message : 26 | error.status ? `${error.status} - ${error.statusText}` : 'Server error'; 27 | console.error(errMsg); // log to console instead 28 | return Observable.throw(errMsg); 29 | } 30 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/resource.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input,Output,EventEmitter } from '@angular/core'; 2 | 3 | import { PointComponent } from './point/point.component'; 4 | 5 | @Component({ 6 | moduleId: module.id, 7 | selector: 'resource-api', 8 | templateUrl: 'resource.component.html', 9 | styleUrls: ['resource.component.css'], 10 | directives: [PointComponent] 11 | 12 | }) 13 | export class ResourceComponent implements OnInit { 14 | constructor() { } 15 | 16 | @Input() name: string; 17 | @Input() point: any; 18 | @Output() setCurrent = new EventEmitter(); 19 | open0: boolean = false; 20 | ngOnInit() { 21 | } 22 | 23 | Open() { 24 | this.open0= !this.open0; 25 | this.setCurrent.emit(this.open0); 26 | } 27 | 28 | toArray(object){ 29 | var arr = new Array(); 30 | for (var key in object) { 31 | if (object.hasOwnProperty(key)) { 32 | var name = key; 33 | var value = object[key]; 34 | arr.push(name); 35 | } 36 | } 37 | return arr; 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/point.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Headers, RequestOptions, Response, Http } from '@angular/http'; 3 | import { Observable } from 'rxjs/Observable'; 4 | 5 | @Injectable() 6 | export class PointService { 7 | private url = window.location.origin + "/api/help/get"; 8 | 9 | constructor(private http:Http) { } 10 | 11 | GetData(para:string):Observable{ 12 | return this.http.get(this.url,{search:para}) 13 | .map(this.extractData) 14 | .catch(this.handleError); 15 | } 16 | 17 | private extractData(res: Response) { 18 | let body = res.json(); 19 | return body || {}; 20 | } 21 | 22 | private handleError(error: any) { 23 | // In a real world app, we might use a remote logging infrastructure 24 | // We'd also dig deeper into the error to get a better message 25 | let errMsg = (error.message) ? error.message : 26 | error.status ? `${error.status} - ${error.statusText}` : 'Server error'; 27 | console.error(errMsg); // log to console instead 28 | return Observable.throw(errMsg); 29 | } 30 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/ApiHelpOptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | namespace Microsoft.AspNetCore.ApiHelp.Core { 4 | /// 5 | /// Represents the all options will be used for configuring Api help toolchain. 6 | /// 7 | public class ApiHelpOptions { 8 | /// 9 | /// Gets or sets a value indicating whether include supported media type. 10 | /// 11 | /// true if include supported media type; otherwise, false. 12 | public bool IncludeSupportedMediaType { get; set; } = true; 13 | /// 14 | /// Gets or sets the value indicating whether ignore obsoleted API or not. 15 | /// 16 | /// The value indicating whether ignore obsoleted API or not. 17 | public bool IgnoreObsoleteApi { get; set; } = true; 18 | 19 | /// 20 | /// Gets or sets the API document loading policy. 21 | /// 22 | /// The API document loading policy. 23 | public DocumentGenerateStrategy GenerateStrategy { get; set; } = DocumentGenerateStrategy.Lazy; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/main.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
    6 |
  • 7 | 8 |
  • 9 |
10 | 20 |
21 |
22 | 23 |
24 | 25 |
-------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resourceNav/resource.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit,Input} from '@angular/core'; 2 | 3 | import { PointComponent } from '../resource/point/point.component'; 4 | @Component({ 5 | moduleId: module.id, 6 | selector: 'resource-new', 7 | templateUrl: 'resource.component.html', 8 | styleUrls:['resource.component.css'], 9 | directives:[PointComponent] 10 | }) 11 | export class ResourceNewComponent implements OnInit { 12 | constructor() { } 13 | 14 | @Input() resourceList:any; 15 | ngOnInit() { 16 | 17 | } 18 | 19 | point:any; 20 | name:any; 21 | current:number;//=0; 22 | toArray(object){ 23 | var arr = new Array(); 24 | for (var key in object) { 25 | if (object.hasOwnProperty(key)) { 26 | var name = key; 27 | var value = object[key]; 28 | arr.push(name); 29 | } 30 | } 31 | return arr; 32 | } 33 | 34 | bindPoint(item,index){ 35 | this.point = item.point; 36 | this.name = item.name; 37 | this.current = index; 38 | } 39 | 40 | test(data){ 41 | console.log(data) 42 | } 43 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/schema/model-schema.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/ApiHelpApplicationModelConvention.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using Microsoft.AspNetCore.Mvc.ApplicationModels; 5 | 6 | namespace Microsoft.AspNetCore.ApiHelp.Core { 7 | /// 8 | /// Allows customization of the of the Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModel 9 | /// 10 | internal class ApiHelpApplicationModelConvention : IApplicationModelConvention { 11 | /// 12 | /// Called to apply the convention to the . 13 | /// 14 | /// The . 15 | public void Apply(ApplicationModel application) { 16 | application.ApiExplorer.IsVisible = true; 17 | foreach (var controller in application.Controllers) { 18 | if (controller.ControllerName.Equals("Help", StringComparison.OrdinalIgnoreCase)) { 19 | controller.ApiExplorer.IsVisible = false; 20 | continue; 21 | } 22 | 23 | controller.ApiExplorer.GroupName = controller.ControllerName; 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/IndexPageStreamFactory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System.IO; 4 | using System.Reflection; 5 | 6 | namespace Microsoft.AspNetCore.ApiHelp { 7 | /// 8 | /// Represents the default implementation of interface. 9 | /// 10 | public class IndexPageStreamFactory : IIndexPageStreamFactory { 11 | private readonly Assembly _resourceAssembly; 12 | private readonly string _indexResourceName; 13 | 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | /// Name of the index resource. 18 | public IndexPageStreamFactory(string indexResourceName) { 19 | _resourceAssembly = GetType().GetTypeInfo().Assembly; 20 | _indexResourceName = indexResourceName; 21 | } 22 | 23 | /// 24 | /// Creates the stream of the Index.html file. 25 | /// 26 | /// Stream. 27 | public Stream Create() => _resourceAssembly.GetManifestResourceStream(_indexResourceName); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/Microsoft.AspNetCore.ApiHelp.Core.Test/NestedScaffold.json: -------------------------------------------------------------------------------- 1 | { 2 | "TotalCount": { 3 | "Summary": "", 4 | "Type": "Int32", 5 | "IsOptional": false 6 | }, 7 | "TotalPages": { 8 | "Summary": "", 9 | "Type": "Int32", 10 | "IsOptional": false 11 | }, 12 | "Items": [ 13 | { 14 | "UserName": { 15 | "Summary": "", 16 | "Type": "String", 17 | "IsOptional": false 18 | }, 19 | "Password": { 20 | "Summary": "", 21 | "Type": "String", 22 | "IsOptional": false 23 | } 24 | } 25 | ], 26 | "PagedList": { 27 | "PageIndex": { 28 | "Summary": "", 29 | "Type": "Int32", 30 | "IsOptional": false 31 | }, 32 | "PageSize": { 33 | "Summary": "", 34 | "Type": "Int32", 35 | "IsOptional": false 36 | }, 37 | "TotalCount": { 38 | "Summary": "", 39 | "Type": "Int32", 40 | "IsOptional": false 41 | }, 42 | "TotalPages": { 43 | "Summary": "", 44 | "Type": "Int32", 45 | "IsOptional": false 46 | }, 47 | "Items": [ 48 | { 49 | "UserName": { 50 | "Summary": "", 51 | "Type": "String", 52 | "IsOptional": false 53 | }, 54 | "Password": { 55 | "Summary": "", 56 | "Type": "String", 57 | "IsOptional": false 58 | } 59 | } 60 | ] 61 | } 62 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/ApiHelpUIOptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | namespace Microsoft.AspNetCore.ApiHelp { 4 | /// 5 | /// Represents the all options will be used to configure Api help UI. 6 | /// 7 | public class ApiHelpUIOptions { 8 | /// 9 | /// Gets or sets the title. 10 | /// 11 | /// The title. 12 | public string Title { get; set; } = "API toolchain for ASP.NET Core"; 13 | /// 14 | /// Gets or sets the description. 15 | /// 16 | /// The description. 17 | public string Description { get; set; } = "A toolchain for ASP.NET Core to automatically generating API documentation."; 18 | /// 19 | /// Gets or sets the base route. 20 | /// 21 | /// The base route. 22 | public string BaseRoute { get; set; } = "api/help/ui"; 23 | /// 24 | /// Gets the index path. 25 | /// 26 | /// The index path. 27 | public string IndexPath => BaseRoute.Trim('/') + "/index.html"; 28 | /// 29 | /// Gets or sets the UI. 30 | /// 31 | /// The UI. 32 | public ApiHelpUI UI { get; set; } = ApiHelpUI.Swagger; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Host/Host.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp1.1 4 | true 5 | Exe 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/Microsoft.AspNetCore.ApiHelp.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.1.1 4 | A toolchain for ASP.NET Core to automatically generating API documentation. 5 | rigofunc;rigofunc@outlook.com;lotosbin;lotosbin@gmail.com 6 | net46;netstandard1.6 7 | $(NoWarn);CS1591 8 | true 9 | true 10 | Microsoft.AspNetCore.ApiHelp.Core 11 | Microsoft.AspNetCore.ApiHelp.Core 12 | swagger;documentation;discovery;help;api-help;webapi;aspnet;aspnetcore 13 | https://github.com/arch/ApiHelp 14 | https://github.com/arch/ApiHelp/blob/master/LICENSE 15 | git 16 | https://github.com/arch/ApiHelp.git 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/main.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | import { ResourceComponent } from './resource/resource.component'; 4 | import { ResourceNewComponent } from './resourceNav/resource.component'; 5 | import { ResourceService } from './resourceService.ts'; 6 | import { ResourceModel } from './resourceModel.ts'; 7 | @Component({ 8 | moduleId: module.id, 9 | selector: 'main-pager', 10 | templateUrl: 'main.component.html', 11 | styleUrls:['main.component.css'], 12 | directives: [ResourceComponent,ResourceNewComponent], 13 | providers: [ResourceService] 14 | }) 15 | export class MainComponent implements OnInit { 16 | constructor(private resourceService: ResourceService) { } 17 | list: Array = new Array(); 18 | open:boolean=false; 19 | current:boolean=false; 20 | ngOnInit() { 21 | this.resourceService.GetData() 22 | .subscribe( 23 | data => this.toArray(data) 24 | ); 25 | } 26 | 27 | toArray(data: any) { 28 | for (var prop in data) { 29 | var item: ResourceModel = new ResourceModel(prop, data[prop]); 30 | this.list.push(item); 31 | } 32 | } 33 | 34 | onSetCurrent(current){ 35 | if(current){ 36 | return "resource active"; 37 | } 38 | else{ 39 | return "resource"; 40 | } 41 | } 42 | 43 | test(data){ 44 | console.log(data); 45 | } 46 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resourceNav/resource.component.css: -------------------------------------------------------------------------------- 1 | .flowerMenu{ 2 | position: fixed; 3 | top:80px; 4 | font-family: "Droid Sans", sans-serif; 5 | width:180px; 6 | margin:20px; 7 | -moz-box-shadow: 5px 5px 15px #888888; 8 | box-shadow: 5px 5px 15px #888888; 9 | border-top-left-radius: 15px; 10 | border-top-right-radius: 15px; 11 | } 12 | 13 | @media only screen and (min-width:1400px) { 14 | .flowerMenu{ 15 | left:50%; 16 | margin-left:-700px; 17 | } 18 | } 19 | 20 | @media only screen and (max-width:1400px){ 21 | .flowerMenu{ 22 | left:0; 23 | display:none; 24 | } 25 | } 26 | 27 | 28 | .flowerMenu ul{ 29 | border:1px solid #ededed; 30 | padding-left:15px; 31 | 32 | } 33 | 34 | .flowerMenu ul li{ 35 | margin:5px 0; 36 | color:#CCC; 37 | cursor: pointer; 38 | line-height: 10px; 39 | } 40 | .flowerMenu ul li:hover a{ 41 | font-weight: bold; 42 | color:#000; 43 | } 44 | 45 | /*.flowerMenu ul li.active{ 46 | 47 | }*/ 48 | .flowerMenu ul li.active a{ 49 | font-weight: bold; 50 | color:#000; 51 | } 52 | 53 | 54 | .flowerMenu h4{ 55 | padding:15px; 56 | background-color:#547f00; 57 | text-align: center; 58 | font-weight: bold; 59 | color:white; 60 | border-top-left-radius: 15px; 61 | border-top-right-radius: 15px; 62 | } 63 | 64 | #resources{ 65 | margin-top:40px; 66 | } 67 | 68 | .flowerMenu h2 a{ 69 | color:#CCC; 70 | text-decoration: none; 71 | } 72 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/custom-typings.d.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Custom Type Definitions 3 | * When including 3rd party modules you also need to include the type definition for the module 4 | * if they don't provide one within the module. You can try to install it with typings 5 | 6 | typings install node --save 7 | 8 | * If you can't find the type definition in the registry we can make an ambient definition in 9 | * this file for now. For example 10 | 11 | declare module "my-module" { 12 | export function doesSomething(value: string): string; 13 | } 14 | 15 | * 16 | * If you're prototying and you will fix the types later you can also declare it as type any 17 | * 18 | 19 | declare var assert: any; 20 | 21 | * 22 | * If you're importing a module that uses Node.js modules which are CommonJS you need to import as 23 | * 24 | 25 | import * as _ from 'lodash' 26 | 27 | * You can include your type definitions in this file until you create one for the typings registry 28 | * see https://github.com/typings/registry 29 | * 30 | */ 31 | 32 | // Alias legacy import/exports pre rc 33 | declare module "angular2/core" { 34 | export * from '@angular/core'; 35 | } 36 | 37 | declare module "angular2/http" { 38 | export * from '@angular/http'; 39 | } 40 | 41 | declare module 'angular2/platform/browser' { 42 | export * from '@angular/platform-browser' 43 | } 44 | 45 | declare module 'angular2/testing' { 46 | export * from '@angular/core/testing'; 47 | } 48 | 49 | declare module 'angular2/http/testing' { 50 | export * from '@angular/http/testing'; 51 | } 52 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/RedirectMiddleware.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.AspNetCore.Routing; 6 | using Microsoft.AspNetCore.Routing.Template; 7 | 8 | namespace Microsoft.AspNetCore.ApiHelp { 9 | /// 10 | /// Enable redirect from base path to index path 11 | /// 12 | public class RedirectMiddleware { 13 | private readonly RequestDelegate _next; 14 | private readonly string _toPath; 15 | private readonly TemplateMatcher _requestMatcher; 16 | 17 | public RedirectMiddleware(RequestDelegate next, string fromPath, string toPath) { 18 | _next = next; 19 | _toPath = toPath; 20 | _requestMatcher = new TemplateMatcher(TemplateParser.Parse(fromPath), new RouteValueDictionary()); 21 | } 22 | 23 | public async Task Invoke(HttpContext httpContext) { 24 | if (!RequestingFromPath(httpContext.Request)) { 25 | await _next(httpContext); 26 | return; 27 | } 28 | 29 | RespondWithRedirect(httpContext.Response, httpContext.Request.PathBase); 30 | } 31 | 32 | private bool RequestingFromPath(HttpRequest request) { 33 | if (request.Method != "GET") 34 | return false; 35 | 36 | return _requestMatcher.TryMatch(request.Path, new RouteValueDictionary()); 37 | } 38 | 39 | private void RespondWithRedirect(HttpResponse response, string pathBase) { 40 | response.Redirect(pathBase + "/" + _toPath); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/Microsoft.AspNetCore.ApiHelp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.1.1 4 | A toolchain for ASP.NET Core to automatically generating API documentation. 5 | rigofunc;rigofunc@outlook.com;lotosbin;lotosbin@gmail.com 6 | net46;netstandard1.6 7 | $(NoWarn);CS1591 8 | true 9 | true 10 | Microsoft.AspNetCore.ApiHelp 11 | Microsoft.AspNetCore.ApiHelp 12 | swagger;documentation;discovery;help;api-help;webapi;aspnet;aspnetcore 13 | https://github.com/arch/ApiHelp 14 | https://github.com/arch/ApiHelp/blob/master/LICENSE 15 | git 16 | https://github.com/arch/ApiHelp.git 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonEditor/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %(Title) 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 45 | 46 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %(Title) 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Loading... 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 56 | 57 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %(Title) 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Loading... 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 56 | 57 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/schema/model-schema.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | moduleId: module.id, 5 | selector: 'model-schema', 6 | templateUrl: 'model-schema.component.html', 7 | styleUrls:['model-schema.component.css'], 8 | directives:[ModelSchemaComponent] 9 | }) 10 | export class ModelSchemaComponent implements OnInit { 11 | constructor() { } 12 | @Input() schema: any; 13 | ngOnInit() { 14 | } 15 | 16 | 17 | jsonHandle(object){ 18 | var item =[]; 19 | if(object instanceof Array){ 20 | // for(var i=0,len = object.length;i 9 | /// Extensions for configuring API help services using an . 10 | /// 11 | public static class IMvcBuilderExtensions { 12 | /// 13 | /// Configuring API help services using an . 14 | /// 15 | /// The interface for configuring MVC services. 16 | /// An action to configure the . 17 | /// The interface for configuring MVC services. 18 | public static IMvcBuilder AddApiHelp(this IMvcBuilder builder, Action setupAction = null) { 19 | if (builder == null) { 20 | throw new ArgumentNullException(nameof(builder)); 21 | } 22 | 23 | AddApiHelpServices(builder.Services); 24 | 25 | if (setupAction != null) { 26 | builder.Services.Configure(setupAction); 27 | } 28 | else { 29 | builder.Services.Configure(options => { 30 | options.IncludeSupportedMediaType = true; 31 | options.IgnoreObsoleteApi = true; 32 | options.GenerateStrategy = DocumentGenerateStrategy.Eager; 33 | }); 34 | } 35 | 36 | return builder; 37 | } 38 | 39 | private static void AddApiHelpServices(IServiceCollection services) { 40 | services.Configure(c => 41 | c.Conventions.Add(new ApiHelpApplicationModelConvention())); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/jsonHandle/json-handle.component.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* CSS Document */ 3 | div.ControlsRow, div.HeadersRow { 4 | font-family: Georgia; 5 | } 6 | 7 | div.Canvas { 8 | font-family: Lucida Console, Georgia; 9 | font-size: 13px; 10 | background-color: #ECECEC; 11 | color: #000000; 12 | border: solid 1px #CECECE; 13 | } 14 | 15 | .ObjectBrace { 16 | color: #00AA00; 17 | font-weight: bold; 18 | } 19 | 20 | .ArrayBrace { 21 | color: #0033FF; 22 | font-weight: bold; 23 | } 24 | 25 | .PropertyName { 26 | color: #CC0000; 27 | font-weight: bold; 28 | } 29 | 30 | .String { 31 | color: #007777; 32 | } 33 | 34 | .Number { 35 | color: #AA00AA; 36 | } 37 | 38 | .Boolean { 39 | color: #0000FF; 40 | } 41 | 42 | .Function { 43 | color: #AA6633; 44 | text-decoration: italic; 45 | } 46 | 47 | .Null { 48 | color: #0000FF; 49 | } 50 | 51 | .Comma { 52 | color: #000000; 53 | font-weight: bold; 54 | } 55 | 56 | PRE.CodeContainer { 57 | margin-top: 0px; 58 | margin-bottom: 0px; 59 | } 60 | 61 | PRE.CodeContainer img { 62 | cursor: pointer; 63 | border: none; 64 | margin-bottom: -1px; 65 | } 66 | 67 | #CollapsibleViewDetail a { 68 | padding-left: 10px; 69 | } 70 | 71 | #ControlsRow { 72 | white-space: nowrap; 73 | font: 11px Georgia; 74 | } 75 | 76 | #TabSizeHolder { 77 | padding-left: 10px; 78 | padding-right: 10px; 79 | } 80 | 81 | #HeaderTitle { 82 | text-align: right; 83 | font-size: 11px; 84 | } 85 | 86 | #HeaderSubTitle { 87 | margin-bottom: 2px; 88 | margin-top: 0px; 89 | } 90 | 91 | #RawJson { 92 | width: 99%; 93 | height: 120px; 94 | } 95 | 96 | A.OtherToolsLink { 97 | color: #555; 98 | text-decoration: none; 99 | } 100 | 101 | A.OtherToolsLink:hover { 102 | text-decoration: underline; 103 | } 104 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/tree.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .treeNav {text-shadow: -2px 1px 3px rgba(70, 70, 70, 0.2);} 4 | .treeNav .ico {float:left;cursor:pointer;padding:0 0 0 2px;} 5 | .treeNav .row {padding:0 0 0 16px;line-height:24px;background-color@:#fff;overflow@:hidden;} 6 | 7 | .treeNav .elmSpan {white-space: nowrap;margin:0 0 0 1px;display:inline-block;border-radius:8px;} 8 | .treeNav .cur>.row .elmSpan {box-shadow: -3px 3px 5px rgba(50, 50, 50, 0.4);font-weight:bold;background-color:#577cff;} 9 | .treeNav .cur>.row .elmSpan * {color:#fff !important;} 10 | 11 | .treeNav .elmBlock {cursor:row-resize;background:url(treePic/line.png) repeat-y 0 0;} 12 | 13 | .treeNav .elmBox {cursor:pointer;border-radius:8px;padding-left:0;border-left:2px solid #fafaff;} 14 | .treeNav .row:hover .elmBox{font-weight:bold;border-color:#778cff;} 15 | .treeNav .elm {padding:3px 8px;white-space:nowrap;} 16 | 17 | .treeNav .elmList {padding:0 0 0 22px;} 18 | 19 | .treeNav .folder {background:url(treePic/line.png) repeat-y 0 0;} 20 | .treeNav .root.elmBlock>.row {background-image:url(treePic/folderRoot.png);} 21 | .treeNav .root.open.elmBlock>.row {background-image:url(treePic/openRoot.png);} 22 | 23 | .treeNav .elmBlock .row {background:none no-repeat 0 0;} 24 | .treeNav .folder>.row {background-image:url(treePic/folder.png);} 25 | 26 | .treeNav .last, 27 | .treeNav .root{background-image:none;} 28 | .treeNav .last.folder>.row {background-image:url(treePic/folderLast.png);} 29 | .treeNav .last.node>.row, 30 | .treeNav .empty.elmBlock.last>.row {background-image:url(treePic/nodeLast.png);} 31 | 32 | .treeNav .open>.row {background-image:url(treePic/open.png);} 33 | .treeNav .open.last>.row {background-image:url(treePic/openLast.png);} 34 | .treeNav .open.root>.row {background-image:url(treePic/open.png);} 35 | 36 | .treeNav .empty>.row {background-image:url(treePic/node.png);} 37 | .treeNav .last.node>.row {background-image:url(treePic/nodeLast.png);} 38 | 39 | .treeNav .node .row {margin:0;white-space:nowrap;background:url(treePic/node.png) no-repeat 0 0;cursor:default;} 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/IMvcCoreBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.ApiHelp.Core; 6 | 7 | namespace Microsoft.Extensions.DependencyInjection { 8 | /// 9 | /// Extensions for configuring API help services using an . 10 | /// 11 | public static class IMvcCoreBuilderExtensions { 12 | /// 13 | /// Configuring API help services using an . 14 | /// 15 | /// The interface for configuring essential MVC services. 16 | /// An action to configure the . 17 | /// The interface for configuring essential MVC services. 18 | public static IMvcCoreBuilder AddApiHelp(this IMvcCoreBuilder builder, Action setupAction = null) { 19 | if (builder == null) { 20 | throw new ArgumentNullException(nameof(builder)); 21 | } 22 | 23 | builder.AddApiExplorer(); 24 | 25 | AddApiHelpServices(builder.Services); 26 | 27 | if (setupAction != null) { 28 | builder.Services.Configure(setupAction); 29 | } 30 | else { 31 | builder.Services.Configure(options => { 32 | options.IncludeSupportedMediaType = true; 33 | options.IgnoreObsoleteApi = true; 34 | options.GenerateStrategy = DocumentGenerateStrategy.Eager; 35 | }); 36 | } 37 | 38 | return builder; 39 | } 40 | 41 | private static void AddApiHelpServices(IServiceCollection services) { 42 | services.Configure(c => 43 | c.Conventions.Add(new ApiHelpApplicationModelConvention())); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apihelp", 3 | "version": "1.0.0", 4 | "description": "A toolchain for ASP.NET Core to automatically generating API documentation.", 5 | "scripts": { 6 | "typings-install": "typings install", 7 | "postinstall": "npm run typings-install", 8 | "build": "webpack --inline --colors --progress --display-error-details --display-cached", 9 | "watch": "npm run build -- --watch", 10 | "server": "webpack-dev-server --inline --colors --progress --display-error-details --display-cached --port 3000 --content-base src", 11 | "start": "npm run server" 12 | }, 13 | "contributors": [ 14 | "rigofunc " 15 | ], 16 | "license": "MIT", 17 | "devDependencies": { 18 | "angular2-template-loader": "^0.4.0", 19 | "awesome-typescript-loader": "^1.1.1", 20 | "copy-webpack-plugin": "^3.0.1", 21 | "css-loader": "^0.23.1", 22 | "json-loader": "^0.5.4", 23 | "raw-loader": "^0.5.1", 24 | "source-map-loader": "^0.1.5", 25 | "to-string-loader": "^1.1.4", 26 | "typescript": "~1.8.9", 27 | "typings": "~1.0.3", 28 | "webpack": "^1.12.9", 29 | "webpack-dev-server": "^1.14.0", 30 | "webpack-merge": "^0.8.4" 31 | }, 32 | "dependencies": { 33 | "@angular/common": "2.0.0-rc.4", 34 | "@angular/compiler": "2.0.0-rc.4", 35 | "@angular/core": "2.0.0-rc.4", 36 | "@angular/http": "2.0.0-rc.4", 37 | "@angular/platform-browser": "2.0.0-rc.4", 38 | "@angular/platform-browser-dynamic": "2.0.0-rc.4", 39 | "@angular/platform-server": "2.0.0-rc.4", 40 | "@angular/router": "3.0.0-beta.2", 41 | "core-js": "^2.2.0", 42 | "ie-shim": "^0.1.0", 43 | "rxjs": "5.0.0-beta.6", 44 | "zone.js": "~0.6.12" 45 | }, 46 | "keywords": [ 47 | "lovedotnet", 48 | "love.net.help", 49 | "love.net", 50 | "aspnetcore" 51 | ], 52 | "repository": { 53 | "type": "git", 54 | "url": "https://github.com/lovedotnet/ApiHelp.git" 55 | }, 56 | "bugs": { 57 | "url": "https://github.com/lovedotnet/ApiHelp/issues" 58 | }, 59 | "homepage": "https://github.com/lovedotnet/ApiHelp" 60 | } 61 | -------------------------------------------------------------------------------- /src/Host/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.ApiHelp; 6 | using Microsoft.AspNetCore.ApiHelp.Core; 7 | using Microsoft.AspNetCore.Builder; 8 | using Microsoft.AspNetCore.Hosting; 9 | using Microsoft.Extensions.Configuration; 10 | using Microsoft.Extensions.DependencyInjection; 11 | using Microsoft.Extensions.Logging; 12 | 13 | namespace Host 14 | { 15 | public class Startup 16 | { 17 | public Startup(IHostingEnvironment env) 18 | { 19 | var builder = new ConfigurationBuilder() 20 | .SetBasePath(env.ContentRootPath) 21 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 22 | .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); 23 | 24 | if (env.IsEnvironment("Development")) 25 | { 26 | } 27 | 28 | builder.AddEnvironmentVariables(); 29 | Configuration = builder.Build(); 30 | } 31 | 32 | public IConfigurationRoot Configuration { get; } 33 | 34 | // This method gets called by the runtime. Use this method to add services to the container 35 | public void ConfigureServices(IServiceCollection services) 36 | { 37 | services.AddMvc() 38 | .AddApiHelp(options => { 39 | options.IgnoreObsoleteApi = true; 40 | options.GenerateStrategy = DocumentGenerateStrategy.Eager; 41 | options.IncludeSupportedMediaType = false; 42 | }); 43 | } 44 | 45 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline 46 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 47 | { 48 | loggerFactory.AddConsole(Configuration.GetSection("Logging")); 49 | loggerFactory.AddDebug(); 50 | 51 | app.UseApiHelp(new ApiHelpUIOptions { 52 | UI = ApiHelpUI.Swagger, 53 | }); 54 | 55 | app.UseMvc(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/js/ad.js: -------------------------------------------------------------------------------- 1 | 2 | JH.mod.add('ad', function (modName, JH) { 3 | var _pri_static = {}, _pro_static = {}, _interface = []; 4 | 5 | 6 | 7 | var _pub_static = function (oIni) { 8 | var _checkArgs, _parseDOM, _init, _uiEvt, _custEvt, _airEvt, _main, _this = this, _args = arguments, _pri = {}, _pro = {}, _pub = {__varyContext_:function (pro, pub) {_pro = pro;_pub = pub;}}, _mod, _base, _parent; 9 | 10 | _main = function () { 11 | _pub = JH.mod.init(_pub_static, _this, _pro, _pub, _pro_static, _interface).pub; 12 | if(oIni) { 13 | _pri.getIni = function (cb) { 14 | cb({ 15 | code : 1, 16 | data : oIni 17 | }); 18 | }; 19 | } 20 | }; 21 | 22 | 23 | 24 | _pri["request"] = JH.request(_pub); 25 | 26 | JH.mergePropertyFrom(_pri, { 27 | "setIni" : _pri.request.create(null, 'setIni'), 28 | "getIni" : function (cb) { 29 | _pri.request.create(null, 'getIni', { 30 | succeed : function (oIni) { 31 | cb(oIni); 32 | } 33 | }).send(); 34 | }, 35 | "fetchAd" : function (cb) { 36 | _pri.getIni(function (oResp) { 37 | var oIni = oResp.data; 38 | var aList = oIni.adList; 39 | var oAd = null; 40 | var currIndex = oIni.adIndex; 41 | if(aList && aList.length) { 42 | if(currIndex >= aList.length) { 43 | currIndex = 0; 44 | } 45 | oAd = aList[currIndex]; 46 | currIndex++; 47 | } 48 | if(oAd && oIni.adShoot[oAd.id]) { 49 | oAd = null; 50 | } 51 | _pri.setIni.send({ 52 | adIndex : currIndex 53 | }); 54 | cb(oAd); 55 | }); 56 | } 57 | 58 | }); 59 | 60 | 61 | JH.mergePropertyFrom(_pub, { 62 | "getAd" : function (cb) { 63 | _pri.fetchAd(function (oAd) { 64 | cb(oAd); 65 | }); 66 | }, 67 | "getAdList" : function (cb) { 68 | _pri.getIni(function (oResp) { 69 | cb(oResp.data.adList); 70 | }); 71 | }, 72 | 73 | "destroy" : function(){ 74 | if(_pub) { 75 | 76 | _pri = _pro = _pub = null; 77 | } 78 | } 79 | //------------------------------------------- 80 | }); 81 | 82 | 83 | _main(); 84 | 85 | 86 | return _pub; 87 | 88 | }; 89 | 90 | return _pub_static; 91 | }); -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/request/method/method.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | import { MethodEnum } from '../../method.enum'; 4 | import { JsonHandleComponent } from '../../../../jsonHandle/json-handle.component'; 5 | import { ContentTypeComponent } from '../../content-type/content-type.component'; 6 | @Component({ 7 | moduleId: module.id, 8 | selector: 'method', 9 | templateUrl: 'method.component.html', 10 | styleUrls:['method.component.css'], 11 | directives:[JsonHandleComponent,ContentTypeComponent] 12 | }) 13 | export class MethodComponent implements OnInit { 14 | constructor() { } 15 | 16 | @Input() type: MethodEnum; 17 | @Input() parameters: any; 18 | formatValue:string=""; 19 | ngOnInit() { } 20 | 21 | jsonHandle(object) { 22 | var item = []; 23 | if (typeof object == 'object') { 24 | if (object instanceof Array) { 25 | 26 | } else { 27 | for (var key in object) { 28 | if (object.hasOwnProperty(key)) { 29 | if(key!="SupportedMediaType") 30 | { 31 | var name = key; 32 | var value = object[key]; 33 | item.push({ name, value }); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | return item; 40 | } 41 | 42 | getDataType(data) { 43 | if (typeof data == 'object') { 44 | if (data instanceof Array) { 45 | return 'array'; 46 | } 47 | else { 48 | return 'object' 49 | } 50 | } else { 51 | return typeof data; 52 | } 53 | } 54 | 55 | getJsonString(json){ 56 | var jsonString = JSON.stringify(json); 57 | return jsonString; 58 | } 59 | 60 | getValue(){ 61 | // console.log(123123); 62 | } 63 | 64 | onGetValue(json:string){ 65 | this.formatValue =json; 66 | } 67 | 68 | 69 | test(data) { 70 | alert(123); 71 | console.log(data); 72 | debugger; 73 | } 74 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/ApiDescriptionExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Reflection; 7 | using Microsoft.AspNetCore.Mvc.ApiExplorer; 8 | using Microsoft.AspNetCore.Mvc.Controllers; 9 | 10 | namespace Microsoft.AspNetCore.ApiHelp.Core { 11 | internal static class ApiDescriptionExtensions { 12 | internal static IEnumerable SupportedRequestMediaTypes(this ApiDescription apiDescription) { 13 | return apiDescription.SupportedRequestFormats 14 | .Select(requestFormat => requestFormat.MediaType); 15 | } 16 | 17 | internal static IEnumerable SupportedResponseMediaTypes(this ApiDescription apiDescription) { 18 | return apiDescription.SupportedResponseTypes 19 | .SelectMany(responseType => responseType.ApiResponseFormats) 20 | .Select(responseFormat => responseFormat.MediaType) 21 | .Distinct(); 22 | } 23 | 24 | internal static IEnumerable GetActionAttributes(this ApiDescription apiDescription) { 25 | var actionDescriptor = apiDescription.ActionDescriptor as ControllerActionDescriptor; 26 | #if NET46 27 | return (actionDescriptor != null) 28 | ? actionDescriptor.MethodInfo.GetCustomAttributes(false).Cast() 29 | : Enumerable.Empty(); 30 | #else 31 | return (actionDescriptor != null) 32 | ? actionDescriptor.MethodInfo.GetCustomAttributes(false) 33 | : Enumerable.Empty(); 34 | #endif 35 | } 36 | 37 | internal static string GetSummary(this ApiDescription apiDescription) { 38 | var actionDescriptor = apiDescription.ActionDescriptor as ControllerActionDescriptor; 39 | return (actionDescriptor != null) 40 | ? actionDescriptor.MethodInfo.XmlDoc() 41 | : apiDescription.ActionDescriptor.DisplayName; 42 | } 43 | 44 | internal static bool IsObsolete(this ApiDescription apiDescription) { 45 | return apiDescription.GetActionAttributes().OfType().Any(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/IApplicationBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using System.Reflection; 5 | using Microsoft.AspNetCore.ApiHelp; 6 | using Microsoft.AspNetCore.StaticFiles; 7 | using Microsoft.Extensions.FileProviders; 8 | 9 | namespace Microsoft.AspNetCore.Builder { 10 | public static class IApplicationBuilderExtensions { 11 | public static IApplicationBuilder UseApiHelp(this IApplicationBuilder app, ApiHelpUIOptions uiOptions = null) { 12 | if(uiOptions == null) { 13 | uiOptions = new ApiHelpUIOptions(); 14 | } 15 | 16 | // Enable redirect from base path ton index path. 17 | app.UseMiddleware(uiOptions.BaseRoute, uiOptions.IndexPath); 18 | 19 | // Serve indexPath via middleware 20 | app.UseMiddleware(uiOptions); 21 | 22 | // Serve all other UI assets as static files 23 | var options = new FileServerOptions(); 24 | options.RequestPath = $"/{uiOptions.BaseRoute}"; 25 | options.EnableDefaultFiles = false; 26 | options.StaticFileOptions.ContentTypeProvider = new FileExtensionContentTypeProvider(); 27 | 28 | // Debug view the embed files 29 | var embedFiles = typeof(IApplicationBuilderExtensions).GetTypeInfo().Assembly.GetManifestResourceNames(); 30 | 31 | var baseNamespace = "Microsoft.AspNetCore.ApiHelp.UI."; 32 | switch (uiOptions.UI) { 33 | case ApiHelpUI.Swagger: 34 | baseNamespace += "Swagger.dist"; 35 | break; 36 | case ApiHelpUI.JsonH: 37 | baseNamespace += "JsonH"; 38 | break; 39 | case ApiHelpUI.JsonEditor: 40 | baseNamespace += "JsonEditor"; 41 | break; 42 | default: 43 | throw new ArgumentOutOfRangeException(nameof(options)); 44 | } 45 | options.FileProvider = new EmbeddedFileProvider(typeof(ApiHelpUI).GetTypeInfo().Assembly, baseNamespace); 46 | 47 | app.UseFileServer(options); 48 | 49 | return app; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microsoft.AspNetCore.ApiHelp 2 | 3 | A toolchain for ASP.NET Core to automatically generating API documentation. 4 | 5 | # Features 6 | - [x] Read XML comments at run time (so the deployment need to include yourAssembly.xml file). 7 | - [x] Get **Enum** raw constant value and XML comments. 8 | 9 | ```C# 10 | public enum Gender { 11 | /// 12 | /// 未知. 13 | /// 14 | Unknown, 15 | /// 16 | /// 男性. 17 | /// 18 | Male, 19 | /// 20 | /// 女性. 21 | /// 22 | Female, 23 | } 24 | ``` 25 | 26 | ```JSON 27 | { 28 | "0": "未知", 29 | "1": "男性", 30 | "2": "女性" 31 | } 32 | ``` 33 | - [x] Generate API documentation for ASP.NET Core. 34 | - [x] JsonOutputFormatter use camel case or not determined by the API (Because it's API). 35 | - [x] More... 36 | 37 | # Running from demo 38 | 39 | To integrate `ApiHelp` to your project, download this repo and see [Host](src/Host) source code, running and open link [api/help/ui](http://localhost:5000/api/help/ui/) 40 | in your browser to view the result. 41 | 42 | # Packages 43 | - [Microsoft.AspNetCore.ApiHelp.Core](https://www.nuget.org/packages/Microsoft.AspNetCore.ApiHelp.Core/1.0.0) 44 | 45 | The core API toolchain for ASP.NET Core. 46 | 47 | - [Microsoft.AspNetCore.ApiHelp](https://www.nuget.org/packages/Microsoft.AspNetCore.ApiHelp/1.0.0) 48 | 49 | The three styles UI (Swagger, JsonH, JsonEditor) for Microsoft.AspNetCore.ApiHelp.Core. 50 | 51 | # How to use 52 | 53 | ## Install package. 54 | 55 | `PM> Install-Package Microsoft.AspNetCore.ApiHelp` 56 | 57 | ## Configure Startup.cs. 58 | 59 | ```csharp 60 | public void ConfigureServices(IServiceCollection services) { 61 | services.AddMvc() 62 | .AddApiHelp(options => { 63 | options.IgnoreObsoleteApi = true; 64 | options.GenerateStrategy = DocumentGenerateStrategy.Eager; 65 | options.IncludeSupportedMediaType = false; 66 | }); 67 | } 68 | 69 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { 70 | loggerFactory.AddConsole(Configuration.GetSection("Logging")); 71 | 72 | app.UseApiHelp(new ApiHelpUIOptions { 73 | Title = "API toolchain for ASP.NET Core", 74 | UI = ApiHelpUI.Swagger, 75 | }); 76 | 77 | app.UseMvc(); 78 | } 79 | ``` -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/ApiHelpMiddleware.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using System.IO; 5 | using System.Reflection; 6 | using System.Threading.Tasks; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.AspNetCore.Routing; 9 | using Microsoft.AspNetCore.Routing.Template; 10 | 11 | namespace Microsoft.AspNetCore.ApiHelp { 12 | public class ApiHelpMiddleware { 13 | private readonly RequestDelegate _next; 14 | private readonly TemplateMatcher _requestMatcher; 15 | private readonly ApiHelpUIOptions _options; 16 | private readonly Assembly _resourceAssembly; 17 | private readonly string _templateResourceName; 18 | 19 | public ApiHelpMiddleware(RequestDelegate next, ApiHelpUIOptions options) { 20 | _next = next; 21 | _options = options; 22 | _requestMatcher = new TemplateMatcher(TemplateParser.Parse(_options.IndexPath), new RouteValueDictionary()); 23 | _resourceAssembly = GetType().GetTypeInfo().Assembly; 24 | 25 | // set the index resource name. 26 | _templateResourceName = "Microsoft.AspNetCore.ApiHelp.UI."; 27 | switch (_options.UI) { 28 | case ApiHelpUI.Swagger: 29 | _templateResourceName += "Swagger.dist.index.html"; 30 | break; 31 | case ApiHelpUI.JsonH: 32 | _templateResourceName += "JsonH.index.html"; 33 | break; 34 | case ApiHelpUI.JsonEditor: 35 | _templateResourceName += "JsonEditor.index.html"; 36 | break; 37 | default: 38 | throw new ArgumentOutOfRangeException(nameof(options)); 39 | } 40 | } 41 | 42 | public async Task Invoke(HttpContext httpContext) { 43 | if (!RequestingApiHelpUI(httpContext.Request)) { 44 | await _next(httpContext); 45 | return; 46 | } 47 | 48 | var template = _resourceAssembly.GetManifestResourceStream(_templateResourceName); 49 | 50 | template.AssignParameters(new Tuple($"%(Title)", _options.Title)).ToResponse(httpContext.Response); 51 | } 52 | 53 | private bool RequestingApiHelpUI(HttpRequest request) 54 | => (request.Method == "GET") && _requestMatcher.TryMatch(request.Path, new RouteValueDictionary()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/js/listenResizeWin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @example 3 | 'kit/listenResizeWin' 4 | 5 | $$listenResizeWin.add(fn); 6 | $$listenResizeWin.remove(fn); 7 | $$listenResizeWin.clear(); 8 | $$listenResizeWin.destroy(); 9 | */ 10 | JH.mod.add([], 'listenResizeWin', function (modName, JH, $$) { 11 | var _interface = [], _pri_static = {}, _pro_static = {}, _pub_static = {}; 12 | 13 | 14 | _pri_static["callbackList"] = []; 15 | 16 | _pub_static["checkResize"] = function () { 17 | var iWinWidth = document.documentElement.clientWidth; 18 | var iWinHeight = document.documentElement.clientHeight; 19 | var oWH = { 20 | width:iWinWidth, 21 | height:iWinHeight, 22 | oldWidth : _pub_static.width, 23 | oldHeight : _pub_static.height 24 | }; 25 | if(_pri_static.callbackList.length 26 | &&( 27 | _pub_static.width != iWinWidth 28 | || _pub_static.height != iWinHeight 29 | ) 30 | ) { 31 | _pri_static.runCallbackList(oWH); 32 | } 33 | _pub_static.width = iWinWidth; 34 | _pub_static.height = iWinHeight; 35 | return oWH; 36 | }; 37 | 38 | _pri_static["runCallbackList"] = function (oWH) { 39 | var i, l; 40 | for (i=0, l = _pri_static.callbackList.length; i < l; ++i) { 41 | try{ 42 | _pri_static.callbackList[i](oWH); 43 | }catch(e) {} 44 | } 45 | }; 46 | 47 | _pri_static["listenResizeWin"] = function () { 48 | _pub_static.checkResize(); 49 | _pri_static.iSI = setInterval(function() { 50 | _pub_static.checkResize(); 51 | },1000); 52 | $(window).on('resize', _pub_static.checkResize); 53 | }; 54 | 55 | _pub_static["add"] = function (callback) { 56 | _pri_static.callbackList.push(callback); 57 | //callback({ 58 | //width:_pub_static.width, 59 | //height:_pub_static.height, 60 | //oldWidth : _pub_static.width, 61 | //oldHeight : _pub_static.height 62 | //}); 63 | }; 64 | 65 | _pub_static["remove"] = function (callback) { 66 | var i, l; 67 | for (i=0, l = _pri_static.callbackList.length; i < l; ++i) { 68 | if(_pri_static.callbackList[i] === callback) { 69 | _pri_static.callbackList.splice(i, 1); 70 | return true; 71 | } 72 | } 73 | return false; 74 | }; 75 | 76 | _pub_static["clear"] = function () { 77 | _pri_static.callbackList = []; 78 | }; 79 | 80 | _pub_static["destroy"] = function () { 81 | _pub_static.clear(); 82 | clearInterval(_pri_static.iSI); 83 | $(window).off('resize', _pub_static.checkResize); 84 | }; 85 | 86 | _pri_static.listenResizeWin(); 87 | 88 | return _pub_static; 89 | 90 | }); -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/request/method/method.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 参数名称 4 | 参数值 5 | 传参类型 6 | 参数类型 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 |
18 | 19 | {{item.value.Source}} 20 | 21 | 22 | 23 | scaffold 24 | schema 25 | 26 | 27 | 28 | 29 | scaffold 30 | schema 31 | 32 | 33 | 34 | {{item.value.Scaffold}} 35 | null 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | var CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | 5 | // Webpack Config 6 | var webpackConfig = { 7 | entry: { 8 | 'polyfills': './src/polyfills.browser.ts', 9 | 'vendor': './src/vendor.browser.ts', 10 | 'main': './src/main.browser.ts', 11 | }, 12 | 13 | output: { 14 | path: './dist', 15 | }, 16 | 17 | plugins: [ 18 | new webpack.optimize.OccurenceOrderPlugin(true), 19 | new webpack.optimize.CommonsChunkPlugin({ name: ['main', 'vendor', 'polyfills'], minChunks: Infinity }), 20 | new CopyWebpackPlugin([ 21 | {from:'./src/css',to:'./css'}, 22 | {from:'./src/images',to:'./images'}, 23 | {from:'./src/favicon.ico',to:'./'}, 24 | {from:'./src/index.html',to:'./'}, 25 | {from:'./src/fonts',to:'./fonts'} 26 | ]) 27 | ], 28 | 29 | module: { 30 | loaders: [ 31 | // .ts files for TypeScript 32 | { test: /\.ts$/, loaders: ['awesome-typescript-loader', 'angular2-template-loader'] }, 33 | { test: /\.css$/, loaders: ['to-string-loader', 'css-loader'] }, 34 | { test: /\.html$/, loader: 'raw-loader' }, 35 | { test: /\.json$/, loader: 'json-loader' }, 36 | 37 | ] 38 | } 39 | 40 | }; 41 | 42 | 43 | // Our Webpack Defaults 44 | var defaultConfig = { 45 | devtool: 'cheap-module-source-map', 46 | cache: true, 47 | debug: true, 48 | output: { 49 | filename: '[name].bundle.js', 50 | sourceMapFilename: '[name].map', 51 | chunkFilename: '[id].chunk.js' 52 | }, 53 | 54 | module: { 55 | preLoaders: [ 56 | { 57 | test: /\.js$/, 58 | loader: 'source-map-loader', 59 | exclude: [ 60 | // these packages have problems with their sourcemaps 61 | path.join(__dirname, 'node_modules', 'rxjs'), 62 | path.join(__dirname, 'node_modules', '@angular2-material'), 63 | path.join(__dirname, 'node_modules', '@angular'), 64 | ] 65 | } 66 | ], 67 | noParse: [ 68 | path.join(__dirname, 'node_modules', 'zone.js', 'dist'), 69 | path.join(__dirname, 'node_modules', 'angular2', 'bundles') 70 | ] 71 | }, 72 | 73 | resolve: { 74 | root: [ path.join(__dirname, 'src') ], 75 | extensions: ['', '.ts', '.js', '.json'] 76 | }, 77 | 78 | devServer: { 79 | historyApiFallback: true, 80 | watchOptions: { aggregateTimeout: 300, poll: 1000 } 81 | }, 82 | 83 | node: { 84 | global: 1, 85 | crypto: 'empty', 86 | module: 0, 87 | Buffer: 0, 88 | clearImmediate: 0, 89 | setImmediate: 0 90 | }, 91 | } 92 | 93 | var webpackMerge = require('webpack-merge'); 94 | module.exports = webpackMerge(defaultConfig, webpackConfig); 95 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/point.component.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • 3 |
    4 |

    5 | 6 | {{method}} 7 | 8 | 9 | {{apiName}} 10 | 11 |
    12 | {{summary}} 13 |
    14 |

    15 |
    16 |
    17 |

    Response Class (Status 200)

    18 |
    19 |

    OK

    20 |
    21 |

    22 | 23 |

    24 | 37 |
    38 |
    39 |
    40 | 41 |
    42 |
    43 | 44 |
    45 |
    46 |
    47 |
    48 | 49 | 50 |

    51 |
    52 |
    53 |

    Request Parameters

    54 | 55 |
    56 |
    57 |
  • 58 |
-------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/js/pageInit.js: -------------------------------------------------------------------------------- 1 | window.extension = window.extension || { 2 | sendRequest : function (o, f) { 3 | config.mode = ''; 4 | f({}); 5 | } 6 | }; 7 | 8 | 9 | 10 | //chrome.extension.sendRequest({cmd:'getIni'}, (function () { 11 | setTimeout(function() { 12 | 13 | JH.request({}).create(null, 'getIni', {succeed : function (oResp) { 14 | 15 | 16 | var _pub_static = function () {var _pri = {}, _pub = {}; 17 | var _init = function (oIni) { 18 | JH.md.jsonH.language = oIni.lang; 19 | JH.md.jsonH.oIni = oIni; 20 | _pri.oIni = oIni; 21 | if(config.mode === 'request') { 22 | var jsonH_Request = JH.request(_pub); 23 | var getJsonStringRequest = jsonH_Request.create(JH.request.NS.jsonH, 'getJsonString', {succeed : function (oResponseData, oRequestData) { 24 | 25 | //try{ 26 | _pri.startJsonH(oResponseData.data); 27 | //} 28 | //catch(e) { 29 | //_pri.jsonH_error(oResponseData.data); 30 | //} 31 | }}); 32 | try{ 33 | getJsonStringRequest.send('first view'); 34 | }catch(e) { 35 | _pri.startJsonH(); 36 | } 37 | 38 | }else if(config.mode === 'script_string') { 39 | _pri.startJsonH(script_JsonString); 40 | }else if(config.mode === 'dom') { 41 | _pri.startJsonH($('#jsonData').html()); 42 | }else{ 43 | _pri.startJsonH(); 44 | } 45 | 46 | }; 47 | 48 | _pri["startJsonH"] = function (sJson) { 49 | var oJH = JH.md.jsonH(sJson); 50 | //JH.e('#enterValue').select(); 51 | 52 | if(_pri.oIni) { 53 | JH.e('#showValueInNav').checked = _pri.oIni.showValue === undefined ? true : _pri.oIni.showValue; 54 | oJH.checkShowValueInNav(JH.e('#showValueInNav')); 55 | 56 | JH.e('#showImg').checked = _pri.oIni.showImg; 57 | oJH.checkShowImg(JH.e('#showImg')); 58 | 59 | JH.e('#showArrLeng').checked = _pri.oIni.showArrLeng; 60 | oJH.checkShowArrLeng(JH.e('#showArrLeng')); 61 | 62 | JH.e('#showIco').checked = _pri.oIni.showIco; 63 | oJH.checkShowIco(JH.e('#showIco')); 64 | 65 | JH.e('#icoAsFolder').checked = _pri.oIni.showStyle == 'folder'; 66 | oJH.checkIcoAsFolderBtn(JH.e('#icoAsFolder')); 67 | 68 | if(_pri.oIni.holdPanel) { 69 | oJH.showPanel(true); 70 | }else{ 71 | oJH.hidePanel(true); 72 | } 73 | } 74 | //showValueInNav 75 | //showIco 76 | //icoAsFolder 77 | //showValue : Application.prefs.getValue('extensions.jsonhandle.showValue', true), 78 | //showIco : Application.prefs.getValue('extensions.jsonhandle.showIco', false), 79 | //showStyle : Application.prefs.getValue('extensions.jsonhandle.showStyle', '') 80 | //"checkShowIco" : function (elm) { 81 | //"checkShowValueInNav" : function (elm) { 82 | //"checkIcoAsFolderBtn" : function (elm) {//debugger; 83 | }; 84 | 85 | _pri["jsonH_error"] = function (sJson) { 86 | alert(sJson); 87 | }; 88 | 89 | 90 | _init.apply(_pub, arguments); 91 | return _pub; 92 | }; 93 | 94 | 95 | 96 | return _pub_static(oResp.data); 97 | 98 | }}).send(); 99 | }); 100 | 101 | 102 | 103 | 104 | //}())); 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /ApiHelp.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26228.4 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C4851D21-C387-4949-A1A6-4B1BA179D618}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B966E54D-79A8-4EB3-8133-BA818679C54B}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ApiHelp", "src\Microsoft.AspNetCore.ApiHelp\Microsoft.AspNetCore.ApiHelp.csproj", "{24A863A4-6640-4E5F-86E4-B43225CBDB66}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ApiHelp.Core", "src\Microsoft.AspNetCore.ApiHelp.Core\Microsoft.AspNetCore.ApiHelp.Core.csproj", "{AE7B37D5-2EBC-4547-9A7E-27C224ABA4D2}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.ApiHelp.Core.Test", "test\Microsoft.AspNetCore.ApiHelp.Core.Test\Microsoft.AspNetCore.ApiHelp.Core.Test.csproj", "{A992ECB8-E793-43BA-9556-12A60112854E}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Host", "src\Host\Host.csproj", "{98D78B69-8D65-4F3A-A92E-99985AE7C4B0}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {24A863A4-6640-4E5F-86E4-B43225CBDB66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {24A863A4-6640-4E5F-86E4-B43225CBDB66}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {24A863A4-6640-4E5F-86E4-B43225CBDB66}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {24A863A4-6640-4E5F-86E4-B43225CBDB66}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {AE7B37D5-2EBC-4547-9A7E-27C224ABA4D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {AE7B37D5-2EBC-4547-9A7E-27C224ABA4D2}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {AE7B37D5-2EBC-4547-9A7E-27C224ABA4D2}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {AE7B37D5-2EBC-4547-9A7E-27C224ABA4D2}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {A992ECB8-E793-43BA-9556-12A60112854E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {A992ECB8-E793-43BA-9556-12A60112854E}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {A992ECB8-E793-43BA-9556-12A60112854E}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {A992ECB8-E793-43BA-9556-12A60112854E}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {98D78B69-8D65-4F3A-A92E-99985AE7C4B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {98D78B69-8D65-4F3A-A92E-99985AE7C4B0}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {98D78B69-8D65-4F3A-A92E-99985AE7C4B0}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {98D78B69-8D65-4F3A-A92E-99985AE7C4B0}.Release|Any CPU.Build.0 = Release|Any CPU 40 | EndGlobalSection 41 | GlobalSection(SolutionProperties) = preSolution 42 | HideSolutionNode = FALSE 43 | EndGlobalSection 44 | GlobalSection(NestedProjects) = preSolution 45 | {24A863A4-6640-4E5F-86E4-B43225CBDB66} = {C4851D21-C387-4949-A1A6-4B1BA179D618} 46 | {AE7B37D5-2EBC-4547-9A7E-27C224ABA4D2} = {C4851D21-C387-4949-A1A6-4B1BA179D618} 47 | {A992ECB8-E793-43BA-9556-12A60112854E} = {B966E54D-79A8-4EB3-8133-BA818679C54B} 48 | {98D78B69-8D65-4F3A-A92E-99985AE7C4B0} = {C4851D21-C387-4949-A1A6-4B1BA179D618} 49 | EndGlobalSection 50 | EndGlobal 51 | -------------------------------------------------------------------------------- /test/Microsoft.AspNetCore.ApiHelp.Core.Test/TypeJsonExtensionsTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using Xunit; 5 | 6 | namespace Microsoft.AspNetCore.ApiHelp.Core.Test { 7 | public interface IPagedList { 8 | int PageIndex { get; } 9 | int PageSize { get; } 10 | int TotalCount { get; } 11 | int TotalPages { get; } 12 | IList Items { get; } 13 | } 14 | 15 | public interface NestedGeneric { 16 | int TotalCount { get; } 17 | int TotalPages { get; } 18 | IList Items { get; } 19 | IPagedList PagedList { get; set; } 20 | } 21 | 22 | public class User { 23 | public string UserName { get; set; } 24 | public string Password { get; set; } 25 | } 26 | 27 | public class Agenda { 28 | /// 29 | /// Gets or sets the template identifier. 30 | /// 31 | /// The template identifier. 32 | public int TemplateId { get; set; } 33 | /// 34 | /// Gets or sets the users. 35 | /// 36 | /// The users. 37 | public IList Users { get; set; } 38 | /// 39 | /// Gets or sets the items. 40 | /// 41 | /// The items. 42 | public IList Items { get; set; } 43 | } 44 | 45 | public enum Gender { 46 | Unknown, 47 | Male, 48 | Female, 49 | } 50 | 51 | public class TypeJsonExtensionsTest { 52 | [Fact] 53 | public void GenericType_Scaffold_Test() { 54 | var type = typeof(IPagedList); 55 | var json = type.Scaffold(); 56 | 57 | var expected = File.ReadAllText(".\\Scaffold.json"); 58 | 59 | Assert.Equal(expected, json.ToString()); 60 | } 61 | 62 | [Fact] 63 | public void GenericType_Schema_Test() { 64 | var type = typeof(IPagedList); 65 | var json = type.Schema(); 66 | 67 | var expected = File.ReadAllText(".\\Schema.json"); 68 | 69 | Assert.Equal(expected, json.ToString()); 70 | } 71 | 72 | [Fact] 73 | public void Nested_GenericType_Scaffold_Test() { 74 | var type = typeof(NestedGeneric); 75 | var json = type.Scaffold(); 76 | 77 | var expected = File.ReadAllText(".\\NestedScaffold.json"); 78 | 79 | Assert.Equal(expected, json.ToString()); 80 | } 81 | 82 | [Fact] 83 | public void Nested_GenericType_Schema_Test() { 84 | var type = typeof(NestedGeneric); 85 | var json = type.Schema(); 86 | 87 | var expected = File.ReadAllText(".\\NestedSchema.json"); 88 | 89 | Assert.Equal(expected, json.ToString()); 90 | } 91 | 92 | [Fact] 93 | public void Class_TimeSpan_Prop_Schema_Default_Value_Test() { 94 | var type = typeof(Agenda); 95 | var json = type.Schema(); 96 | 97 | var expected = File.ReadAllText(".\\TimeSpan.json"); 98 | 99 | Assert.Equal(expected, json.ToString()); 100 | } 101 | 102 | [Fact] 103 | public void Enum_Schema_Default_Value_Test() { 104 | var type = typeof(Gender); 105 | var json = type.Schema(); 106 | 107 | Assert.Equal(0, json); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/dist/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */ 2 | html, 3 | body, 4 | div, 5 | span, 6 | applet, 7 | object, 8 | iframe, 9 | h1, 10 | h2, 11 | h3, 12 | h4, 13 | h5, 14 | h6, 15 | p, 16 | blockquote, 17 | pre, 18 | a, 19 | abbr, 20 | acronym, 21 | address, 22 | big, 23 | cite, 24 | code, 25 | del, 26 | dfn, 27 | em, 28 | img, 29 | ins, 30 | kbd, 31 | q, 32 | s, 33 | samp, 34 | small, 35 | strike, 36 | strong, 37 | sub, 38 | sup, 39 | tt, 40 | var, 41 | b, 42 | u, 43 | i, 44 | center, 45 | dl, 46 | dt, 47 | dd, 48 | ol, 49 | ul, 50 | li, 51 | fieldset, 52 | form, 53 | label, 54 | legend, 55 | table, 56 | caption, 57 | tbody, 58 | tfoot, 59 | thead, 60 | tr, 61 | th, 62 | td, 63 | article, 64 | aside, 65 | canvas, 66 | details, 67 | embed, 68 | figure, 69 | figcaption, 70 | footer, 71 | header, 72 | hgroup, 73 | menu, 74 | nav, 75 | output, 76 | ruby, 77 | section, 78 | summary, 79 | time, 80 | mark, 81 | audio, 82 | video { 83 | margin: 0; 84 | padding: 0; 85 | border: 0; 86 | font-size: 100%; 87 | font: inherit; 88 | vertical-align: baseline; 89 | } 90 | /* HTML5 display-role reset for older browsers */ 91 | article, 92 | aside, 93 | details, 94 | figcaption, 95 | figure, 96 | footer, 97 | header, 98 | hgroup, 99 | menu, 100 | nav, 101 | section { 102 | display: block; 103 | } 104 | 105 | body { 106 | line-height: 1; 107 | } 108 | 109 | ol, 110 | ul { 111 | list-style: none; 112 | } 113 | 114 | blockquote, 115 | q { 116 | quotes: none; 117 | } 118 | 119 | blockquote:before, 120 | blockquote:after, 121 | q:before, 122 | q:after { 123 | content: ''; 124 | content: none; 125 | } 126 | 127 | table { 128 | border-collapse: collapse; 129 | border-spacing: 0; 130 | } 131 | 132 | 133 | @charset "utf-8"; 134 | /* CSS Document */ 135 | div.ControlsRow, div.HeadersRow { 136 | font-family: Georgia; 137 | } 138 | 139 | div.Canvas { 140 | font-family: Lucida Console, Georgia; 141 | font-size: 13px; 142 | background-color: #ECECEC; 143 | color: #000000; 144 | border: solid 1px #CECECE; 145 | } 146 | 147 | .ObjectBrace { 148 | color: #00AA00; 149 | font-weight: bold; 150 | } 151 | 152 | .ArrayBrace { 153 | color: #0033FF; 154 | font-weight: bold; 155 | } 156 | 157 | .PropertyName { 158 | color: #CC0000; 159 | font-weight: bold; 160 | } 161 | 162 | .String { 163 | color: #007777; 164 | } 165 | 166 | .Number { 167 | color: #AA00AA; 168 | } 169 | 170 | .Boolean { 171 | color: #0000FF; 172 | } 173 | 174 | .Function { 175 | color: #AA6633; 176 | text-decoration: italic; 177 | } 178 | 179 | .Null { 180 | color: #0000FF; 181 | } 182 | 183 | .Comma { 184 | color: #000000; 185 | font-weight: bold; 186 | } 187 | 188 | PRE.CodeContainer { 189 | margin-top: 0px; 190 | margin-bottom: 0px; 191 | } 192 | 193 | PRE.CodeContainer img { 194 | cursor: pointer; 195 | border: none; 196 | margin-bottom: -1px; 197 | } 198 | 199 | #CollapsibleViewDetail a { 200 | padding-left: 10px; 201 | } 202 | 203 | #ControlsRow { 204 | white-space: nowrap; 205 | font: 11px Georgia; 206 | } 207 | 208 | #TabSizeHolder { 209 | padding-left: 10px; 210 | padding-right: 10px; 211 | } 212 | 213 | #HeaderTitle { 214 | text-align: right; 215 | font-size: 11px; 216 | } 217 | 218 | #HeaderSubTitle { 219 | margin-bottom: 2px; 220 | margin-top: 0px; 221 | } 222 | 223 | #RawJson { 224 | width: 99%; 225 | height: 120px; 226 | } 227 | 228 | A.OtherToolsLink { 229 | color: #555; 230 | text-decoration: none; 231 | } 232 | 233 | A.OtherToolsLink:hover { 234 | text-decoration: underline; 235 | } 236 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */ 2 | html, 3 | body, 4 | div, 5 | span, 6 | applet, 7 | object, 8 | iframe, 9 | h1, 10 | h2, 11 | h3, 12 | h4, 13 | h5, 14 | h6, 15 | p, 16 | blockquote, 17 | pre, 18 | a, 19 | abbr, 20 | acronym, 21 | address, 22 | big, 23 | cite, 24 | code, 25 | del, 26 | dfn, 27 | em, 28 | img, 29 | ins, 30 | kbd, 31 | q, 32 | s, 33 | samp, 34 | small, 35 | strike, 36 | strong, 37 | sub, 38 | sup, 39 | tt, 40 | var, 41 | b, 42 | u, 43 | i, 44 | center, 45 | dl, 46 | dt, 47 | dd, 48 | ol, 49 | ul, 50 | li, 51 | fieldset, 52 | form, 53 | label, 54 | legend, 55 | table, 56 | caption, 57 | tbody, 58 | tfoot, 59 | thead, 60 | tr, 61 | th, 62 | td, 63 | article, 64 | aside, 65 | canvas, 66 | details, 67 | embed, 68 | figure, 69 | figcaption, 70 | footer, 71 | header, 72 | hgroup, 73 | menu, 74 | nav, 75 | output, 76 | ruby, 77 | section, 78 | summary, 79 | time, 80 | mark, 81 | audio, 82 | video { 83 | margin: 0; 84 | padding: 0; 85 | border: 0; 86 | font-size: 100%; 87 | font: inherit; 88 | vertical-align: baseline; 89 | } 90 | /* HTML5 display-role reset for older browsers */ 91 | article, 92 | aside, 93 | details, 94 | figcaption, 95 | figure, 96 | footer, 97 | header, 98 | hgroup, 99 | menu, 100 | nav, 101 | section { 102 | display: block; 103 | } 104 | 105 | body { 106 | line-height: 1; 107 | } 108 | 109 | ol, 110 | ul { 111 | list-style: none; 112 | } 113 | 114 | blockquote, 115 | q { 116 | quotes: none; 117 | } 118 | 119 | blockquote:before, 120 | blockquote:after, 121 | q:before, 122 | q:after { 123 | content: ''; 124 | content: none; 125 | } 126 | 127 | table { 128 | border-collapse: collapse; 129 | border-spacing: 0; 130 | } 131 | 132 | 133 | @charset "utf-8"; 134 | /* CSS Document */ 135 | div.ControlsRow, div.HeadersRow { 136 | font-family: Georgia; 137 | } 138 | 139 | div.Canvas { 140 | font-family: Lucida Console, Georgia; 141 | font-size: 13px; 142 | background-color: #ECECEC; 143 | color: #000000; 144 | border: solid 1px #CECECE; 145 | } 146 | 147 | .ObjectBrace { 148 | color: #00AA00; 149 | font-weight: bold; 150 | } 151 | 152 | .ArrayBrace { 153 | color: #0033FF; 154 | font-weight: bold; 155 | } 156 | 157 | .PropertyName { 158 | color: #CC0000; 159 | font-weight: bold; 160 | } 161 | 162 | .String { 163 | color: #007777; 164 | } 165 | 166 | .Number { 167 | color: #AA00AA; 168 | } 169 | 170 | .Boolean { 171 | color: #0000FF; 172 | } 173 | 174 | .Function { 175 | color: #AA6633; 176 | text-decoration: italic; 177 | } 178 | 179 | .Null { 180 | color: #0000FF; 181 | } 182 | 183 | .Comma { 184 | color: #000000; 185 | font-weight: bold; 186 | } 187 | 188 | PRE.CodeContainer { 189 | margin-top: 0px; 190 | margin-bottom: 0px; 191 | } 192 | 193 | PRE.CodeContainer img { 194 | cursor: pointer; 195 | border: none; 196 | margin-bottom: -1px; 197 | } 198 | 199 | #CollapsibleViewDetail a { 200 | padding-left: 10px; 201 | } 202 | 203 | #ControlsRow { 204 | white-space: nowrap; 205 | font: 11px Georgia; 206 | } 207 | 208 | #TabSizeHolder { 209 | padding-left: 10px; 210 | padding-right: 10px; 211 | } 212 | 213 | #HeaderTitle { 214 | text-align: right; 215 | font-size: 11px; 216 | } 217 | 218 | #HeaderSubTitle { 219 | margin-bottom: 2px; 220 | margin-top: 0px; 221 | } 222 | 223 | #RawJson { 224 | width: 99%; 225 | height: 120px; 226 | } 227 | 228 | A.OtherToolsLink { 229 | color: #555; 230 | text-decoration: none; 231 | } 232 | 233 | A.OtherToolsLink:hover { 234 | text-decoration: underline; 235 | } 236 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/ClosedGenericMatcher.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using System.Reflection; 5 | 6 | namespace Microsoft.AspNetCore.ApiHelp.Core { 7 | /// 8 | /// Helper related to generic interface definitions and implementing classes. 9 | /// 10 | internal static class ClosedGenericMatcher { 11 | /// 12 | /// Determine whether is or implements a closed generic 13 | /// created from . 14 | /// 15 | /// The of interest. 16 | /// The open generic to match. Usually an interface. 17 | /// 18 | /// The closed generic created from that 19 | /// is or implements. null if the two s have no such 20 | /// relationship. 21 | /// 22 | /// 23 | /// This method will return if is 24 | /// typeof(KeyValuePair{,}), and is 25 | /// typeof(KeyValuePair{string, object}). 26 | /// 27 | public static Type ExtractGenericInterface(Type queryType, Type interfaceType) { 28 | if (queryType == null) { 29 | throw new ArgumentNullException(nameof(queryType)); 30 | } 31 | 32 | if (interfaceType == null) { 33 | throw new ArgumentNullException(nameof(interfaceType)); 34 | } 35 | 36 | if (IsGenericInstantiation(queryType, interfaceType)) { 37 | // queryType matches (i.e. is a closed generic type created from) the open generic type. 38 | return queryType; 39 | } 40 | 41 | // Otherwise check all interfaces the type implements for a match. 42 | // - If multiple different generic instantiations exists, we want the most derived one. 43 | // - If that doesn't break the tie, then we sort alphabetically so that it's deterministic. 44 | // 45 | // We do this by looking at interfaces on the type, and recursing to the base type 46 | // if we don't find any matches. 47 | return GetGenericInstantiation(queryType, interfaceType); 48 | } 49 | 50 | private static bool IsGenericInstantiation(Type candidate, Type interfaceType) => candidate.GetTypeInfo().IsGenericType && candidate.GetGenericTypeDefinition() == interfaceType; 51 | 52 | private static Type GetGenericInstantiation(Type queryType, Type interfaceType) { 53 | Type bestMatch = null; 54 | var interfaces = queryType.GetInterfaces(); 55 | foreach (var @interface in interfaces) { 56 | if (IsGenericInstantiation(@interface, interfaceType)) { 57 | if (bestMatch == null) { 58 | bestMatch = @interface; 59 | } 60 | else if (StringComparer.Ordinal.Compare(@interface.FullName, bestMatch.FullName) < 0) { 61 | bestMatch = @interface; 62 | } 63 | else { 64 | // There are two matches at this level of the class hierarchy, but @interface is after 65 | // bestMatch in the sort order. 66 | } 67 | } 68 | } 69 | 70 | if (bestMatch != null) { 71 | return bestMatch; 72 | } 73 | 74 | // BaseType will be null for object and interfaces, which means we've reached 'bottom'. 75 | var baseType = queryType?.GetTypeInfo().BaseType; 76 | if (baseType == null) { 77 | return null; 78 | } 79 | else { 80 | return GetGenericInstantiation(baseType, interfaceType); 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/TypeSharedExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using System.Linq; 5 | using System.Collections.Generic; 6 | using System.Reflection; 7 | using System.Collections; 8 | 9 | namespace Microsoft.AspNetCore.ApiHelp.Core { 10 | /// 11 | /// The extension methods for . 12 | /// 13 | internal static class TypeSharedExtensions { 14 | public static bool IsCollectionType(this Type type) => (type.GetInterfaces().Any(t => t == typeof(IEnumerable))); 15 | 16 | public static bool IsNullableType(this Type type) { 17 | var typeInfo = type.GetTypeInfo(); 18 | 19 | return !typeInfo.IsValueType 20 | || (typeInfo.IsGenericType 21 | && (typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))); 22 | } 23 | 24 | /// 25 | /// Gets the unwrap nullalble type if the the is nullable type or the type self. 26 | /// 27 | /// 28 | /// 29 | public static Type UnwrapNullableType(this Type type) => Nullable.GetUnderlyingType(type) ?? type; 30 | 31 | /// 32 | /// Determines the specified type is primitive type. 33 | /// 34 | /// 35 | /// 36 | public static bool IsPrimitive(this Type type) => type.IsInteger() || type.IsNonIntegerPrimitive(); 37 | 38 | /// 39 | /// Determines the specified type is integer type. 40 | /// 41 | /// 42 | /// 43 | public static bool IsInteger(this Type type) { 44 | type = type.UnwrapNullableType(); 45 | 46 | return (type == typeof(int)) 47 | || (type == typeof(long)) 48 | || (type == typeof(short)) 49 | || (type == typeof(byte)) 50 | || (type == typeof(uint)) 51 | || (type == typeof(ulong)) 52 | || (type == typeof(ushort)) 53 | || (type == typeof(sbyte)) 54 | || (type == typeof(char)); 55 | } 56 | 57 | public static object GetDefaultValue(this Type type) { 58 | if (!type.GetTypeInfo().IsValueType) { 59 | return null; 60 | } 61 | 62 | // A bit of perf code to avoid calling Activator.CreateInstance for common types and 63 | // to avoid boxing on every call. This is about 50% faster than just calling CreateInstance 64 | // for all value types. 65 | object value; 66 | return _commonTypeDictionary.TryGetValue(type, out value) 67 | ? value 68 | : Activator.CreateInstance(type); 69 | } 70 | 71 | private static bool IsNonIntegerPrimitive(this Type type) { 72 | type = type.UnwrapNullableType(); 73 | 74 | return (type == typeof(bool)) 75 | || (type == typeof(byte[])) 76 | || (type == typeof(DateTime)) 77 | || (type == typeof(TimeSpan)) 78 | || (type == typeof(DateTimeOffset)) 79 | || (type == typeof(decimal)) 80 | || (type == typeof(double)) 81 | || (type == typeof(float)) 82 | || (type == typeof(Guid)) 83 | || (type == typeof(string)) 84 | || type.GetTypeInfo().IsEnum; 85 | } 86 | 87 | private static readonly Dictionary _commonTypeDictionary = new Dictionary 88 | { 89 | { typeof(Guid), default(Guid) }, 90 | { typeof(TimeSpan), default(TimeSpan) }, 91 | { typeof(DateTime), default(DateTime) }, 92 | { typeof(DateTimeOffset), default(DateTimeOffset) }, 93 | { typeof(char), default(char) }, 94 | { typeof(int), default(int) }, 95 | { typeof(uint), default(uint) }, 96 | { typeof(long), default(long) }, 97 | { typeof(ulong), default(ulong) }, 98 | { typeof(short), default(short) }, 99 | { typeof(ushort), default(ushort) }, 100 | { typeof(byte), default(byte) }, 101 | { typeof(sbyte), default(sbyte) }, 102 | { typeof(bool), default(bool) }, 103 | { typeof(double), default(double) }, 104 | { typeof(float), default(float) }, 105 | }; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/resource/point/point.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | import { PointService } from './point.service'; 4 | import { ModelSchemaComponent } from './schema/model-schema.component'; 5 | import { RequestComponent } from './request/request.component'; 6 | import { JsonHandleComponent } from '../../jsonHandle/json-handle.component'; 7 | import { ContentTypeComponent } from './content-type/content-type.component'; 8 | 9 | import { PointModel, Response, ModelResponse, DataModel } from './pointModel'; 10 | import { MethodEnum } from './method.enum'; 11 | @Component({ 12 | moduleId: module.id, 13 | selector: 'point', 14 | templateUrl: 'point.component.html', 15 | styleUrls: ['point.component.css'], 16 | directives: [ModelSchemaComponent,RequestComponent,JsonHandleComponent,ContentTypeComponent], 17 | providers: [PointService] 18 | }) 19 | export class PointComponent implements OnInit { 20 | constructor(private pointService: PointService) { } 21 | 22 | modelType: number = 0; 23 | modelSelected: boolean = false; 24 | 25 | @Input() api: string; 26 | method: string; 27 | titleClass: string; 28 | apiName: string; 29 | open1: boolean; 30 | @Input() summary:string; 31 | response: Response; 32 | Data: Response; 33 | Schema: Response; 34 | SupportedMediaType:any; 35 | request:any; 36 | 37 | enum:MethodEnum; 38 | point: PointModel; 39 | ngOnInit() { 40 | this.open1 = false; 41 | this.bindData(); 42 | } 43 | selectTab(i: number) { 44 | this.modelType = i; 45 | if (i == 0) { 46 | this.modelSelected = true; 47 | } else { 48 | this.modelSelected = false; 49 | } 50 | } 51 | 52 | 53 | bindData() { 54 | var model = this.api.split(' '); 55 | this.titleClass = model[0].toLowerCase(); 56 | this.method = model[0]; 57 | this.apiName = model[1]; 58 | 59 | } 60 | 61 | Open() { 62 | this.open1 = !this.open1; 63 | var para = `RelativePath=${this.apiName}&HttpMethod=${this.method}`; 64 | this.enum = MethodEnum[this.method]; 65 | if (this.open1) { 66 | this.pointService.GetData(para).subscribe( 67 | data => this.bindModel(data) 68 | ); 69 | } 70 | } 71 | 72 | bindModel(data) { 73 | var point: PointModel = data[this.api]; 74 | 75 | // this.summary = point.Summary; 76 | //repose 77 | this.response = point.Response; 78 | 79 | var modelData = this.clone(this.response); 80 | delete modelData.Schema; 81 | delete modelData.SupportedMediaType; 82 | this.Data = modelData; 83 | 84 | var schemaData = this.clone(this.response); 85 | delete schemaData.Scaffold; 86 | delete schemaData.SupportedMediaType 87 | this.Schema = schemaData; 88 | 89 | this.SupportedMediaType = this.response.SupportedMediaType; 90 | 91 | //request 92 | this.request = point.Request; 93 | 94 | 95 | } 96 | 97 | 98 | 99 | 100 | jsonHandle(object) { 101 | var item = []; 102 | if (object instanceof Array) { 103 | for (var i = 0, len = object.length; i < len; i++) { 104 | if (typeof object[i] == object) 105 | this.jsonHandle(object[i]); 106 | else { 107 | item = object[i]; 108 | } 109 | } 110 | } else { 111 | if (typeof object == 'object') { 112 | if (object) { 113 | for (var key in object) { 114 | var name = key; 115 | var value = this.jsonHandle(object[key]); 116 | item.push({ name, value }); 117 | } 118 | } 119 | } else { 120 | item = object; 121 | } 122 | } 123 | return item; 124 | } 125 | 126 | clone(obj) { 127 | var o; 128 | switch (typeof obj) { 129 | case 'undefined': break; 130 | case 'string': o = obj + ''; break; 131 | case 'number': o = obj - 0; break; 132 | case 'boolean': o = obj; break; 133 | case 'object': 134 | if (obj === null) { 135 | o = null; 136 | } else { 137 | if (obj instanceof Array) { 138 | o = []; 139 | for (var i = 0, len = obj.length; i < len; i++) { 140 | o.push(this.clone(obj[i])); 141 | } 142 | } else { 143 | o = {}; 144 | for (var k in obj) { 145 | o[k] = this.clone(obj[k]); 146 | } 147 | } 148 | } 149 | break; 150 | default: 151 | o = obj; break; 152 | } 153 | return o; 154 | } 155 | 156 | 157 | test(){ 158 | console.log(this.response.SupportedMediaType); 159 | } 160 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %(Title) 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
31 | 32 |
33 |
34 | Path:
35 | Key: : 36 | 37 | 38 | 39 |
40 | 41 |
42 |
43 |
44 | Link 45 | 46 | 47 | 48 |
49 | 50 | 51 | 52 | 53 | 54 |

55 | 56 | 57 | 58 | 59 | 60 |
61 | 62 |
63 |
64 |
65 | 66 | 67 |
68 |
69 |
70 | loading... 71 |
72 | 88 | 89 | 90 |
91 | 92 | 93 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/js/jsonH/nav.js: -------------------------------------------------------------------------------- 1 | 2 | JH.mod.add(['treeNav'], 'jsonH.nav', function (modName, JH, $$) { 3 | 4 | var _interface = []; 5 | 6 | 7 | 8 | 9 | 10 | var _pri_static = { 11 | 12 | }; 13 | 14 | 15 | 16 | var _pro_static = { 17 | 18 | }; 19 | 20 | 21 | var _pub_static = function (opts) { 22 | var _main, _this = this, _args = arguments, _pri = {}, _pro = {}, _pub = {__varyContext_:function (pro, pub) {_pro = pro;_pub = pub;}}, _mod, _base, _parent; 23 | _base =$$.treeNav; 24 | 25 | 26 | _main = function () { 27 | 28 | _mod = JH.mod.init(_pub_static, _this, _pro, _pub, _pro_static, _interface, _base, _args); 29 | _pro = _mod.pro; 30 | _pub = _mod.pub; 31 | _parent = _mod.parent; 32 | 33 | 34 | 35 | 36 | }; 37 | 38 | 39 | JH.mergePropertyFrom(_pri, { 40 | 41 | 42 | "encodeToXMLchar" : function (sValue) { 43 | return sValue.replace(/\&/g,'&').replace(/\/g,'>').replace(/\"/g,'"'); 44 | }, 45 | "parsePathByElm" : function (eBlock) { 46 | var aPath = [eBlock]; 47 | $(eBlock).parents('.elmBlock').each(function (sKey, eB) { 48 | aPath.push(eB); 49 | }); 50 | 51 | var sPath = ''; 52 | aPath = aPath.reverse(); 53 | var aPathObj = []; 54 | JH.forEach(aPath, function (o, i) {//debugger; 55 | var sKey = o.sKeyName + ''; 56 | if(sKey.match(/^[a-zA-Z_]\w*$/)) { 57 | 58 | aPathObj.push({type:'point', value:sKey}); 59 | }else if(sKey.match(/^\d+$/)) { 60 | 61 | aPathObj.push({type:'bracketNumber', value:sKey}); 62 | }else{ 63 | 64 | aPathObj.push({type:'bracket', value:sKey}); 65 | } 66 | }); 67 | var mergePath = function (aPathObj) { 68 | var sPath = ''; 69 | JH.forEach(aPathObj, function (o) { 70 | if(o.type === 'point') { 71 | sPath += '.' + o.value; 72 | }else if(o.type === 'bracketNumber') { 73 | sPath += '[' + o.value + ']'; 74 | }else{ 75 | sPath += '["' + o.value + '"]'; 76 | } 77 | }); 78 | return sPath; 79 | }; 80 | var sPath = mergePath(aPathObj).slice(1); 81 | aPathObj.pop(); 82 | return { 83 | sParent : mergePath(aPathObj).slice(1), 84 | toString : function () { 85 | return sPath; 86 | } 87 | }; 88 | }, 89 | "filterStringValue" : function (sTxt) { 90 | //sTxt = sTxt.replace(/\\n/g, '\n').replace(/\\r/g, '').replace(/\\t/g, '\t'); 91 | if(sTxt.match(/(http|https):\/\/.+/)) { 92 | _pri.showLink(sTxt); 93 | } 94 | return '"' + sTxt + '"'; 95 | }, 96 | "showLink" : function (sLink) { 97 | $('#showLink').attr('href', sLink).show(); 98 | }, 99 | "hideLink" : function () { 100 | $('#showLink').hide().attr(''); 101 | } 102 | 103 | 104 | }); 105 | 106 | JH.mergePropertyFrom(_pro, { 107 | 108 | 109 | "icoConfig" : { 110 | 'array' : { 111 | className : 'open folder array', 112 | icoName : 'arr.png' 113 | }, 114 | 'number' : { 115 | className : 'node number', 116 | icoName : 'num.png' 117 | }, 118 | 'string' : { 119 | className : 'node string', 120 | icoName : 'str.png' 121 | }, 122 | 'boolean' : { 123 | className : 'node boolean', 124 | icoName : 'boolean.png' 125 | }, 126 | 'null' : { 127 | className : 'node null', 128 | icoName : 'null.png' 129 | }, 130 | 'object' : { 131 | className : 'open folder object', 132 | icoName : 'obj.png' 133 | } 134 | }, 135 | "clickElmCallback" : function (eBlock) { 136 | 137 | 138 | var oPath = _pri.parsePathByElm(eBlock); 139 | $('#showPath').val(oPath); 140 | $('#showPath').attr('parentPath', oPath.sParent); 141 | 142 | _pri.hideLink(); 143 | 144 | var sTxt ; 145 | if(typeof eBlock.oData === 'string') { 146 | sTxt = _pri.filterStringValue(eBlock.oData); 147 | }else{ 148 | sTxt = _pub.JSON.stringify(eBlock.oData, null, 4); 149 | } 150 | $('#showValue') 151 | .val(sTxt) 152 | .prop('oData', eBlock.oData) 153 | ; 154 | $('#showKey').val(eBlock.sKeyName); 155 | $('#showKey').attr('oldValue', eBlock.sKeyName); 156 | var parentElm = $(eBlock).parents('.elmBlock');//debugger; 157 | if(parentElm.length && parentElm[0].sType === 'array') { 158 | $('#showKey').attr('readonly', 'readonly'); 159 | $('#showKey').addClass('isArrayElm'); 160 | }else{ 161 | //$('#showKey').removeAttr('readonly'); 162 | $('#showKey').attr('readonly', 'readonly'); 163 | $('#showKey').removeClass('isArrayElm'); 164 | } 165 | 166 | }, 167 | "overElmCallback" : function (eBlock) { 168 | $('#pathTips').html(_pri.parsePathByElm(eBlock)+''); 169 | 170 | 171 | }, 172 | "outElmCallback" : function (eBlock) { 173 | $('#pathTips').html(''); 174 | 175 | 176 | }, 177 | "drawElmCallback" : function (eBlock) { 178 | _parent._pro.drawElmCallback(eBlock); 179 | //var sV = _pub.JSON.stringify(eBlock.oData); 180 | //var sImg = '', sHasImgClass = ''; 181 | //if($(eBlock).hasClass('node')) { 182 | //$('.elmSpan', eBlock).append('' + _pri.encodeToXMLchar(sV) + sImg +''); 183 | //} 184 | } 185 | 186 | 187 | }); 188 | 189 | JH.mergePropertyFrom(_pub, { 190 | 191 | "getData" : function () { 192 | return _pro.data; 193 | }, 194 | "destroy" : function(){ 195 | if(_pub) { 196 | 197 | _pri = _pro = _pub = null; 198 | } 199 | } 200 | 201 | }); 202 | 203 | 204 | _main(); 205 | 206 | 207 | return _pub; 208 | 209 | }; 210 | 211 | return JH.mergePropertyFrom(_pub_static, { 212 | 213 | 214 | 215 | }); 216 | }); -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/js/lang.js: -------------------------------------------------------------------------------- 1 | 2 | JH.mod.add([], 'lang', function (sModName, JH) { 3 | var _pri_s = {}; 4 | _pri_s["data"] = { 5 | 'zh-cn' : { 6 | 'title_1' : '路径:', 7 | 'title_2' : '键:', 8 | 'title_3' : '链接', 9 | 'title_4' : '自动渲染JSON文件', 10 | 'title_5' : '打开时显示面板', 11 | 'title_6' : '图片展示的模式', 12 | 'title_7' : '直接展示所有', 13 | 'title_8' : '鼠标悬浮时', 14 | 'title_9' : '点击JH的打开方式', 15 | 'title_10' : '设置', 16 | 'title_11' : '关于JH里边的广告', 17 | 'title_12' : '成员数量展示模式', 18 | 'title_13' : '仅数组', 19 | 'title_14' : '数组与对象', 20 | 'button_1' : '修改', 21 | 'button_2' : '-全部收起', 22 | 'button_3' : '展开到选中节点', 23 | 'button_4' : '+全部展开', 24 | 'button_5' : '\u21e6撤销', 25 | 'button_6' : '前进\u21e8', 26 | 'button_7' : '跳到选中节点', 27 | 'button_8' : '保存', 28 | 'button_9' : '复制', 29 | 'button_10' : '联系JH', 30 | 'label_1' : '显示值', 31 | 'label_2' : '显示图标', 32 | 'label_3' : '文件夹风格', 33 | 'label_4' : '自动展示图片', 34 | 'label_5' : '展示数组长度', 35 | 'msg_1' : '需要选择一个节点', 36 | 'msg_2' : 'JSON格式错误 : 输入的内容无法被解析 !', 37 | 'msg_3' : '请输入JSON字符串.....', 38 | 'msg_4' : 'JSON格式错误', 39 | 'msg_5' : function (key, iLine) { 40 | return '@第' + iLine + '行'; 41 | }, 42 | 'msg_6' : '复制成功!' 43 | , 'msg_8' : '当字符串值为图片URL时,展示图片' 44 | , 'msg_9' : '为什么会有广告?' 45 | , 'msg_10' : '给作者一点动力以持续地维护JSON-handle, 并且他希望在这儿推荐更多更好的工具和应用给大家。' 46 | , 'msg_11' : '?关于推广' 47 | }, 48 | 'zh-tw' : { 49 | 'title_1' : '路徑:', 50 | 'title_2' : '鍵:', 51 | 'title_3' : '鏈接', 52 | 'title_4' : '自動渲染JSON文檔', 53 | 'title_5' : '打開時顯示面板', 54 | 'title_6' : '圖片顯示的模式', 55 | 'title_7' : '直接顯示所有', 56 | 'title_8' : '滑鼠懸浮時', 57 | 'title_9' : '點擊JH的打開模式', 58 | 'title_10' : '設定', 59 | 'title_11' : '關於JH裡的廣告', 60 | 'title_12' : '成員數量顯示模式', 61 | 'title_13' : '僅陣列', 62 | 'title_14' : '陣列與物件', 63 | 'button_1' : '更改', 64 | 'button_2' : '-全部收起', 65 | 'button_3' : '展開到選中節點', 66 | 'button_4' : '+全部展開', 67 | 'button_5' : '\u21e6撤銷', 68 | 'button_6' : '前進\u21e8', 69 | 'button_7' : '跳到選中節點', 70 | 'button_8' : '存儲', 71 | 'button_9' : '複製', 72 | 'button_10' : '聯系JH', 73 | 'label_1' : '顯示值', 74 | 'label_2' : '顯示圖標', 75 | 'label_3' : '資料夾風格', 76 | 'label_4' : '展示圖片', 77 | 'label_5' : '展示數組長度', 78 | 'msg_1' : '需要選擇一個節點', 79 | 'msg_2' : 'JSON格式錯誤 : 輸入的內容無法被解析 !', 80 | 'msg_3' : '請輸入JSON字串.....', 81 | 'msg_4' : 'JSON格式錯誤', 82 | 'msg_5' : function (key, iLine) { 83 | return '@第' + iLine + '行'; 84 | }, 85 | 'msg_6' : '複製成功!' 86 | , 'msg_8' : '當字串值為圖片URL時,展示圖片' 87 | , 'msg_9' : '為什麼會有廣告?' 88 | , 'msg_10' : '給作者一點動力以持續地維護JSON-handle,並且他希望從這兒推薦更多更好的工具和程式給大家。.' 89 | , 'msg_11' : '?關於推廣' 90 | }, 91 | 'en' : { 92 | 'title_1' : 'Path:', 93 | 'title_2' : 'Key:', 94 | 'title_3' : 'Link', 95 | 'title_4' : 'Auto render JSON', 96 | 'title_5' : 'Show panel', 97 | 'title_6' : 'Show img mode', 98 | 'title_7' : 'Show all', 99 | 'title_8' : 'When hover', 100 | 'title_9' : 'Open JH mode', 101 | 'title_10' : 'Setting', 102 | 'title_11' : 'About Ad in JH', 103 | 'button_1' : 'modify', 104 | 'button_2' : '-collapse all', 105 | 'button_3' : 'expand node', 106 | 'button_4' : '+expand all', 107 | 'button_5' : '\u21e6undo', 108 | 'button_6' : 'redo\u21e8', 109 | 'button_7' : 'goto node', 110 | 'button_8' : 'save', 111 | 'button_9' : 'copy', 112 | 'button_10' : 'Contact JH', 113 | 'title_12' : 'Show array length mode', 114 | 'title_13' : 'Array only', 115 | 'title_14' : 'Array & Object', 116 | 'label_1' : 'show value', 117 | 'label_2' : 'show ico', 118 | 'label_3' : 'folder style', 119 | 'label_4' : 'show img', 120 | 'label_5' : 'show array leng', 121 | 'msg_1' : 'must select a node', 122 | 'msg_2' : 'JSON format error : Can\'t parse the input !', 123 | 'msg_3' : 'input JSON string.....', 124 | 'msg_4' : 'JSON format error', 125 | 'msg_5' : function (key, iLine) { 126 | return '@line ' + iLine; 127 | }, 128 | 'msg_6' : 'copied!' 129 | , 'msg_8' : 'When the value is string of image URL, show pictures automatically' 130 | , 'msg_9' : 'Why is there a Ad?' 131 | , 'msg_10' : 'A little power for author to support JSON-handle, & He hope recommend more great tools and application to all.' 132 | , 'msg_11' : '?About Ad' 133 | } 134 | }; 135 | var _pub_static = function () {var _pub = {}, _pri = {}, _pro = {}; 136 | var _init = function (sLang) { 137 | _pri.lang = sLang; 138 | 139 | }; 140 | 141 | _pri["lang"] = 'en'; 142 | 143 | _pub["switchLang"] = function (sLang) { 144 | _pri.lang = sLang; 145 | return _pub; 146 | }; 147 | 148 | _pub["setPage"] = function (sLang) { 149 | sLang = sLang || _pri.lang; 150 | JH.forIn(_pri_s.data[sLang], function (o, k) { 151 | $('.langID_' + k).html(_pub.getStr(k)); 152 | $('.langTitleID_' + k).attr('title', _pub.getStr(k)); 153 | $('.langValueID_' + k).attr('value', _pub.getStr(k)); 154 | }); 155 | $('.langID_data').each(function () { 156 | try{ 157 | var oLang = JSON.parse(this.getAttribute('data-lang')); 158 | this.langDef || (this.langDef = this.innerHTML); 159 | var sStr = this.langDef; 160 | if(oLang[sLang]) { 161 | sStr = oLang[sLang]; 162 | }else if(oLang.en) { 163 | sStr = oLang.en; 164 | } 165 | this.innerHTML = sStr; 166 | }catch(e) {} 167 | }); 168 | }; 169 | 170 | _pub["getStr"] = function (sKey) { 171 | var sKey = _pri_s.data[_pri.lang][sKey]; 172 | if(sKey.call) { 173 | return sKey.apply(sKey, arguments); 174 | }else{ 175 | return sKey; 176 | } 177 | }; 178 | 179 | _pub["getStrInLang"] = function (sKey, sLang) { 180 | sLang = sLang || _pri.lang; 181 | var sKey = _pri_s.data[sLang][sKey]; 182 | if(sKey.call) { 183 | return sKey.apply(sKey, [arguments[0]].concat(arguments.slice(2))); 184 | }else{ 185 | return sKey; 186 | } 187 | }; 188 | 189 | switch(this+'') { 190 | case 'test': 191 | _pub._pri = _pri; 192 | case 'extend': 193 | _pub._pro = _pro; 194 | _pub._init = _init; 195 | break; 196 | default: 197 | delete _pub._init; 198 | delete _pub._pro; 199 | _init.apply(_pub, arguments); 200 | } 201 | return _pub; 202 | }; 203 | 204 | 205 | 206 | return _pub_static; 207 | 208 | 209 | 210 | }); 211 | 212 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/js/envSetting.js: -------------------------------------------------------------------------------- 1 | /** 2 | _pri["request"] = JH.request(_pub); 3 | "setIniRequest" : _pri.request.create(JH.request.NS.jsonH, 'setIni'), 4 | "getIniRequest" : _pri.request.create(JH.request.NS.jsonH, 'getIni'), 5 | 6 | 7 | "setIni" : _pri.request.create(JH.request.NS.opt, 'setIni'), 8 | "getIni" : function (cb) { 9 | _pri.request.create(JH.request.NS.opt, 'getIni', { 10 | succeed : function (oIni) { 11 | cb(oIni); 12 | } 13 | }).send(); 14 | }, 15 | */ 16 | 17 | var config = { 18 | mode: 'request' 19 | }; 20 | 21 | JH.request = JH.newFun(function (JH) { 22 | var _fun = function (oSrc) { 23 | var _oSrc = oSrc, _oRequestData, _oResponseData; 24 | 25 | //JH.modNS.jsonH.language = 'en'; 26 | return { 27 | "create": function (ns, sKey, oSpec) { 28 | var oRe; 29 | var buildSend = function (fn) { 30 | return { 31 | send: function (oRequestData) { 32 | fn(oRequestData, function (oData) { 33 | if (oSpec && oSpec.succeed) { 34 | oSpec.succeed.apply(_oSrc, [oData, oRequestData]); 35 | } 36 | }); 37 | } 38 | }; 39 | }; 40 | 41 | switch (sKey) { 42 | case 'openTab': 43 | oRe = buildSend(function (oRequestData, fResponse) { 44 | window.extension.sendRequest({ cmd: 'openTab', data: oRequestData }, function (response) { 45 | var oData = { 46 | code: 1, 47 | msg: 'ok', 48 | data: response 49 | }; 50 | fResponse(oData); 51 | }); 52 | }); 53 | break; 54 | case 'getJsonString': 55 | oRe = buildSend(function (oRequestData, fResponse) { 56 | window.extension.sendRequest({ cmd: 'getJson' }, function (response) { 57 | var oData = { 58 | code: 1, 59 | msg: 'ok', 60 | data: response 61 | }; 62 | fResponse(oData); 63 | }); 64 | }); 65 | break; 66 | case 'getAdData': 67 | oRe = buildSend(function (oRequestData, fResponse) { 68 | window.extension.sendRequest({ 69 | cmd: 'getAdData', 70 | data: { 71 | url: oRequestData.url 72 | } 73 | }, function (response) { 74 | var oData = { 75 | code: 1, 76 | msg: 'ok', 77 | data: response 78 | }; 79 | fResponse(oData); 80 | }); 81 | }); 82 | break; 83 | case 'setIni': 84 | oRe = buildSend(function (oRequestData, fResponse) { 85 | window.extension.sendRequest({ 86 | cmd: 'setIni' 87 | , oIni: oRequestData 88 | }, function (response) { 89 | var oData = { 90 | code: 1, 91 | msg: 'ok', 92 | data: response 93 | }; 94 | fResponse(oData); 95 | }); 96 | }); 97 | break; 98 | case 'getIni': 99 | oRe = buildSend(function (oRequestData, fResponse) { 100 | window.extension.sendRequest({ 101 | cmd: 'getIni' 102 | }, function (response) { 103 | var oDefault = { 104 | "able": true, 105 | "lang": 'en', 106 | "holdPanel": true, 107 | "showValue": true, 108 | "showIco": false, 109 | "showStyle": "", 110 | "showImg": true, 111 | "hideAdList": true, 112 | "showImgMode": 'hover', 113 | "openJhMode": 'win', 114 | "showArrLeng": false, 115 | "adVer": 0, 116 | "adIndex": 0, 117 | "adShoot": {}, 118 | "adList": [], 119 | "times": 0 120 | }; 121 | for (var k in oDefault) { 122 | if (response[k] === undefined) { 123 | response[k] = oDefault[k]; 124 | } 125 | } 126 | localStorage['jhIni'] = JSON.stringify(response); 127 | var oData = { 128 | code: 1, 129 | msg: 'ok', 130 | data: response 131 | }; 132 | fResponse(oData); 133 | }); 134 | }); 135 | break; 136 | 137 | } 138 | 139 | return oRe; 140 | 141 | } 142 | }; 143 | }; 144 | 145 | return JH.mergePropertyFrom(_fun, { 146 | "NS": { 147 | 'jsonH': {}, 148 | 'opt': {} 149 | } 150 | }); 151 | }); 152 | 153 | parseHTML = {}; 154 | parseHTML.s = ['inner']; 155 | 156 | JH["elementHtml"] = function (el, sHtml) { 157 | var s = parseHTML.s.concat(['HTM']).join(''); 158 | if (sHtml !== undefined) { 159 | //parseHTML(document, sHtml, true, 'window://jsonhandle/content/JSON-handle/JSON-handle.html', false); 160 | el[s + 'L'] = sHtml; 161 | return el; 162 | } else { 163 | return el[s + 'L']; 164 | } 165 | }; 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/HelpController.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Threading.Tasks; 7 | using Microsoft.AspNetCore.Mvc; 8 | using Microsoft.AspNetCore.Mvc.ApiExplorer; 9 | using Microsoft.AspNetCore.Mvc.Controllers; 10 | using Microsoft.Extensions.Options; 11 | using Microsoft.AspNetCore.Authorization; 12 | using Newtonsoft.Json.Linq; 13 | 14 | namespace Microsoft.AspNetCore.ApiHelp.Core { 15 | /// 16 | /// Represents the help controller to generate API documentation. 17 | /// 18 | [AllowAnonymous] 19 | [Route("api/[controller]")] 20 | public class HelpController { 21 | private readonly IApiDescriptionGroupCollectionProvider _provider; 22 | private readonly ApiHelpOptions _options; 23 | 24 | /// 25 | /// Initializes a new instance of the class. 26 | /// 27 | /// The provider. 28 | /// The api help options. 29 | public HelpController(IApiDescriptionGroupCollectionProvider provider, IOptions options) { 30 | _provider = provider; 31 | _options = options.Value; 32 | } 33 | 34 | [HttpGet] 35 | public JObject Get() { 36 | var json = new JObject(); 37 | 38 | // each group 39 | foreach (var group in _provider.ApiDescriptionGroups.Items) { 40 | json.Add(group.GroupName, Handle(group)); 41 | } 42 | 43 | return json; 44 | } 45 | 46 | [HttpGet("[action]")] 47 | public JObject Get([FromQuery]ApiHelpInputModel model) { 48 | var items = _provider.ApiDescriptionGroups.Items 49 | .SelectMany(group => group.Items.Where(it => 50 | it.RelativePath.Equals(model.RelativePath, StringComparison.OrdinalIgnoreCase) 51 | && 52 | (model.HttpMethod == null || it.HttpMethod.Equals(model.HttpMethod, StringComparison.OrdinalIgnoreCase)) 53 | )); 54 | 55 | // Remove the obsolete 56 | if (_options.IgnoreObsoleteApi) { 57 | items = items.Where(item => !item.IsObsolete()); 58 | } 59 | 60 | var json = new JObject(); 61 | foreach (var item in items) { 62 | json.Add($"{item.HttpMethod} {item.RelativePath}", Handle(item, false)); 63 | } 64 | 65 | return json; 66 | } 67 | 68 | private JToken Handle(ApiDescriptionGroup group) { 69 | var items = group.Items.AsEnumerable(); 70 | // Remove the obsolete 71 | if (_options.IgnoreObsoleteApi) { 72 | items = items.Where(item => !item.IsObsolete()); 73 | } 74 | 75 | var json = new JObject(); 76 | foreach (var item in items) { 77 | json.Add($"{item.HttpMethod} {item.RelativePath}", Handle(item)); 78 | } 79 | 80 | return json; 81 | } 82 | 83 | private JToken Handle(ApiDescription item, bool checkPolicy = true) { 84 | var json = new JObject(); 85 | 86 | json.Add("Summary", item.GetSummary()); 87 | json.Add("HttpMethod", item.HttpMethod); 88 | json.Add("RelativePath", item.RelativePath); 89 | 90 | if (!checkPolicy || _options.GenerateStrategy == DocumentGenerateStrategy.Eager) { 91 | json.Add("Request", HandleRequest(item)); 92 | json.Add("Response", HandleResponse(item)); 93 | } 94 | 95 | return json; 96 | } 97 | 98 | private JToken HandleRequest(ApiDescription item) { 99 | var json = new JObject(); 100 | 101 | if (_options.IncludeSupportedMediaType && item.SupportedRequestFormats?.Count > 0) { 102 | json.Add("SupportedMediaType", new JArray(item.SupportedRequestMediaTypes())); 103 | } 104 | 105 | foreach (var parameter in item.ParameterDescriptions.Where(p => p.Source.IsFromRequest)) { 106 | json.Add(parameter.Name, HandlerParameter(parameter)); 107 | } 108 | 109 | return json; 110 | } 111 | 112 | private JToken HandleResponse(ApiDescription item) { 113 | Type type = null; 114 | 115 | var action = item.ActionDescriptor; 116 | if (action is ControllerActionDescriptor) { 117 | var controllerAtion = action as ControllerActionDescriptor; 118 | // We only provide response info if we can figure out a type that is a user-data type. 119 | // Void /Task object/IActionResult will result in no data. 120 | type = GetDeclaredReturnType(controllerAtion); 121 | } 122 | else { 123 | var supportedResponseTypes = item.SupportedResponseTypes; 124 | if (supportedResponseTypes.Count > 0) { 125 | type = supportedResponseTypes[0].Type; 126 | } 127 | } 128 | 129 | var json = new JObject(); 130 | 131 | if (_options.IncludeSupportedMediaType && item.SupportedResponseTypes?.Count > 0) { 132 | json.Add("SupportedMediaType", new JArray(item.SupportedResponseMediaTypes())); 133 | } 134 | 135 | json.Add("Scaffold", type.Scaffold()); 136 | json.Add("Schema", type.Schema()); 137 | 138 | return json; 139 | } 140 | 141 | private JToken HandlerParameter(ApiParameterDescription parameter) { 142 | var json = new JObject(); 143 | 144 | json.Add("Source", parameter.Source.Id); 145 | json.Add("Scaffold", parameter.Type.Scaffold()); 146 | json.Add("Schema", parameter.Type.Schema()); 147 | 148 | return json; 149 | } 150 | 151 | private static Type GetDeclaredReturnType(ControllerActionDescriptor action) { 152 | var declaredReturnType = action.MethodInfo.ReturnType; 153 | if (declaredReturnType == typeof(void) || 154 | declaredReturnType == typeof(Task)) { 155 | return typeof(void); 156 | } 157 | 158 | // Unwrap the type if it's a Task. The Task (non-generic) case was already handled. 159 | var unwrappedType = GetTaskInnerTypeOrNull(declaredReturnType) ?? declaredReturnType; 160 | 161 | // If the method is declared to return IActionResult or a derived class, that information 162 | // isn't valuable to the formatter. 163 | if (typeof(IActionResult).IsAssignableFrom(unwrappedType)) { 164 | return null; 165 | } 166 | else { 167 | return unwrappedType; 168 | } 169 | } 170 | 171 | private static Type GetTaskInnerTypeOrNull(Type type) { 172 | var genericType = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(Task<>)); 173 | 174 | return genericType?.GenericTypeArguments[0]; 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/Swagger/src/app/components/main/jsonHandle/json-handle.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input, EventEmitter, OnChanges, SimpleChanges, AfterViewChecked} from '@angular/core'; 2 | import { Observable } from 'rxjs/Observable'; 3 | 4 | @Component({ 5 | moduleId: module.id, 6 | selector: 'json-handle', 7 | templateUrl: 'json-handle.component.html', 8 | styleUrls: ['json-handle.component.css'] 9 | }) 10 | export class JsonHandleComponent implements OnInit, AfterViewChecked { 11 | constructor() { } 12 | 13 | @Input() jsonStr; 14 | ngOnChanges(changes: SimpleChanges) { 15 | this.HTML = this.Process(); 16 | } 17 | ngOnInit() { 18 | this.HTML = this.Process(); 19 | } 20 | ngAfterViewChecked() { 21 | console.clear(); 22 | } 23 | 24 | SINGLE_TAB = " "; 25 | TAB = this.MultiplyString(1, this.SINGLE_TAB); 26 | ImgCollapsed = "./images/Collapsed.gif"; 27 | ImgExpanded = "./images/Expanded.gif"; 28 | HTML: string = ""; 29 | 30 | @Input() showType: string = "code"; 31 | 32 | // Indent 33 | MultiplyString(num: number, str: string) { 34 | var sb = []; 35 | for (var i = 0; i < num; i++) { 36 | sb.push(str); 37 | } 38 | return sb.join(""); 39 | } 40 | Process() { 41 | var html = ""; 42 | var HTML = ""; 43 | //if (this.jsonStr == "") 44 | // this.jsonStr = "\"\""; 45 | var obj = this.jsonStr; 46 | html = this.ProcessObject(obj, 0, false, false, false); 47 | if (this.showType == "code") 48 | HTML = `
${html}
`; 49 | else if (this.showType == "text") 50 | HTML = `
${html}
`; 51 | return HTML; 52 | } 53 | getDataType(data) { 54 | if (typeof data === 'object') { 55 | if (data instanceof Array) 56 | return 'array'; 57 | else if (data instanceof Date) 58 | return 'date'; 59 | else if (data instanceof RegExp) 60 | return 'regExp'; 61 | else 62 | return 'object' 63 | } 64 | else { 65 | return typeof data; 66 | } 67 | } 68 | GetRow(indent, data, isPropertyContent) { 69 | var tabs = ""; 70 | for (var i = 0; i < indent && !isPropertyContent; i++) tabs += this.TAB; 71 | if (data != null && data.length > 0 && data.charAt(data.length - 1) != "\n") 72 | data = data + "\n"; 73 | return tabs + data; 74 | } 75 | FormatLiteral(literal, quote, comma, indent, isArray, style) { 76 | if (typeof literal == 'string') 77 | literal = literal.split("<").join("<").split(">").join(">"); 78 | var str = "" + quote + literal + quote + comma + ""; 79 | if (isArray) str = this.GetRow(indent, str, null); 80 | return str; 81 | } 82 | FormatFunction(indent, obj) { 83 | var tabs = ""; 84 | for (var i = 0; i < indent; i++) tabs += this.TAB; 85 | var funcStrArray = obj.toString().split("\n"); 86 | var str = ""; 87 | for (var i = 0; i < funcStrArray.length; i++) { 88 | str += ((i == 0) ? "" : tabs) + funcStrArray[i] + "\n"; 89 | } 90 | return str; 91 | } 92 | ProcessObject(obj, indent, addComma, isArray, isPropertyContent) { 93 | var html = ""; 94 | var comma = (addComma) ? ", " : ""; 95 | var type = this.getDataType(obj); 96 | var clpsHtml = ""; 97 | if (type == 'array') { 98 | if (obj.length == 0) { 99 | html += this.GetRow(indent, `[ ]${comma}`, isPropertyContent); 100 | } else { 101 | clpsHtml = ``; 102 | html += this.GetRow(indent, `[${clpsHtml}`, isPropertyContent); 103 | for (var i = 0; i < obj.length; i++) { 104 | html += this.ProcessObject(obj[i], indent + 1, i < (obj.length - 1), true, false); 105 | } 106 | clpsHtml = ""; 107 | html += this.GetRow(indent, clpsHtml + "]" + comma, null); 108 | } 109 | } else if (type == 'object') { 110 | if (obj == null) { 111 | html += this.FormatLiteral("null", "", comma, indent, isArray, "Null"); 112 | } else if (type == 'date') { 113 | html += this.FormatLiteral(`new Date(${obj.getTime()}) /*${obj.toLocaleString()}*/`, "", comma, indent, isArray, "Date"); 114 | } else if (type == 'regExp') { 115 | html += this.FormatLiteral(`new RegExp(${obj})`, "", comma, indent, isArray, "RegExp"); 116 | } else { 117 | var numProps = 0; 118 | for (var prop in obj) numProps++; 119 | if (numProps == 0) { 120 | html += this.GetRow(indent, "{ }" + comma, isPropertyContent); 121 | } else { 122 | clpsHtml = ``; 123 | html += this.GetRow(indent, `{${clpsHtml}`, isPropertyContent); 124 | var j = 0; 125 | for (var prop in obj) { 126 | var quote = "\""; 127 | var result = this.ProcessObject(obj[prop], indent + 1, ++j < numProps, false, true); 128 | html += this.GetRow(indent + 1, `${quote}${prop}${quote}: ${result}`, null); 129 | } 130 | clpsHtml = ""; 131 | html += this.GetRow(indent, `${clpsHtml}}${comma}`, null); 132 | } 133 | } 134 | } else if (type == 'number') { 135 | html += this.FormatLiteral(obj, "", comma, indent, isArray, "Number"); 136 | } else if (type == 'boolean') { 137 | html += this.FormatLiteral(obj, "", comma, indent, isArray, "Boolean"); 138 | } else if (type == 'function') { 139 | if (type == 'regExp') { 140 | html += this.FormatLiteral(`new RegExp(${obj})`, "", comma, indent, isArray, "RegExp"); 141 | } else { 142 | obj = this.FormatFunction(indent, obj); 143 | html += this.FormatLiteral(obj, "", comma, indent, isArray, "Function"); 144 | } 145 | } else if (type == 'undefined') { 146 | html += this.FormatLiteral("undefined", "", comma, indent, isArray, "Null"); 147 | } else { 148 | html += this.FormatLiteral(obj.toString().split("\\").join("\\\\").split('"').join('\\"'), "\"", comma, indent, isArray, "String"); 149 | } 150 | return html; 151 | } 152 | test() { 153 | // this.onGetValue.emit("test"); 154 | } 155 | } -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/TypeJsonExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using System.Linq; 5 | using System.Reflection; 6 | using Newtonsoft.Json.Linq; 7 | 8 | namespace Microsoft.AspNetCore.ApiHelp.Core { 9 | /// 10 | /// The extension methods for to enable an application to read XML comments at run time represents by a Json object. 11 | /// 12 | internal static class TypeJsonExtensions { 13 | public static JToken Schema(this Type type, params string[] excludeProperties) { 14 | if (type == null || type == typeof(void)) { 15 | return null; 16 | } 17 | 18 | type = type.UnwrapNullableType(); 19 | 20 | var typeInfo = type.GetTypeInfo(); 21 | if (typeInfo.IsEnum || type.IsPrimitive()) { 22 | return JToken.FromObject(type.GetDefaultValue() ?? type.Name); 23 | } 24 | else if (typeInfo.IsGenericType && type.IsCollectionType()) { 25 | var array = new JArray(); 26 | var elementType = type.GenericTypeArguments[0]; 27 | if (elementType.IsPrimitive()) { 28 | array.Add(JToken.FromObject(elementType.GetDefaultValue() ?? elementType.Name)); 29 | } 30 | else { 31 | array.Add(elementType.Schema()); 32 | } 33 | 34 | return array; 35 | } 36 | 37 | var json = new JObject(); 38 | var properties = typeInfo.GetProperties(); 39 | if (excludeProperties.Length > 0) { 40 | properties = properties.Where(p => !excludeProperties.Contains(p.Name)).ToArray(); 41 | } 42 | foreach (var prop in properties) { 43 | var propertyType = prop.PropertyType.UnwrapNullableType(); 44 | if (propertyType.IsPrimitive()) { 45 | var defaultValue = JToken.FromObject(propertyType.GetDefaultValue() ?? prop.XmlDoc() ?? prop.Name); 46 | json.Add(prop.Name, defaultValue); 47 | } 48 | else if (propertyType.GetTypeInfo().IsGenericType && propertyType.IsCollectionType()) { 49 | var array = new JArray(); 50 | var elementType = propertyType.GenericTypeArguments[0]; 51 | if (elementType.IsPrimitive()) { 52 | var defaultValue = JToken.FromObject(elementType.GetDefaultValue() ?? prop.XmlDoc() ?? prop.Name); 53 | array.Add(defaultValue); 54 | } 55 | else { 56 | array.Add(elementType.Schema()); 57 | } 58 | 59 | json.Add(prop.Name, array); 60 | } 61 | else { 62 | json.Add(prop.Name, propertyType.Schema()); 63 | } 64 | } 65 | 66 | return json; 67 | } 68 | 69 | public static JToken Scaffold(this Type type) { 70 | if (type == null || type == typeof(void)) { 71 | return null; 72 | } 73 | 74 | var unwarp = type.UnwrapNullableType(); 75 | 76 | var json = new JObject(); 77 | 78 | var typeInfo = unwarp.GetTypeInfo(); 79 | if (typeInfo.IsEnum) { 80 | // Summary 81 | json.Add("Summary", unwarp.GetEnumXDoc()); 82 | // Type 83 | json.Add("Type", Enum.GetUnderlyingType(unwarp).Name); 84 | 85 | // Optional 86 | var isNullable = type != unwarp; 87 | if (isNullable) { 88 | json.Add("IsOptional", true); 89 | } 90 | else { 91 | json.Add("IsOptional", false); 92 | } 93 | 94 | return json; 95 | } 96 | else if (type.IsPrimitive()) { 97 | // Optional 98 | var isNullable = type != unwarp; 99 | if (isNullable) { 100 | json.Add("Type", unwarp.Name); 101 | json.Add("IsOptional", true); 102 | return json; 103 | } 104 | else { 105 | return type.Name; 106 | } 107 | } 108 | else if (typeInfo.IsGenericType && type.IsCollectionType()) { 109 | var array = new JArray(); 110 | var elementType = type.GenericTypeArguments[0]; 111 | if (elementType.IsPrimitive()) { 112 | array.Add(JToken.FromObject(elementType.GetDefaultValue() ?? elementType.Name)); 113 | } 114 | else { 115 | array.Add(elementType.Scaffold()); 116 | } 117 | 118 | return array; 119 | } 120 | 121 | var properties = typeInfo.GetProperties(); 122 | foreach (var prop in properties) { 123 | if (prop.PropertyType.IsPrimitive()) { 124 | var propJson = new JObject(); 125 | var propertyType = prop.PropertyType.UnwrapNullableType(); 126 | // Summary & type 127 | if (propertyType.GetTypeInfo().IsEnum) { 128 | propJson.Add("Summary", propertyType.GetEnumXDoc()); 129 | propJson.Add("Type", Enum.GetUnderlyingType(propertyType).Name); 130 | } 131 | else { 132 | propJson.Add("Summary", prop.XmlDoc() ?? prop.Name); 133 | propJson.Add("Type", propertyType.Name); 134 | } 135 | 136 | // Optional 137 | var isNullable = propertyType != prop.PropertyType; 138 | if (isNullable) { 139 | propJson.Add("IsOptional", true); 140 | } 141 | else { 142 | propJson.Add("IsOptional", false); 143 | } 144 | 145 | json.Add(prop.Name, propJson); 146 | } 147 | else if (prop.PropertyType.GetTypeInfo().IsGenericType && prop.PropertyType.IsCollectionType()) { 148 | var array = new JArray(); 149 | var elementType = prop.PropertyType.GenericTypeArguments[0]; 150 | if (elementType.IsPrimitive()) { 151 | var inner = new JObject(); 152 | var unwrapType = elementType.UnwrapNullableType(); 153 | // Summary & type 154 | if (unwrapType.GetTypeInfo().IsEnum) { 155 | inner.Add("Summary", unwrapType.GetEnumXDoc()); 156 | inner.Add("Type", Enum.GetUnderlyingType(unwrapType).Name); 157 | } 158 | else { 159 | inner.Add("Summary", prop.XmlDoc() ?? prop.Name); 160 | inner.Add("Type", unwrapType.Name); 161 | } 162 | 163 | // Optional 164 | var isNullable = unwrapType != elementType; 165 | if (isNullable) { 166 | inner.Add("IsOptional", true); 167 | } 168 | else { 169 | inner.Add("IsOptional", false); 170 | } 171 | 172 | array.Add(inner); 173 | } 174 | else { 175 | array.Add(elementType.Scaffold()); 176 | } 177 | 178 | json.Add(prop.Name, array); 179 | } 180 | else { 181 | json.Add(prop.Name, prop.PropertyType.Scaffold()); 182 | } 183 | } 184 | 185 | return json; 186 | } 187 | 188 | internal static JToken GetEnumXDoc(this Type enumType) { 189 | var typeInfo = enumType.UnwrapNullableType().GetTypeInfo(); 190 | if (!typeInfo.IsEnum) { 191 | throw new ArgumentException($"{nameof(enumType)} must be a Enum", nameof(enumType)); 192 | } 193 | 194 | var json = new JObject(); 195 | 196 | // why: remove the "value__" 197 | var fields = typeInfo.DeclaredFields.Where(f => !f.IsSpecialName); 198 | foreach (var field in fields) { 199 | var xml = field.XmlDoc() ?? field.Name; 200 | json.Add(field.GetRawConstantValue().ToString(), xml); 201 | } 202 | 203 | return json; 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp.Core/TypeXDocExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Arch team. All rights reserved. 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Xml.Linq; 9 | using System.Xml.XPath; 10 | 11 | namespace Microsoft.AspNetCore.ApiHelp.Core { 12 | /// 13 | /// Provides extension methods for reading XML comments from reflected members. 14 | /// 15 | internal static class TypeXDocExtensions { 16 | private static Dictionary _cachedXDoc; 17 | 18 | /// 19 | /// Static constructor. 20 | /// 21 | static TypeXDocExtensions() { 22 | _cachedXDoc = new Dictionary(StringComparer.OrdinalIgnoreCase); 23 | } 24 | 25 | /// 26 | /// Returns the XML documentation (summary tag) for the specified member. 27 | /// 28 | /// The reflected member. 29 | /// The contents of the summary tag for the member. 30 | public static string XmlDoc(this MemberInfo member) { 31 | var assembly = member.Module.Assembly; 32 | 33 | var assemblyName = assembly.GetName(); 34 | if (_cachedXDoc.ContainsKey(assemblyName.FullName)) { 35 | var xml = _cachedXDoc[assemblyName.FullName]; 36 | 37 | return XmlDoc(member, xml); 38 | } 39 | else { 40 | var assemblyPath = Path.GetDirectoryName(assembly.Location); 41 | var path = Path.Combine(assemblyPath, assemblyName.Name + ".xml"); 42 | 43 | return XmlDoc(member, path); 44 | } 45 | } 46 | 47 | /// 48 | /// Returns the XML documentation (summary tag) for the specified member. 49 | /// 50 | /// The reflected member. 51 | /// Path to the XML documentation file. 52 | /// The contents of the summary tag for the member. 53 | public static string XmlDoc(this MemberInfo member, string pathToXmlFile) { 54 | var assemblyName = member.Module.Assembly.GetName(); 55 | XDocument xml = null; 56 | 57 | if (_cachedXDoc.ContainsKey(assemblyName.FullName)) { 58 | xml = _cachedXDoc[assemblyName.FullName]; 59 | } 60 | else { 61 | if (!File.Exists(pathToXmlFile)) { 62 | //throw new FileNotFoundException($"Cannot find the xml file: {pathToXmlFile}", pathToXmlFile); 63 | return null; 64 | } 65 | _cachedXDoc[assemblyName.FullName] = (xml = XDocument.Load(pathToXmlFile)); 66 | } 67 | 68 | return XmlDoc(member, xml); 69 | } 70 | 71 | /// 72 | /// Returns the XML documentation (summary tag) for the specified member. 73 | /// 74 | /// The reflected member. 75 | /// XML documentation. 76 | /// The contents of the summary tag for the member. 77 | public static string XmlDoc(this MemberInfo member, XDocument xml) { 78 | return xml.XPathEvaluate( 79 | string.Format( 80 | "string(/doc/members/member[@name='{0}']/summary)", 81 | GetMemberElementName(member) 82 | ) 83 | ).ToString().Trim(); 84 | } 85 | 86 | /// 87 | /// Returns the XML documentation (returns/param tag) for the specified parameter. 88 | /// 89 | /// The reflected parameter (or return value). 90 | /// The contents of the returns/param tag for the parameter. 91 | /// 92 | /// Console.WriteLine(typeof(SomeClass).GetMethod("SomeMethod").GetParameter("someParam").XmlDoc()); 93 | /// Console.WriteLine(typeof(SomeClass).GetMethod("SomeMethod").ReturnParameter.XmlDoc()); 94 | /// 95 | public static string XmlDoc(this ParameterInfo parameter) { 96 | var assembly = parameter.Member.Module.Assembly; 97 | 98 | var assemblyName = assembly.GetName(); 99 | if (_cachedXDoc.ContainsKey(assemblyName.FullName)) { 100 | var xml = _cachedXDoc[assemblyName.FullName]; 101 | 102 | return XmlDoc(parameter, xml); 103 | } 104 | else { 105 | var assemblyPath = Path.GetDirectoryName(assembly.Location); 106 | var path = Path.Combine(assemblyPath, assemblyName.Name + ".xml"); 107 | 108 | return XmlDoc(parameter, path); 109 | } 110 | } 111 | 112 | /// 113 | /// Returns the XML documentation (returns/param tag) for the specified parameter. 114 | /// 115 | /// The reflected parameter (or return value). 116 | /// Path to the XML documentation file. 117 | /// The contents of the returns/param tag for the parameter. 118 | public static string XmlDoc(this ParameterInfo parameter, string pathToXmlFile) { 119 | var assemblyName = parameter.Member.Module.Assembly.GetName(); 120 | XDocument xml = null; 121 | 122 | if (_cachedXDoc.ContainsKey(assemblyName.FullName)) { 123 | xml = _cachedXDoc[assemblyName.FullName]; 124 | } 125 | else { 126 | if (!File.Exists(pathToXmlFile)) { 127 | //throw new FileNotFoundException("Cannot find the xml file", pathToXmlFile); 128 | return null; 129 | } 130 | 131 | _cachedXDoc[assemblyName.FullName] = (xml = XDocument.Load(pathToXmlFile)); 132 | } 133 | 134 | return XmlDoc(parameter, xml); 135 | } 136 | 137 | /// 138 | /// Returns the XML documentation (returns/param tag) for the specified parameter. 139 | /// 140 | /// The reflected parameter (or return value). 141 | /// XML documentation. 142 | /// The contents of the returns/param tag for the parameter. 143 | public static string XmlDoc(this ParameterInfo parameter, XDocument xml) { 144 | if (parameter.IsRetval || string.IsNullOrEmpty(parameter.Name)) { 145 | return xml.XPathEvaluate( 146 | string.Format( 147 | "string(/doc/members/member[@name='{0}']/returns)", 148 | GetMemberElementName(parameter.Member) 149 | ) 150 | ).ToString().Trim(); 151 | } 152 | else { 153 | return xml.XPathEvaluate( 154 | string.Format( 155 | "string(/doc/members/member[@name='{0}']/param[@name='{1}'])", 156 | GetMemberElementName(parameter.Member), 157 | parameter.Name 158 | ) 159 | ).ToString().Trim(); 160 | } 161 | } 162 | 163 | /// 164 | /// Returns the expected name for a member element in the XML documentation file. 165 | /// 166 | /// The reflected member. 167 | /// The name of the member element. 168 | private static string GetMemberElementName(MemberInfo member) { 169 | char prefixCode; 170 | string memberName = member.DeclaringType.FullName + "." + member.Name; 171 | 172 | switch (member.MemberType) { 173 | case MemberTypes.Constructor: 174 | // XML documentation uses slightly different constructor names 175 | memberName = memberName.Replace(".ctor", "#ctor"); 176 | goto case MemberTypes.Method; 177 | case MemberTypes.Method: 178 | prefixCode = 'M'; 179 | // parameters are listed according to their type, not their name 180 | string paramTypesList = string.Join( 181 | ",", 182 | ((MethodBase)member).GetParameters() 183 | .Cast() 184 | .Select(x => x.ParameterType.FullName 185 | ).ToArray() 186 | ); 187 | if (!string.IsNullOrEmpty(paramTypesList)) { 188 | memberName += "(" + paramTypesList + ")"; 189 | } 190 | break; 191 | case MemberTypes.Event: 192 | prefixCode = 'E'; 193 | break; 194 | case MemberTypes.Field: 195 | prefixCode = 'F'; 196 | break; 197 | case MemberTypes.NestedType: 198 | // XML documentation uses slightly different nested type names 199 | memberName = memberName.Replace('+', '.'); 200 | goto case MemberTypes.TypeInfo; 201 | case MemberTypes.TypeInfo: 202 | prefixCode = 'T'; 203 | break; 204 | case MemberTypes.Property: 205 | prefixCode = 'P'; 206 | break; 207 | default: 208 | throw new ArgumentException("Unknown member type", nameof(member)); 209 | } 210 | 211 | // elements are of the form "M:Namespace.Class.Method" 212 | return string.Format("{0}:{1}", prefixCode, memberName); 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/Microsoft.AspNetCore.ApiHelp/UI/JsonH/css/jsonH.css: -------------------------------------------------------------------------------- 1 | @import url(tree.css); 2 | 3 | body {margin:0px;padding:1em 1em 2.8em;font-family:Tahoma,arial,simsun;font-size:14px;background-color:#fafaff;} 4 | div,form,img,ol,dl,dt,dd,fieldset {margin:0;padding:0;border:0;} 5 | h1,h2,h3,h4,h5,h6,p {margin:0;padding:0;font-size:1em;} 6 | ul,ol,li {margin:0;padding:0;list-style:none;} 7 | em {font-style:normal;} 8 | hr {display:none;} 9 | 10 | html { 11 | visibility:visible !important; 12 | } 13 | /**/ 14 | #jsonNav {height@:100%;} 15 | #panel {padding:12px 2px 12px 12px;width:512px;height:80%;@min-height:300px;position:fixed;z-index:10;right:1em;top:1em;border:1px solid #C8C8C8;border-color:#e7e7f3 #c8c8d8 #c8c8d8 #e7e7f3;background:#f3f5ff;box-shadow:4px 4px 9px rgba(0, 0, 50, 0.2), -3px -3px 30px rgba(88, 88, 188, 0.1) inset; 16 | transition: 17 | height .2s ease-out 18 | ,width .2s ease-out 19 | ; 20 | } 21 | 22 | #panel.min {width:10px;height:3px;} 23 | #panel.disTransition {transition:none;} 24 | #showLink {display:none;position:absolute;right:27px;top:45px;} 25 | a#showLink:link, a#showLink:visited {color:#577cff;text-decoration:underline;} 26 | a#showLink:hover, a#showLink:active {color:#577cff;text-decoration:none;} 27 | #minBtn {position:absolute;right:5px;top:5px;cursor:pointer;color:#577cff;} 28 | #minBtn:hover {color:#87acff;} 29 | #valueAct {height:100%;overflow:auto;opacity:1;position:relative; 30 | transition: 31 | opacity .4s ease-in 32 | ; 33 | } 34 | #panel.min #valueAct {display@:none;opacity:0;height:1px;overflow:hidden;} 35 | #saveBtn {float:left;} 36 | #undoBtn {margin-left:4em;} 37 | #undoBtn, #redoBtn {float:left;font-family:Tahoma,arial,simsun;} 38 | #showPath {width:420px;background-color:#e3e4e9;} 39 | #showKey {width:200px;background-color:#e3e4e9;} 40 | #showKey.isArrayElm {} 41 | #showKey.isArrayElm~span {visibility:hidden;} 42 | .lableInput #showKey~span {font-weight:bold;} 43 | #showValue {outline:0;width:462px;min-height:270px;padding:10px 12px;border:1px solid #b6b6c4;border-right-color:#eef;border-bottom-color:#eef;border-radius:2px;font-family:Tahoma,arial,simsun;box-shadow:1px 1px 6px rgba(33, 33, 98, .16) inset;} 44 | #showValue:focus {box-shadow:1px 1px 12px rgba(53, 53, 118, .26) inset;border:1px solid #d0d0ed;border-right-color:#ddf;border-bottom-color:#ddf;} 45 | .inputTitle {display:inline-block;width:4em;margin:0 0 1em;} 46 | #pathTips {height:1.5em;line-height:1.6em;width:100%;position:fixed;z-index:15;left:0;bottom:0;background-color:#eee;color:#666;padding:0.2em 1em 0;border-top:1px solid #fff;} 47 | button {border-radius:2px;margin:0.5em 0 0;font-family:Tahoma,arial,simsun;border-width: 1px;padding: 1px 8px 3px;} 48 | #msgBox {color:red;font-size:12px;font-weight:bold;height:38px;line-height:14px;padding-right:24px;padding-top:5px;text-align:right;} 49 | .textInpub {padding:3px 6px;border-radius:2px;font-family:Tahoma,arial,simsun;} 50 | #mask {z-index:20;position:absolute;left:0;top:0;background-color:rgba(101, 123, 190,0.3);width:100%;height:100%;} 51 | #enterInputDialog {position:absolute;left:50%;top:50%;margin:-170px 0 0 -280px;padding:20px;width:560px;height:340px;text-align:right;border-radius:6px;box-shadow: 6px 5px 7px rgba(50, 50, 50, 0.4);background-color:#fafaff;border:1px solid #e8e8e8;} 52 | #enterValue {width:530px;height:265px;margin:5px 0 0;border-radius:2px;padding:15px;box-shadow:1px 1px 10px rgba(88, 88, 188, 0.18) inset;border-color:#888 #ddd #ddd #888;font-family:Tahoma,arial,simsun;} 53 | #enterInputTips {text-align:left;line-height:1.5em;} 54 | .tools2 {padding:0 1em 0 0;text-align:right;} 55 | 56 | .noIco .ico {display:none;} 57 | .folderIco .ico {display:none;} 58 | .folderIco .elmBox {padding:0 0 0 20px;} 59 | .folderIco .node .elmBox {background-image:url(treePic/elm.png);background-position:2px 0;background-repeat:no-repeat;} 60 | .folderIco .elmBox {background-image:url(treePic/objectOpen.png);background-position:2px 0;background-repeat:no-repeat;} 61 | .noIco.folderIco .elmBox {background-image:none;padding:0;} 62 | 63 | .value {display:none;padding:0 8px} 64 | .object>.row .elm {color:#333;font-weight:normal;} 65 | .object>.row .elm:after {content:"";} 66 | .object>.elmList>.elmBlock>.row .elm:after {} 67 | .array>.elmList>.elmBlock>.row .elm {font-weight:normal;color:#000;display@:none;} 68 | .array>.elmList>.elmBlock>.row .elm.array-key {color:#aaa;} 69 | .showValueInNav .array>.elmList>.node>.row .elm {display:none;} 70 | .showValueInNav .array>.elmList>.array>.row .elm {display:inline;} 71 | .array>.elmList>.array>.row .elm {} 72 | .elm, .array>.elmList>.array>.row .elm {color:#4a0;font-weight:bold;display:inline;} 73 | .showValueInNav .elm:after {content:" :";color:#2c3;font-weight:bold;} 74 | .showValueInNav .cur>.row .elm:after {color:#fff;} 75 | .array>.elmList>.array>.row .elm:after {content:"";color:#2c3;font-weight:bold;} 76 | .showValueInNav .value {display:inline-block;line-height:24px;} 77 | .showValueInNav .array>.elmList>.elmBlock>.row .elm {} 78 | .string>.row .value {color:#f63;float@:left;} 79 | .string>.row .value img {display:none;border:1px solid #8C9ACA;} 80 | .showImg .string>.row .value img {display:inline;} 81 | .showImg .imgUrl.elmBlock>.row .elm {vertical-align:sub;} 82 | .showImg .value.has-img {padding-bottom:8px;vertical-align:text-top;} 83 | .number>.row .value {color:#cc00ff;} 84 | .null>.row .value {color:#bb4;} 85 | .boolean>.row .value {color:#09c;} 86 | .hover-show-img.showImg .value.has-img {padding-bottom:0;} 87 | .hover-show-img.showImg .string>.row .value { 88 | z-index:1; 89 | position:relative; 90 | } 91 | .hover-show-img.showImg .string>.row .value img { 92 | display:none; 93 | position:absolute; 94 | left:0; 95 | top:120%; 96 | } 97 | .hover-show-img.showImg .string>.row .value:hover { 98 | z-index:2; 99 | } 100 | .hover-show-img.showImg .string>.row .value:hover img{ 101 | display:inline; 102 | } 103 | .has-img img { 104 | max-height:300px; 105 | max-width:500px; 106 | } 107 | 108 | .copy-tips { 109 | color:#4a0; 110 | opacity:0; 111 | } 112 | .copy-tips.hide { 113 | transition:opacity 3s ease-in .5s; 114 | } 115 | .copy-tips.show { 116 | opacity:1; 117 | } 118 | #hideBox { 119 | width:1px; 120 | height:1px; 121 | overflow:hidden; 122 | position:absolute; 123 | left:-100px; 124 | top:-100px; 125 | } 126 | #errorTips { 127 | position:fixed; 128 | left:0; 129 | top:0; 130 | z-index:23; 131 | width:560px;border-radius:6px;box-shadow: 6px 5px 7px rgba(229, 163, 163, 0.4);background-color:#ffecf1;border:1px solid #dbb2b2; 132 | overflow:auto; 133 | max-height:98%; 134 | } 135 | #sigh { 136 | position:absolute; 137 | left:10px; 138 | top:10px; 139 | z-index:23; 140 | color:#d84646; 141 | cursor:pointer; 142 | } 143 | #errorBtn { 144 | padding:5px 0 0 5px; 145 | font-size:16px; 146 | cursor:pointer; 147 | color:#e96969; 148 | position:absolute; 149 | left:0; 150 | top:0; 151 | } 152 | #errorBtn:hover { 153 | opacity:0.6; 154 | } 155 | #errorCode .errorEm { 156 | background-color:#ff921b; 157 | } 158 | #errorTarget { 159 | color:#000; 160 | background-color:#fff; 161 | } 162 | #errorCode { 163 | padding:0 10px 10px; 164 | } 165 | #errorCode ol { 166 | padding:0 0 0 3em; 167 | } 168 | #tipsBox { 169 | color:#b4465c; 170 | padding: 6px 0 4px 2em; 171 | } 172 | #errorCode ol li { 173 | padding:4px 7px 0; 174 | list-style-type: decimal; 175 | color:#b4465c; 176 | background-color:#fdf7f7; 177 | } 178 | #errorCode ol li div { 179 | color:#000; 180 | } 181 | 182 | #jsObjEnterOk { 183 | float:left; 184 | color:#999; 185 | background-color:#fff; 186 | border-color:#eee #fff #fff #eee; 187 | } 188 | 189 | 190 | #rcmd { 191 | position:absolute; 192 | right:-1px; 193 | top:calc(100% + 2px); 194 | box-shadow:4px 4px 9px rgba(0, 0, 50, 0.4), -3px -3px 30px rgba(88, 88, 188, 0.2) inset; 195 | } 196 | #rcmd.tips { 197 | box-shadow:none; 198 | } 199 | #rcmd.tips a { 200 | line-height: 2em; 201 | font-size:12px; 202 | text-decoration:none; 203 | color:#6178C7; 204 | } 205 | #rcmd.tips a:hover { 206 | text-decoration:underline; 207 | } 208 | .min #optBtn, 209 | .min #rcmd { 210 | visibility:hidden; 211 | } 212 | .min #showValue { 213 | transition-delay : .4s; 214 | visibility:hidden; 215 | } 216 | #rcmd #closeAd { 217 | position:absolute; 218 | width:14px; 219 | height:14px; 220 | line-height:14px; 221 | padding:0; 222 | text-align:center; 223 | right:0; 224 | top:0; 225 | background-color:#aaa; 226 | border:none; 227 | color:#000; 228 | margin:0; 229 | } 230 | #rcmd #closeAd:hover { 231 | color:#fff; 232 | } 233 | .setting-btn { 234 | transition-property:visibility; 235 | transition-delay:.1s; 236 | visibility:visible; 237 | border:none; 238 | padding:0; 239 | margin:0; 240 | position:absolute; 241 | bottom:15px; 242 | right:15px; 243 | display:block; 244 | width:24px; 245 | height:24px; 246 | background:url(img/setting-btn.png) no-repeat 0 0; 247 | cursor:pointer; 248 | outline:none; 249 | } 250 | .setting-btn:hover { 251 | background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAE/ElEQVRIS51VC2xTZRT+bm/brYwhG48xhCggOCPD8dJIILAAGh8JUQEDBCSgMAIaxZjAho+MiEwIZCPAcGEwRZ5DFEFhvByE53Qp7NmtgDDGunWUru199N7ee8xf29IuIwT+5Oa2ueec7/zfOec7HB5xiGgugFcB6AAcAPZzHHcDQOBRvuw7F21ERMkAegHwALgHIFXX8eXFKukDSdbNzFbT4Plk0cS3bNV/XwIwCAAP4A7Hcb6uACMARDQQwMx2tzbB7dWFhDhDaWpf/pkWpzan9qY8huh/dy2g4dxfR058uvi1fEu3p2Y472Og10dlI9Li1oVuGYMTBCCiHgAWtDi12Y1N/gxFJRPPc85ePQ0Oj6APlWWKj/YSBNGXlKhXGc2J6aJM3RmuvaGuYNuGjwus1ktN7H/YPgzQ29Whf1d9Q56nKBSk4nGPKAj6hm+X5pefLl0NwM3yjtSAiOKbHOqCxiZ1va6T5XGDM3tXeyut+mLG+ca6ykUA7ADUmCKzGlTUyNs6fNobTwLw0/a17r0l648qirwWAOsyid2CI6JuAMYAmNh6T82ssiuToruLiHC+/Ij/ysUTLgMgjM98p3vG6AkpRpMxpgML83POHNyTvzojI+OO1Wq9C0AMAyz1STTl32ZljMuj9VNUMkbfYFfx975D+zbXeDrunQDQkNw71bIy98eJ6SNemcUbDREQSZQU0qRbdvv1NZ8vyWS2zUGKiKiwvFL8UFWJ9XPMaay/GshdMbvK4bi1GcBlAPcZt2Vlp9N1y4idvCl+QKc5giSK2rTJKVkAdrC2ZQAbTl4WPuuK91PHD3gK8pb9IopCAYCW0AAqoii+W3Nd+8YtcC909vPLEt6e1Od3AHMYTQzg/ZOXhb1dAdRcu+LLzZ5V5Gpv3RKSCZGIUgEsqayVF7q8Wr/OfqLPi2lTUhlF81lzMYAexfuqi+PizW8mJ/eNN5lNEV5VRaWD+7fus1n/yMnLy+PGjRuXCOD1Fqc23XbbPzIQeECrJApobrJr584c9u7emXcUwCoAbSyYAcBgAMNKSmtn9ksdMM/ARxVPklUu4P1z6LNJzUlJCX0EmZ6/06am+RUyRWdfUrSmY9f2NVcBVAE4B+ACgPbwJJsFQZh+u1XNam7jx4N7ABAOQqQrRt7AaTpiAoe/b8nPth3aU7AJQFloBgQAvohUCFJgZc11db5H0JmiPvZx3G1S1+Uu3nzNepY1RBsAP9OkiNg1twaWNdxWvtb0J9MillHO8ukVVy4cWwigPkYqiMjwT52Y0tqu5fIGWsgbeU6WRNyw14qDhrwYZ+lmiZkRn6eDGmxWcfBzw+N7JvUKfvv1wA/SzzvWnne72nIAVEekIooLQ//+Q56e+9GqIk1Tx14o/83TaLtavyK3xDE8fex8A896AdA1DceP7haLt35VMTRtpGvUy5NHu11Oy+HSwhpJ8u0HcAoAkwpWA4rRk9B2GpCQkJgpCF6mqo0bN24yDRs156A5zhxUWY/bRTnL37PX11ZsA3AWQG8AbFk5AdSGpr0DgNIVQFhh2YJhAQ1ZWVlxaaNmZRvN/DxZ9JlsdZX+ok3ZxwDkA7jJOiXEAusutrflUHD2O3YnR9EVng/2Zk8KgKkAXgoV71ooe6ZNQSpC88TeLHBowT4coKs2ZSrLpD14s1CmLDij4qGncw0eZcsCs65hfmzvsieSbVfO/wGiC2pcTa6aSAAAAABJRU5ErkJggg==) no-repeat 0 0; 252 | } 253 | .setting-btn:active { 254 | background:url(img/setting-btn.png) no-repeat 0 0; 255 | } 256 | 257 | .array-leng { 258 | display:none; 259 | } 260 | .show-leng .array-leng { 261 | display:inline; 262 | padding:0 10px; 263 | margin:0 0 0 4px; 264 | height:20px; 265 | line-height:20px; 266 | background-color:#d3d3d3; 267 | border-radius:4px; 268 | box-shadow:-2px 1px 3px rgba(70, 70, 70, 0.2); 269 | text-shadow:none; 270 | color:#fff; 271 | } 272 | .lengMode-array .elmBlock.object>.row .array-leng { 273 | display:none; 274 | } --------------------------------------------------------------------------------