基于 WebAPI 的 API 实现

本文基于

  • WebAPI 
  • OData (微软发起的一个格式标准,其中一个比较有意思的是可以直接在 Excel 中填入 API 就可以展示了)
  • Swashbuckle.OData(把 API 生成一个测试页面)

项目结构

 

代码

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

 1 public static class WebApiConfig
 2     {
 3         /// <summary>
 4         /// WebApiConfig Register
 5         /// </summary>
 6         /// <param name="config"></param>
 7         public static void Register(HttpConfiguration config)
 8         {
 9             ODataModelBuilder builder = new ODataConventionModelBuilder();
10             builder.EntitySet<UserModel>("Users");
11             config.MapODataServiceRoute(
12                 routeName: "ODataRoute",
13                 routePrefix: null,
14                 model: builder.GetEdmModel());
15         }
16     }
View Code
  • UsersController
 1 public class UsersController : ODataController
 2     {
 3         /// <summary>
 4         /// 查询用户
 5         /// </summary>
 6         /// <returns></returns>
 7         [EnableQuery]
 8         public List<UserModel> Get()
 9         {
10             return new List<UserModel>()
11             {
12                 new UserModel { Id = 1, Name = "Zhang San" },
13                 new UserModel { Id = 2, Name = "Li Si" }
14             };
15         }
16     }
View Code
  • AesourceDocumentation
 1 public class ApplyResourceDocumentation : IDocumentFilter
 2     {
 3         /// <summary>
 4         /// Apply
 5         /// </summary>
 6         /// <param name="swaggerDoc"></param>
 7         /// <param name="schemaRegistry"></param>
 8         /// <param name="apiExplorer"></param>
 9         public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
10         {
11             swaggerDoc.tags = new List<Tag>
12             {
13                 new Tag { name = "Users", description = "a RESTier resource" }
14             };
15         }
16     }
View Code
  • UserModelMap

 1 public class UserModelMap : EntityTypeConfiguration<UserModel>
 2     {
 3         /// <summary>
 4         /// UserModelMap
 5         /// </summary>
 6         public UserModelMap()
 7         {
 8             //this.ToTable("dbo.User");
 9             this.HasKey(u => u.Id);
10 
11             this.Property(u => u.Name).IsRequired();
12         }
13     }
View Code
  • UserModel

 1 public class UserModel
 2     {
 3         /// <summary>
 4         /// User Id
 5         /// </summary>
 6         public int Id { get; set; }
 7         /// <summary>
 8         /// User Name
 9         /// </summary>
10         public string Name { get; set; }
11     }
View Code
  • EfContext

 1 public class EfContext : DbContext
 2     {
 3         /// <summary>
 4         /// Users
 5         /// </summary>
 6         public DbSet<UserModel> Users { get; set; }
 7 
 8         /// <summary>
 9         /// EfContext ctor
10         /// </summary>
11         public EfContext()
12             : base("name=EfContext")
13         {
14         }
15 
16         /// <summary>
17         /// This method is called when the model for a derived context has been initialized, but
18         ///             before the model has been locked down and used to initialize the context.  The default
19         ///             implementation of this method does nothing, but it can be overridden in a derived class
20         ///             such that the model can be further configured before it is locked down.
21         /// </summary>
22         /// <remarks>
23         /// Typically, this method is called only once when the first instance of a derived context
24         ///             is created.  The model for that context is then cached and is for all further instances of
25         ///             the context in the app domain.  This caching can be disabled by setting the ModelCaching
26         ///             property on the given ModelBuidler, but note that this can seriously degrade performance.
27         ///             More control over caching is provided through use of the DbModelBuilder and DbContextFactory
28         ///             classes directly.
29         /// </remarks>
30         /// <param name="modelBuilder">The builder that defines the model for the context being created. </param>
31         protected override void OnModelCreating(DbModelBuilder modelBuilder)
32         {
33             base.OnModelCreating(modelBuilder);
34 
35             modelBuilder.Configurations.Add(new UserModelMap());
36         }
37     }
View Code

Tips:

  • 53515 是项目设置 Web 选项里的端口号,具体请查询真实的端口号
  • 勾选项目设置 Build 选项里的XML documentation file,因为 Swagger 会用 xml 里的注释作为说明,请把代码中的 /// 注释补全,这样才能生成说明

       

运行结果

由于测试直接返回的固定数据,所以,当运行后就可以通过 API 得到结果了,并且可以通过 Swagger 测试页面看到 API 的信息,并可以测试。

此例中的 API 为

http://localhost:53515/Users?$orderby=Id desc  (请求的 API)

http://localhost:53515/swagger/ui/index#/  (Swagger 生成的测试页面)

 

posted @ 2016-07-28 16:29  Blue-G  阅读(2411)  评论(0编辑  收藏  举报