In-depth Optimization of ASP. NET WebApi documentation Swagger, webapiswagger
This article is copyrighted by the blog and the author Wu Shuang himself. for reprinting and crawlers, please indicate the original address of the snail bait in the blog garden, cnblogs.com/tdws
Preface
Forgive me for writing this article to the title party, saying that it is in-depth optimization, But there is actually no depth. The source code has not been modified. If you want to use the WebApi Swagger document, please first move to the moderate optimization in the previous article.
Article 1: ASP. NET WebApi documentation Swagger moderate optimization http://www.cnblogs.com/tdws/p/6100126.html
Article 2: ASP. NET WebApi documentation Swashbuckle. Core and SwaggerUI deep Customization
1. Document frontend and backend Separation
2. Project Structure
3. Implement Area Division (module) to filter the Controller to be displayed
Document frontend and backend Separation
This article provides source code, download link: https://github.com/coderws/CustomSwagger (because the blog Park can only upload 10 MB, put it on github, do not ask for star, just for the convenience of everyone to download)
Because Swagger's original swagger page and resource js css files are embedded in the dll, although we can find the source code of swagger UI, it is still inconvenient to use. So I used sosoapi, another open-source project on github, and its documentation function is also based on swagger, but it must be extended for us, such as the ready-made switch between Chinese and English. In addition, resources are completely different from previous embedded resources, and a swagger UI folder, including js, css, images, html, and so on, is directly separated. In this way, we can easily modify it, you can achieve the customization you want, and I will go down the swagger background processing source code and add it to the solution. In the future, if you encounter problems, you no longer need to be troubled by the inability to modify the dll and add new functions. You can use swagger as part of your framework.
Project Structure
You can see Swashbuckle. Core. The following source code of swaggeris displayed in the test project. The docfolder in the project contains all the content of swaggerui. index.html is the homepage of our documents:
Implement Area (module) to filter the Controller to be displayed
Besides, make minor changes to Area grouping.
Required is highlighted in red
Increase the Swagger width to 1100px,
Add a module filter on the left. Click filter. Only the corresponding modules are displayed.
The specific implementation method is to filter the api access path based on your module name.
For example, the first user indicates the user module, and the second user indicates the Controller name. This definition uses the new features of MVC5, RouteAttribute and RoutePrefixAttribute. They are used to customize routes in the controller. You can download the source code to see them.
Where does the data on the left menu bar come from. See SwaggerConfig in the source code. I have defined this method:
/// <Summary> /// read the Controller description from the API documentation /// </summary> /// <returns> description of all controllers </returns> public static ConcurrentDictionary <string, string> GetControllerDesc (HashSet <string> moduleList) {string xmlpath = String. format ("{0}/bin/SwaggerCustom. test. XML ", AppDomain. currentDomain. baseDirectory); ConcurrentDictionary <string, string> controllerded8ict = new ConcurrentDictionary <string, string> (); if (File. exists (Xmlpath) {XmlDocument xmldoc = new XmlDocument (); xmldoc. load (xmlpath); string type = String. empty, path = String. empty, controllerName = String. empty; string [] arrPath; int length =-1, cCount = "Controller ". length; XmlNode summaryNode = null; foreach (XmlNode node in xmldoc. selectNodes ("// member") {type = node. attributes ["name"]. value; if (type. startsWith ("T:") {// controller arrPath = type. split ('. '); Length = arrPath. length; controllerName = arrPath [length-1]; if (controllerName. endsWith ("Controller") {// module information var moduleName = arrPath [length-2]; moduleList. add (moduleName); // get the Controller annotation summaryNode = node. selectSingleNode ("summary"); string key = controllerName. remove (controllerName. length-cCount, cCount); if (summaryNode! = Null &&! String. IsNullOrEmpty (summaryNode. InnerText )&&! Controllerdestcict. ContainsKey (key) {controllerdestcict. TryAdd (key, summaryNode. InnerText. Trim () ;}}} return controllerdestcict ;}
Originally, this method is only used to read Controller comments, but since xml is read here, I do not need to read it again. I added a HashSet <string> type parameter. The data of each element in the data set is unique. Therefore, we use it to store module information. Each time xml is traversed to the Controller, I will read the module information (for example, namespace SwaggerCustom. test. controllers. admin. adminRoleController), the second-to-last word is the module name. In this way, our module information is also included in json. Looking at areadeworkflow, he shows that I have three modules.
The next step is to screen the page before rendering. I first guessed that rendering must be related to returning the path (interface path) in json, so I searched for path in the swagger-ui-ext.js and finally found the result:
As shown in the following figure: By filtering the Module module, you can directly return the Module that does not meet your requirements without executing it down. The reason why I didn't perform deep optimization is that the real deep optimization should be filtered in the background code, and only the desired json results will be returned, so I am lazy.
Therefore, the result is filtered by clicking the Admin option. This module has only two controllers.
For my personal added js Code, in Doc/lib/swagger-custom.js.
// Obtain the Controller description function SwaggerCustom () {this. setControllerSummary = function () {$. ajax ({type: "get", async: true, url: $ ("# input_baseUrl "). val (), dataType: "json", success: function (data) {var summaryDict = data. controllerDesc; var id, controllerName, strSummary; $ ("# resources_container. resource "). each (function (I, item) {id = $ (item ). attr ("id"); if (id) {controllerName = id. substring (9); StrSummary = summaryDict [controllerName]; if (strSummary) {$ (item ). children (". heading "). children (". options "). prepend ('<li>) ;}}); swaggerCustom. loadMenu (data. areadegle); expendtoggle (); // register the menu contraction event}) ;}; // obtain the current parameter this. getQueryString = function (name) {var reg = new RegExp ("(^ | &)" + name + "= ([^ &] *) (& | $ )"); var r = window. location. search. substr (1 ). match (reg); if (r! = Null) return unescape (r [2]); return null ;}, this. loadMenu = function (modules) {var url = window. location. href; url = url. substring (0, url. lastIndexOf ('? '); $ ('Body '). prepend ('<div class = "menu-expender" id = "menuExpend"> modules </div> <div id = "moduleMenu"> <div onclick = "menuClick (this) "data-url =" '+ url + '? Module = all "" data-module = "all" class = "menu-inner"> all </div> '); var menuInner = ''; modules. forEach (function (item) {menuInner + = '<div onclick = "menuClick (this)" data-url = "' + url + '? Module = '+ item. toLowerCase () + '"data-module ="' + item. toLowerCase () + '"class =" menu-inner ">' + item + '</div>';}); $ ('# lelemenu '). append (menuInner); ('{lelemenu'}.css ("position", "fixed" }.css ("top", "20%") ;}} var swaggerCustom = new SwaggerCustom (); var swaggerCustomGlobalData = {currentModule: "all" }$ (function () {swaggerCustomGlobalData. currentModule = swaggerCustom. getQueryString ('mo Dule') = null? "All": swaggerCustom. getQueryString ('module'); // alert (swaggerCustomGlobalData. currentModule) ;}); var swaggerStyle ={ showActionLink: function () {$ ("li. toggleEndpointList ").css (" color "," #2392f7 ") ;}, titleStyle: function () {$ (" h2. toggleEndpointList ").css (" color "," green ") ;}, showDetailLink: function () {$ (" li. expandResource ").css ('color', '#996633');}, paramTable: function () {$ ('. fullwidth. parameters thead tr th: nth-child (1 )'). width ('50px '); $ ('. fullwidth. parameters thead tr th: nth-child (2 )'). width ('350px '); $ ('. fullwidth. parameters thead tr th: nth-child (3 )'). width ('100px '); $ ('. fullwidth. parameters thead tr th: nth-child (4 )'). width ('60px '); $ ('. fullwidth. parameters thead tr th: nth-child (5 )'). width ('400px '); $ ('td textarea '). width ('margin px');}, init: function () {this. showActionLink (); this. titleStyle (); this. showDetailLink (); // this. paramTable () ;}} function menuClick (ele) {window. location. href = (ele. dataset. url);} function expendtoggle () {$ ('# menuExpend '). toggle (function () {functions (this).html ('→'); $ ('# moduleMenu '). hide () ;}, function () {functions (this).html ('authorization'); $ ('# lelemenu '). show ();});}
How to use it ??
Directly copy the SwaggerConfig. cs and Doc files to your project, and reference Swashbuckle is okay (you can directly use the source code library or install it directly from nuget ). You must comply with the routing rules api/modulename/controller/action if you want to use the module partitioning function, because the module filtering is based on modulename. If you only want to use the basic functions of swagger, read the previous article. With the source code shared this time, you can modify the source code and customize your functions.
Conclusion
Forgive me for being the title party.
If my share is helpful to you, click the red button below to continue sharing. You can also like me. If you have any questions about the source code in this article, please leave a message.