C# 在Windform程序中搭建Webapi

1. 在NuGet引用owin

Microsoft.AspNet.WebApi.Owin
Microsoft.AspNet.WebApi.OwinSelfHost
Microsoft.Owin.StaticFiles
2. 添加服务启动配置类 Startup

 1 using WebapiTest.App_Start;
 2 using Microsoft.Owin.FileSystems;
 3 using Microsoft.Owin.StaticFiles;
 4 using Owin;
 5 using System;
 6 using System.Collections.Generic;
 7 using System.Linq;
 8 using System.Text;
 9 using System.Threading.Tasks;
10 using System.Web.Http;
11 
12 namespace WebapiTest
13 {
14     public class Startup
15     {
16         public void Configuration(IAppBuilder appBuilder)
17         {
18             // 创建 Web API 的配置
19             var config = new HttpConfiguration();
20             // 启用标记路由
21             config.MapHttpAttributeRoutes();
22             // 默认的 Web API 路由
23             config.Routes.MapHttpRoute(
24                 name: "DefaultApi",
25                 routeTemplate: "api/{controller}/{id}",
26                 defaults: new { id = RouteParameter.Optional }
27             );
28 
29             FormatterConfig.Configure(config);
30             SwaggerConfig.Register(config);
31             FilterConfig.Register(config);
32 
33             var physicalFileSystem = new PhysicalFileSystem(@".\Web"); //静态网站根目录
34             var options = new FileServerOptions
35             {
36                 EnableDefaultFiles = true,
37                 FileSystem = physicalFileSystem
38             };
39             options.StaticFileOptions.FileSystem = physicalFileSystem;
40             options.StaticFileOptions.ServeUnknownFileTypes = true;
41             options.StaticFileOptions.DefaultContentType = "text/plain";
42             options.DefaultFilesOptions.DefaultFileNames = new[] { "Index.html" }; //默认页面(填写与静态网站根目录的相对路径)
43             appBuilder.UseFileServer(options);
44 
45             // 将路由配置附加到 appBuilder
46             appBuilder.UseWebApi(config);
47         }
48     }
49 }

3. 添加 Controllers 目录,创建 QueryController Web服务类

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Web.Http;
 7 
 8 namespace WebapiTest.Controllers
 9 {
10  
11         public class QueryController : ApiController
12         {
13             //// GET api
14             //[HttpGet]
15             //public IHttpActionResult Json(string id)
16             //{
17             //    return Json($"hello123:{id}");
18             //}
19 
20             // GET api
21             public string Get(string id)
22             {
23                 return "hello:" + id;
24             }
25             // POST api
26             public string Post([FromBody] string value)
27             {
28                 return value;
29             }
30             // PUT api
31             public void Put(int id, string value)
32             {
33             }
34             // DELETE api
35             public void Delete(int id)
36             {
37             }
38         }
39 
40    
41 }

4. 在程序中调用如下代码启动Web服务

// 打开Web服务
var server = WebApp.Start<Startup>(url: "http://localhost:9099/");

// 停止Web服务
server.Dispose();
server = null;

5. 在生成的文件目录,创建Web文件夹,放入静态Web资源(index.html)

6. 访问Web资源
浏览器访问静态资源 http://localhost:9099/ 
浏览器访问WebApi  http://localhost:9099/api/Query/123

