1+ namespace ApiVersioning . Examples ;
2+
3+ using Asp . Versioning ;
4+ using Asp . Versioning . Conventions ;
5+ using Microsoft . AspNet . OData . Extensions ;
6+ using Microsoft . OData ;
7+ using Newtonsoft . Json . Serialization ;
8+ using Owin ;
9+ using Swashbuckle . Application ;
10+ using System . IO ;
11+ using System . Reflection ;
12+ using System . Text ;
13+ using System . Web . Http ;
14+ using System . Web . Http . Description ;
15+ using static Microsoft . AspNet . OData . Query . AllowedQueryOptions ;
16+
17+ /// <summary>
18+ /// Represents the startup process for the application.
19+ /// </summary>
20+ public class Startup
21+ {
22+ /// <summary>
23+ /// Configures the application using the provided builder.
24+ /// </summary>
25+ /// <param name="builder">The current application builder.</param>
26+ public void Configuration ( IAppBuilder builder )
27+ {
28+ var configuration = new HttpConfiguration ( ) ;
29+ var httpServer = new HttpServer ( configuration ) ;
30+
31+ // note: this example application intentionally only illustrates the
32+ // bare minimum configuration for OpenAPI with partial OData support.
33+ // see the OpenAPI or OData OpenAPI examples for additional options.
34+
35+ configuration . EnableDependencyInjection ( ) ;
36+ configuration . Select ( ) ;
37+ configuration . AddApiVersioning ( ) ;
38+
39+ // note: this is required to make the default swagger json
40+ // settings match the odata conventions applied by EnableLowerCamelCase()
41+ configuration . Formatters . JsonFormatter . SerializerSettings . ContractResolver =
42+ new CamelCasePropertyNamesContractResolver ( ) ;
43+
44+ // NOTE: when you mix OData and non-Data controllers in Web API, it's RECOMMENDED to only use
45+ // convention-based routing. using attribute routing may not work as expected due to limitations
46+ // in the underlying routing system. the order of route registration is important as well.
47+ //
48+ // for example:
49+ //
50+ // configuration.MapVersionedODataRoute( "odata", "api", modelBuilder );
51+ // configuration.Routes.MapHttpRoute( "Default", "api/{controller}/{id}", new { id = RouteParameter.Optional } );
52+ //
53+ // for more information see the advanced OData example
54+ configuration . MapHttpAttributeRoutes ( ) ;
55+
56+ // add the versioned IApiExplorer and capture the strongly-typed implementation (e.g. ODataApiExplorer vs IApiExplorer)
57+ // note: the specified format code will format the version as "'v'major[.minor][-status]"
58+ var apiExplorer = configuration . AddODataApiExplorer (
59+ options =>
60+ {
61+ // add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
62+ // note: the specified format code will format the version as "'v'major[.minor][-status]"
63+ options . GroupNameFormat = "'v'VVV" ;
64+
65+ // configure query options (which cannot otherwise be configured by OData conventions)
66+ options . QueryOptions . Controller < BooksController > ( )
67+ . Action ( c => c . Get ( default ) )
68+ . Allow ( Skip | Count )
69+ . AllowTop ( 100 )
70+ . AllowOrderBy ( "title" , "published" ) ;
71+ } ) ;
72+
73+ configuration . EnableSwagger (
74+ "{apiVersion}/swagger" ,
75+ swagger =>
76+ {
77+ // build a swagger document and endpoint for each discovered API version
78+ swagger . MultipleApiVersions (
79+ ( apiDescription , version ) => apiDescription . GetGroupName ( ) == version ,
80+ info =>
81+ {
82+ foreach ( var group in apiExplorer . ApiDescriptions )
83+ {
84+ var description = new StringBuilder ( "A sample application with some OData, OpenAPI, Swashbuckle, and API versioning." ) ;
85+
86+ if ( group . IsDeprecated )
87+ {
88+ description . Append ( " This API version has been deprecated." ) ;
89+ }
90+
91+ if ( group . SunsetPolicy is SunsetPolicy policy )
92+ {
93+ if ( policy . Date is DateTimeOffset when )
94+ {
95+ description . Append ( " The API will be sunset on " )
96+ . Append ( when . Date . ToShortDateString ( ) )
97+ . Append ( '.' ) ;
98+ }
99+
100+ if ( policy . HasLinks )
101+ {
102+ description . AppendLine ( ) ;
103+
104+ for ( var i = 0 ; i < policy . Links . Count ; i ++ )
105+ {
106+ var link = policy . Links [ i ] ;
107+
108+ if ( link . Type == "text/html" )
109+ {
110+ description . AppendLine ( ) ;
111+
112+ if ( link . Title . HasValue )
113+ {
114+ description . Append ( link . Title . Value ) . Append ( ": " ) ;
115+ }
116+
117+ description . Append ( link . LinkTarget . OriginalString ) ;
118+ }
119+ }
120+ }
121+ }
122+
123+ info . Version ( group . Name , $ "Sample API { group . ApiVersion } " )
124+ . Contact ( c => c . Name ( "Bill Mei" ) . Email ( "bill.mei@somewhere.com" ) )
125+ . Description ( description . ToString ( ) )
126+ . License ( l => l . Name ( "MIT" ) . Url ( "https://opensource.org/licenses/MIT" ) )
127+ . TermsOfService ( "Shareware" ) ;
128+ }
129+ } ) ;
130+
131+ // add a custom operation filter which documents the implicit API version parameter
132+ swagger . OperationFilter < SwaggerDefaultValues > ( ) ;
133+
134+ // integrate xml comments
135+ swagger . IncludeXmlComments ( XmlCommentsFilePath ) ;
136+ } )
137+ . EnableSwaggerUi ( swagger => swagger . EnableDiscoveryUrlSelector ( ) ) ;
138+
139+ builder . UseWebApi ( httpServer ) ;
140+ }
141+
142+ /// <summary>
143+ /// Get the root content path.
144+ /// </summary>
145+ /// <value>The root content path of the application.</value>
146+ public static string ContentRootPath
147+ {
148+ get
149+ {
150+ var app = AppDomain . CurrentDomain ;
151+
152+ if ( string . IsNullOrEmpty ( app . RelativeSearchPath ) )
153+ {
154+ return app . BaseDirectory ;
155+ }
156+
157+ return app . RelativeSearchPath ;
158+ }
159+ }
160+
161+ private static string XmlCommentsFilePath
162+ {
163+ get
164+ {
165+ var fileName = typeof ( Startup ) . GetTypeInfo ( ) . Assembly . GetName ( ) . Name + ".xml" ;
166+ return Path . Combine ( ContentRootPath , fileName ) ;
167+ }
168+ }
169+ }
0 commit comments