Skip to content

Commit b52bd0e

Browse files
author
Chris Martinez
committed
Minor refactoring to the Web API implementation, which now includes a Swagger example
1 parent d84833a commit b52bd0e

32 files changed

+1479
-154
lines changed

ApiVersioningWithSamples.sln

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio 15
4-
VisualStudioVersion = 15.0.26228.9
4+
VisualStudioVersion = 15.0.26228.10
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4D5F5F21-0CB7-4B4E-A42F-732BD4AFD0FF}"
77
EndProject
@@ -86,6 +86,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Ve
8686
EndProject
8787
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SwaggerSample", "samples\aspnetcore\SwaggerSample\SwaggerSample.csproj", "{D95BC932-50F7-4014-970E-0C6E8400BE25}"
8888
EndProject
89+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SwaggerWebApiSample", "samples\webapi\SwaggerWebApiSample\SwaggerWebApiSample.csproj", "{6BEDE228-4BE9-499E-B1E6-93B6B0AC62DA}"
90+
EndProject
8991
Global
9092
GlobalSection(SharedMSBuildProjectFiles) = preSolution
9193
test\Acceptance.Test.Shared\Acceptance.Test.Shared.projitems*{6cdfb878-2642-4f98-ae35-621bac581181}*SharedItemsImports = 13
@@ -186,6 +188,10 @@ Global
186188
{D95BC932-50F7-4014-970E-0C6E8400BE25}.Debug|Any CPU.Build.0 = Debug|Any CPU
187189
{D95BC932-50F7-4014-970E-0C6E8400BE25}.Release|Any CPU.ActiveCfg = Release|Any CPU
188190
{D95BC932-50F7-4014-970E-0C6E8400BE25}.Release|Any CPU.Build.0 = Release|Any CPU
191+
{6BEDE228-4BE9-499E-B1E6-93B6B0AC62DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
192+
{6BEDE228-4BE9-499E-B1E6-93B6B0AC62DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
193+
{6BEDE228-4BE9-499E-B1E6-93B6B0AC62DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
194+
{6BEDE228-4BE9-499E-B1E6-93B6B0AC62DA}.Release|Any CPU.Build.0 = Release|Any CPU
189195
EndGlobalSection
190196
GlobalSection(SolutionProperties) = preSolution
191197
HideSolutionNode = FALSE
@@ -219,5 +225,6 @@ Global
219225
{F7784C3A-5569-4590-AE28-B721C0426045} = {4D5F5F21-0CB7-4B4E-A42F-732BD4AFD0FF}
220226
{15461DBB-95AD-4CA7-AF41-E70F54860FE3} = {0987757E-4D09-4523-B9C9-65B1E8832AA1}
221227
{D95BC932-50F7-4014-970E-0C6E8400BE25} = {900DD210-8500-4D89-A05D-C9526935A719}
228+
{6BEDE228-4BE9-499E-B1E6-93B6B0AC62DA} = {F446ED94-368F-4F67-913B-16E82CA80DFC}
222229
EndGlobalSection
223230
EndGlobal
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
namespace Microsoft.Examples
2+
{
3+
using Microsoft.Web.Http.Description;
4+
using Swashbuckle.Swagger;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Web.Http.Description;
8+
9+
/// <summary>
10+
/// Represents the Swagger/Swashbuckle operation filter used to document the implicit API version parameter.
11+
/// </summary>
12+
public class ImplicitApiVersionParameter : IOperationFilter
13+
{
14+
/// <summary>
15+
/// Applies the filter to the specified operation using the given context.
16+
/// </summary>
17+
/// <param name="operation">The operation to apply the filter to.</param>
18+
/// <param name="schemaRegistry">The API schema registry.</param>
19+
/// <param name="apiDescription">The API description being filtered.</param>
20+
public void Apply( Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription )
21+
{
22+
var description = apiDescription as VersionedApiDescription;
23+
24+
// if the api explorer did not capture an API version for this operation
25+
// then the action must be API version-neutral; there's nothing to add
26+
if ( description?.ApiVersion == null )
27+
{
28+
return;
29+
}
30+
31+
var parameters = operation.parameters;
32+
33+
if ( parameters == null )
34+
{
35+
operation.parameters = parameters = new List<Parameter>();
36+
}
37+
38+
// note: in most applications, service authors will choose a single, consistent
39+
// approach to how API versioning is applied. this sample uses a:
40+
//
41+
// 1. query string parameter method with the name "api-version"
42+
// 2. url path segement with the route parameter name "api-version"
43+
//
44+
// unless you allow multiple API versioning methods in your application,
45+
// your implementation should be even simpler.
46+
47+
// consider the url path segment parameter first
48+
var parameter = parameters.SingleOrDefault( p => p.name == "api-version" );
49+
50+
if ( parameter == null )
51+
{
52+
// the only other method in this sample is by query string
53+
parameter = new Parameter()
54+
{
55+
name = "api-version",
56+
required = true,
57+
description = "The requested API version",
58+
@in = "query",
59+
type = "string"
60+
};
61+
62+
parameters.Add( parameter );
63+
}
64+
65+
// update the default value with the current API version so that
66+
// the route can be invoked in the "Try It!" feature
67+
parameter.@default = description.ApiVersion.ToString();
68+
}
69+
}
70+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle( "SwaggerWebApiSample" )]
9+
[assembly: AssemblyDescription( "" )]
10+
[assembly: AssemblyConfiguration( "" )]
11+
[assembly: AssemblyCompany( "" )]
12+
[assembly: AssemblyProduct( "SwaggerWebApiSample" )]
13+
[assembly: AssemblyCopyright( "Copyright © 2017" )]
14+
[assembly: AssemblyTrademark( "" )]
15+
[assembly: AssemblyCulture( "" )]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible( false )]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid( "6bede228-4be9-499e-b1e6-93b6b0ac62da" )]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Revision and Build Numbers
33+
// by using the '*' as shown below:
34+
[assembly: AssemblyVersion( "1.0.0.0" )]
35+
[assembly: AssemblyFileVersion( "1.0.0.0" )]
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
[assembly: Microsoft.Owin.OwinStartup( typeof( Microsoft.Examples.Startup ) )]
2+
3+
namespace Microsoft.Examples
4+
{
5+
using global::Owin;
6+
using Microsoft.Web.Http.Routing;
7+
using Swashbuckle.Application;
8+
using System.IO;
9+
using System.Reflection;
10+
using System.Web.Http;
11+
using System.Web.Http.Description;
12+
using System.Web.Http.Routing;
13+
14+
/// <summary>
15+
/// Represents the startup process for the application.
16+
/// </summary>
17+
public class Startup
18+
{
19+
/// <summary>
20+
/// Configures the application using the provided builder.
21+
/// </summary>
22+
/// <param name="builder">The current application builder.</param>
23+
public void Configuration( IAppBuilder builder )
24+
{
25+
// we only need to change the default constraint resolver for services that want urls with versioning like: ~/v{version}/{controller}
26+
var constraintResolver = new DefaultInlineConstraintResolver() { ConstraintMap = { ["apiVersion"] = typeof( ApiVersionRouteConstraint ) } };
27+
var configuration = new HttpConfiguration();
28+
var httpServer = new HttpServer( configuration );
29+
30+
// reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions"
31+
configuration.AddApiVersioning( o => o.ReportApiVersions = true );
32+
configuration.MapHttpAttributeRoutes( constraintResolver );
33+
34+
// add the versioned IApiExplorer and capture the strongly-typed implementation (e.g. VersionedApiExplorer vs IApiExplorer)
35+
var apiExplorer = configuration.AddVersionedApiExplorer();
36+
37+
configuration.EnableSwagger(
38+
"{apiVersion}/swagger",
39+
swagger =>
40+
{
41+
// build a swagger document and endpoint for each discovered API version
42+
swagger.MultipleApiVersions(
43+
( apiDescription, version ) => apiDescription.GetGroupName() == version,
44+
info =>
45+
{
46+
foreach ( var group in apiExplorer.ApiDescriptions )
47+
{
48+
var apiVersion = group.ApiVersion;
49+
var description = "A sample application with Swagger, Swashbuckle, and API versioning.";
50+
51+
if ( group.IsDeprecated )
52+
{
53+
description += " This API version has been deprecated.";
54+
}
55+
56+
info.Version( apiExplorer.GetGroupName( apiVersion ), $"Sample API {apiVersion}" )
57+
.Contact( c => c.Name( "Bill Mei" ).Email( "[email protected]" ) )
58+
.Description( description )
59+
.License( l => l.Name( "MIT" ).Url( "https://opensource.org/licenses/MIT" ) )
60+
.TermsOfService( "Shareware" );
61+
}
62+
} );
63+
64+
65+
// add a custom operation filter which documents the implicit API version parameter
66+
swagger.OperationFilter<ImplicitApiVersionParameter>();
67+
68+
// integrate xml comments
69+
swagger.IncludeXmlComments( XmlCommentsFilePath );
70+
} )
71+
.EnableSwaggerUi( swagger => swagger.EnableDiscoveryUrlSelector() );
72+
73+
builder.UseWebApi( httpServer );
74+
}
75+
76+
static string XmlCommentsFilePath
77+
{
78+
get
79+
{
80+
var basePath = System.AppDomain.CurrentDomain.RelativeSearchPath;
81+
var fileName = typeof( Startup ).GetTypeInfo().Assembly.GetName().Name + ".xml";
82+
return Path.Combine( basePath, fileName );
83+
}
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)