7.在项目中加入:swagger,安装Swashbuckle   (补充如果是.net core api请安装Sawshbuckle aspnetcore)

 8、打开项目App_Start文件夹,修改SwaggerConfig.cs配置文件

  1 using System.Web.Http;
  2 using WebActivatorEx;
  3 using WebapiTest;
  4 using Swashbuckle.Application;
  5 using System.Reflection;
  6 using System;
  7 using WebapiTest.App_Start;
  8 
  9 [assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")]
 10 
 11 namespace WebapiTest.App_Start
 12 {
 13     public class SwaggerConfig
 14     {
 15         private static string GetXmlDocumentsPath()
 16         {
 17             var path =
 18              $"{AppDomain.CurrentDomain.BaseDirectory}\\{Assembly.GetExecutingAssembly().GetName().Name}.XML";
 19           
 20 
 21             return path;
 22         }
 23 
 24         private static string GetXmlCommentsPath()
 25         {
 26             var path = $"{AppDomain.CurrentDomain.BaseDirectory}\\{Assembly.GetExecutingAssembly().GetName().Name}.XML";
 27 
 28             //$"{AppDomain.CurrentDomain.BaseDirectory}HellerDataManagerService.XML";
 29 
 30             return path;
 31         }
 32 
 33         public static void Register(HttpConfiguration configuration)
 34         {
 35 
 36             var thisAssembly = typeof(SwaggerConfig).Assembly;
 37 
 38             configuration
 39                 .EnableSwagger(c =>
 40                     {
 41                         // By default, the service root url is inferred from the request used to access the docs.
 42                         // However, there may be situations (e.g. proxy and load-balanced environments) where this does not
 43                         // resolve correctly. You can workaround this by providing your own code to determine the root URL.
 44                         //
 45                         //c.RootUrl(req => GetRootUrlFromAppConfig());
 46 
 47                         // If schemes are not explicitly provided in a Swagger 2.0 document, then the scheme used to access
 48                         // the docs is taken as the default. If your API supports multiple schemes and you want to be explicit
 49                         // about them, you can use the "Schemes" option as shown below.
 50                         //
 51                         //c.Schemes(new[] { "http", "https" });
 52 
 53                         // Use "SingleApiVersion" to describe a single version API. Swagger 2.0 includes an "Info" object to
 54                         // hold additional metadata for an API. Version and title are required but you can also provide
 55                         // additional fields by chaining methods off SingleApiVersion.
 56                         //
 57                         c.SingleApiVersion("v1", "我的在线说明");
 58                         c.IncludeXmlComments(GetXmlDocumentsPath());
 59                         c.IncludeXmlComments(GetXmlCommentsPath());
 60                         // If you want the output Swagger docs to be indented properly, enable the "PrettyPrint" option.
 61                         //
 62                         //c.PrettyPrint();
 63 
 64                         // If your API has multiple versions, use "MultipleApiVersions" instead of "SingleApiVersion".
 65                         // In this case, you must provide a lambda that tells Swashbuckle which actions should be
 66                         // included in the docs for a given API version. Like "SingleApiVersion", each call to "Version"
 67                         // returns an "Info" builder so you can provide additional metadata per API version.
 68                         //
 69                         //c.MultipleApiVersions(
 70                         //    (apiDesc, targetApiVersion) => ResolveVersionSupportByRouteConstraint(apiDesc, targetApiVersion),
 71                         //    (vc) =>
 72                         //    {
 73                         //        vc.Version("v2", "Swashbuckle Dummy API V2");
 74                         //        vc.Version("v1", "Swashbuckle Dummy API V1");
 75                         //    });
 76 
 77                         // You can use "BasicAuth", "ApiKey" or "OAuth2" options to describe security schemes for the API.
 78                         // See https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md for more details.
 79                         // NOTE: These only define the schemes and need to be coupled with a corresponding "security" property
 80                         // at the document or operation level to indicate which schemes are required for an operation. To do this,
 81                         // you'll need to implement a custom IDocumentFilter and/or IOperationFilter to set these properties
 82                         // according to your specific authorization implementation
 83                         //
 84                         //c.BasicAuth("basic")
 85                         //    .Description("Basic HTTP Authentication");
 86                         //
 87                         // NOTE: You must also configure 'EnableApiKeySupport' below in the SwaggerUI section
 88                         //c.ApiKey("apiKey")
 89                         //    .Description("API Key Authentication")
 90                         //    .Name("apiKey")
 91                         //    .In("header");
 92                         //
 93                         //c.OAuth2("oauth2")
 94                         //    .Description("OAuth2 Implicit Grant")
 95                         //    .Flow("implicit")
 96                         //    .AuthorizationUrl("http://petstore.swagger.wordnik.com/api/oauth/dialog")
 97                         //    //.TokenUrl("https://tempuri.org/token")
 98                         //    .Scopes(scopes =>
 99                         //    {
100                         //        scopes.Add("read", "Read access to protected resources");
101                         //        scopes.Add("write", "Write access to protected resources");
102                         //    });
103 
104                         // Set this flag to omit descriptions for any actions decorated with the Obsolete attribute
105                         //c.IgnoreObsoleteActions();
106 
107                         // Each operation be assigned one or more tags which are then used by consumers for various reasons.
108                         // For example, the swagger-ui groups operations according to the first tag of each operation.
109                         // By default, this will be controller name but you can use the "GroupActionsBy" option to
110                         // override with any value.
111                         //
112                         //c.GroupActionsBy(apiDesc => apiDesc.HttpMethod.ToString());
113 
114                         // You can also specify a custom sort order for groups (as defined by "GroupActionsBy") to dictate
115                         // the order in which operations are listed. For example, if the default grouping is in place
116                         // (controller name) and you specify a descending alphabetic sort order, then actions from a
117                         // ProductsController will be listed before those from a CustomersController. This is typically
118                         // used to customize the order of groupings in the swagger-ui.
119                         //
120                         //c.OrderActionGroupsBy(new DescendingAlphabeticComparer());
121 
122                         // If you annotate Controllers and API Types with
123                         // Xml comments (http://msdn.microsoft.com/en-us/library/b2s063f7(v=vs.110).aspx), you can incorporate
124                         // those comments into the generated docs and UI. You can enable this by providing the path to one or
125                         // more Xml comment files.
126                         //
127                         //c.IncludeXmlComments(GetXmlCommentsPath());
128 
129                         // Swashbuckle makes a best attempt at generating Swagger compliant JSON schemas for the various types
130                         // exposed in your API. However, there may be occasions when more control of the output is needed.
131                         // This is supported through the "MapType" and "SchemaFilter" options:
132                         //
133                         // Use the "MapType" option to override the Schema generation for a specific type.
134                         // It should be noted that the resulting Schema will be placed "inline" for any applicable Operations.
135                         // While Swagger 2.0 supports inline definitions for "all" Schema types, the swagger-ui tool does not.
136                         // It expects "complex" Schemas to be defined separately and referenced. For this reason, you should only
137                         // use the "MapType" option when the resulting Schema is a primitive or array type. If you need to alter a
138                         // complex Schema, use a Schema filter.
139                         //
140                         //c.MapType<ProductType>(() => new Schema { type = "integer", format = "int32" });
141 
142                         // If you want to post-modify "complex" Schemas once they've been generated, across the board or for a
143                         // specific type, you can wire up one or more Schema filters.
144                         //
145                         //c.SchemaFilter<ApplySchemaVendorExtensions>();
146 
147                         // In a Swagger 2.0 document, complex types are typically declared globally and referenced by unique
148                         // Schema Id. By default, Swashbuckle does NOT use the full type name in Schema Ids. In most cases, this
149                         // works well because it prevents the "implementation detail" of type namespaces from leaking into your
150                         // Swagger docs and UI. However, if you have multiple types in your API with the same class name, you'll
151                         // need to opt out of this behavior to avoid Schema Id conflicts.
152                         //
153                         //c.UseFullTypeNameInSchemaIds();
154 
155                         // Alternatively, you can provide your own custom strategy for inferring SchemaId's for
156                         // describing "complex" types in your API.
157                         //
158                         //c.SchemaId(t => t.FullName.Contains('`') ? t.FullName.Substring(0, t.FullName.IndexOf('`')) : t.FullName);
159 
160                         // Set this flag to omit schema property descriptions for any type properties decorated with the
161                         // Obsolete attribute
162                         //c.IgnoreObsoleteProperties();
163 
164                         // In accordance with the built in JsonSerializer, Swashbuckle will, by default, describe enums as integers.
165                         // You can change the serializer behavior by configuring the StringToEnumConverter globally or for a given
166                         // enum type. Swashbuckle will honor this change out-of-the-box. However, if you use a different
167                         // approach to serialize enums as strings, you can also force Swashbuckle to describe them as strings.
168                         //
169                         //c.DescribeAllEnumsAsStrings();
170 
171                         // Similar to Schema filters, Swashbuckle also supports Operation and Document filters:
172                         //
173                         // Post-modify Operation descriptions once they've been generated by wiring up one or more
174                         // Operation filters.
175                         //
176                         //c.OperationFilter<AddDefaultResponse>();
177                         //
178                         // If you've defined an OAuth2 flow as described above, you could use a custom filter
179                         // to inspect some attribute on each action and infer which (if any) OAuth2 scopes are required
180                         // to execute the operation
181                         //
182                         //c.OperationFilter<AssignOAuth2SecurityRequirements>();
183 
184                         // Post-modify the entire Swagger document by wiring up one or more Document filters.
185                         // This gives full control to modify the final SwaggerDocument. You should have a good understanding of
186                         // the Swagger 2.0 spec. - https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md
187                         // before using this option.
188                         //
189                         //c.DocumentFilter<ApplyDocumentVendorExtensions>();
190 
191                         // In contrast to WebApi, Swagger 2.0 does not include the query string component when mapping a URL
192                         // to an action. As a result, Swashbuckle will raise an exception if it encounters multiple actions
193                         // with the same path (sans query string) and HTTP method. You can workaround this by providing a
194                         // custom strategy to pick a winner or merge the descriptions for the purposes of the Swagger docs
195                         //
196                         //c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
197 
198                         // Wrap the default SwaggerGenerator with additional behavior (e.g. caching) or provide an
199                         // alternative implementation for ISwaggerProvider with the CustomProvider option.
200                         //
201                         //c.CustomProvider((defaultProvider) => new CachingSwaggerProvider(defaultProvider));
202                     })
203                 .EnableSwaggerUi(c =>
204                     {
205                         // Use the "DocumentTitle" option to change the Document title.
206                         // Very helpful when you have multiple Swagger pages open, to tell them apart.
207                         //
208                         //c.DocumentTitle("My Swagger UI");
209 
210                         // Use the "InjectStylesheet" option to enrich the UI with one or more additional CSS stylesheets.
211                         // The file must be included in your project as an "Embedded Resource", and then the resource's
212                         // "Logical Name" is passed to the method as shown below.
213                         //
214                         //c.InjectStylesheet(containingAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testStyles1.css");
215 
216                         // Use the "InjectJavaScript" option to invoke one or more custom JavaScripts after the swagger-ui
217                         // has loaded. The file must be included in your project as an "Embedded Resource", and then the resource's
218                         // "Logical Name" is passed to the method as shown above.
219                         //
220                         //c.InjectJavaScript(thisAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testScript1.js");
221 
222                         // The swagger-ui renders boolean data types as a dropdown. By default, it provides "true" and "false"
223                         // strings as the possible choices. You can use this option to change these to something else,
224                         // for example 0 and 1.
225                         //
226                         //c.BooleanValues(new[] { "0", "1" });
227 
228                         // By default, swagger-ui will validate specs against swagger.io's online validator and display the result
229                         // in a badge at the bottom of the page. Use these options to set a different validator URL or to disable the
230                         // feature entirely.
231                         //c.SetValidatorUrl("http://localhost/validator");
232                         //c.DisableValidator();
233 
234                         // Use this option to control how the Operation listing is displayed.
235                         // It can be set to "None" (default), "List" (shows operations for each resource),
236                         // or "Full" (fully expanded: shows operations and their details).
237                         //
238                         //c.DocExpansion(DocExpansion.List);
239 
240                         // Specify which HTTP operations will have the 'Try it out!' option. An empty paramter list disables
241                         // it for all operations.
242                         //
243                         //c.SupportedSubmitMethods("GET", "HEAD");
244 
245                         // Use the CustomAsset option to provide your own version of assets used in the swagger-ui.
246                         // It's typically used to instruct Swashbuckle to return your version instead of the default
247                         // when a request is made for "index.html". As with all custom content, the file must be included
248                         // in your project as an "Embedded Resource", and then the resource's "Logical Name" is passed to
249                         // the method as shown below.
250                         //
251                         //c.CustomAsset("index", containingAssembly, "YourWebApiProject.SwaggerExtensions.index.html");
252 
253                         // If your API has multiple versions and you've applied the MultipleApiVersions setting
254                         // as described above, you can also enable a select box in the swagger-ui, that displays
255                         // a discovery URL for each version. This provides a convenient way for users to browse documentation
256                         // for different API versions.
257                         //
258                         //c.EnableDiscoveryUrlSelector();
259 
260                         // If your API supports the OAuth2 Implicit flow, and you've described it correctly, according to
261                         // the Swagger 2.0 specification, you can enable UI support as shown below.
262                         //
263                         //c.EnableOAuth2Support(
264                         //    clientId: "test-client-id",
265                         //    clientSecret: null,
266                         //    realm: "test-realm",
267                         //    appName: "Swagger UI"
268                         //    //additionalQueryStringParams: new Dictionary<string, string>() { { "foo", "bar" } }
269                         //);
270 
271                         // If your API supports ApiKey, you can override the default values.
272                         // "apiKeyIn" can either be "query" or "header"
273                         //
274                         //c.EnableApiKeySupport("apiKey", "header");
275                         
276                     });
277         }
278     }
279 }

9、创建项目xml注释文档

右键项目→属性→生成→选中下方的 "XML文档文件" 然后保存 

 

 10、启动webapi,然后在接口地址后面输入 /swagger   (默认是英文的,如果需要中文显示  还需要做汉化处理)

 

11.汉化:(可以不做)

在App_Start文件夹中添加SwaggerControllerDescProvider.cs

 1 using Swashbuckle.Swagger;
 2 using System;
 3 using System.Collections.Concurrent;
 4 using System.Collections.Generic;
 5 using System.IO;
 6 using System.Linq;
 7 using System.Text;
 8 using System.Threading.Tasks;
 9 using System.Xml;
10 
11 namespace WebapiTest.App_Start
12 {
13     /// <summary>
14     /// swagger显示控制器的描述
15     /// </summary>
16     public class SwaggerControllerDescProvider : ISwaggerProvider
17     {
18         private readonly ISwaggerProvider _swaggerProvider;
19         private static ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>();
20         private readonly string _xml;
21         /// <summary>
22         /// 
23         /// </summary>
24         /// <param name="swaggerProvider"></param>
25         /// <param name="xml">xml文档路径</param>
26         public SwaggerControllerDescProvider(ISwaggerProvider swaggerProvider, string xml)
27         {
28             _swaggerProvider = swaggerProvider;
29             _xml = xml;
30         }
31 
32         public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
33         {
34             var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion);
35             SwaggerDocument srcDoc = null;
36             //只读取一次
37             if (!_cache.TryGetValue(cacheKey, out srcDoc))
38             {
39                 srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion);
40 
41                 srcDoc.vendorExtensions = new Dictionary<string, object> { { "ControllerDesc", GetControllerDesc() } };
42                 _cache.TryAdd(cacheKey, srcDoc);
43             }
44             return srcDoc;
45         }
46 
47         /// <summary>
48         /// 从API文档中读取控制器描述
49         /// </summary>
50         /// <returns>所有控制器描述</returns>
51         public ConcurrentDictionary<string, string> GetControllerDesc()
52         {
53             string xmlpath = _xml;
54             ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>();
55             if (File.Exists(xmlpath))
56             {
57                 XmlDocument xmldoc = new XmlDocument();
58                 xmldoc.Load(xmlpath);
59                 string type = string.Empty, path = string.Empty, controllerName = string.Empty;
60 
61                 string[] arrPath;
62                 int length = -1, cCount = "Controller".Length;
63                 XmlNode summaryNode = null;
64                 foreach (XmlNode node in xmldoc.SelectNodes("//member"))
65                 {
66                     type = node.Attributes["name"].Value;
67                     if (type.StartsWith("T:"))
68                     {
69                         //控制器
70                         arrPath = type.Split('.');
71                         length = arrPath.Length;
72                         controllerName = arrPath[length - 1];
73                         if (controllerName.EndsWith("Controller"))
74                         {
75                             //获取控制器注释
76                             summaryNode = node.SelectSingleNode("summary");
77                             string key = controllerName.Remove(controllerName.Length - cCount, cCount);
78                             if (summaryNode != null && !string.IsNullOrEmpty(summaryNode.InnerText) && !controllerDescDict.ContainsKey(key))
79                             {
80                                 controllerDescDict.TryAdd(key, summaryNode.InnerText.Trim());
81                             }
82                         }
83                     }
84                 }
85             }
86             return controllerDescDict;
87         }
88     }
89 }

(2).添加Swagger.Net和Swagger.Net.UI 程序nuget引用

  (3).如果没有SwaggerNet.cs文件则添加:

 1 using Swagger.Net;
 2 using System;
 3 using System.IO;
 4 using System.Web;
 5 using System.Web.Http;
 6 using System.Web.Http.Description;
 7 using System.Web.Routing;
 8 
 9 [assembly: WebActivator.PreApplicationStartMethod(typeof(WebapiTest.App_Start.SwaggerNet), "PreStart")]
10 [assembly: WebActivator.PostApplicationStartMethod(typeof(WebapiTest.App_Start.SwaggerNet), "PostStart")]
11 namespace WebapiTest.App_Start
12 {
13     public static class SwaggerNet 
14     {
15         public static void PreStart() 
16         {
17             RouteTable.Routes.MapHttpRoute(
18                 name: "SwaggerApi",
19                 routeTemplate: "api/docs/{controller}",
20                 defaults: new { swagger = true }
21             );            
22         }
23         
24         public static void PostStart() 
25         {
26             var config = GlobalConfiguration.Configuration;
27 
28             config.Filters.Add(new SwaggerActionFilter());
29             
30             try
31             {
32                 config.Services.Replace(typeof(IDocumentationProvider),
33                     new XmlCommentDocumentationProvider(HttpContext.Current.Server.MapPath("~/bin/WebapiTest.XML")));
34             }
35             catch (FileNotFoundException)
36             {
37                 throw new Exception("Please enable \"XML documentation file\" in project properties with default (bin\\WebapiTest.XML) value or edit value in App_Start\\SwaggerNet.cs");
38             }
39         }
40     }
41 }

 

 

 

 

posted @ 2024-12-10 22:14  小码哥-风云  阅读(1)  评论(0编辑  收藏  举报