diff --git a/ApiVersioningWithSamples.sln b/ApiVersioningWithSamples.sln index 5d5a6dc9..9b03fe78 100644 --- a/ApiVersioningWithSamples.sln +++ b/ApiVersioningWithSamples.sln @@ -102,6 +102,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.WebApi.Ver EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.OData.Versioning.Tests", "test\Microsoft.AspNet.OData.Versioning.Tests\Microsoft.AspNet.OData.Versioning.Tests.xproj", "{D87E54CC-C2D6-4AE5-806D-AE825B051C66}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedODataWebApiSample", "samples\webapi\AdvancedODataWebApiSample\AdvancedODataWebApiSample.csproj", "{E496EED0-F8C9-4FE9-83E6-75E47A3C41A1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ByNamespaceWebApiSample", "samples\webapi\ByNamespaceWebApiSample\ByNamespaceWebApiSample.csproj", "{A02A4245-3AEB-4549-9037-D89DFDC7E74D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -144,6 +148,14 @@ Global {D87E54CC-C2D6-4AE5-806D-AE825B051C66}.Debug|Any CPU.Build.0 = Debug|Any CPU {D87E54CC-C2D6-4AE5-806D-AE825B051C66}.Release|Any CPU.ActiveCfg = Release|Any CPU {D87E54CC-C2D6-4AE5-806D-AE825B051C66}.Release|Any CPU.Build.0 = Release|Any CPU + {E496EED0-F8C9-4FE9-83E6-75E47A3C41A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E496EED0-F8C9-4FE9-83E6-75E47A3C41A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E496EED0-F8C9-4FE9-83E6-75E47A3C41A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E496EED0-F8C9-4FE9-83E6-75E47A3C41A1}.Release|Any CPU.Build.0 = Release|Any CPU + {A02A4245-3AEB-4549-9037-D89DFDC7E74D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A02A4245-3AEB-4549-9037-D89DFDC7E74D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A02A4245-3AEB-4549-9037-D89DFDC7E74D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A02A4245-3AEB-4549-9037-D89DFDC7E74D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -165,5 +177,7 @@ Global {69C59656-53D1-4ACB-92B5-8B34C8E62175} = {0987757E-4D09-4523-B9C9-65B1E8832AA1} {AEB074E1-E57A-4DD3-A972-3625B367CE5D} = {0987757E-4D09-4523-B9C9-65B1E8832AA1} {D87E54CC-C2D6-4AE5-806D-AE825B051C66} = {0987757E-4D09-4523-B9C9-65B1E8832AA1} + {E496EED0-F8C9-4FE9-83E6-75E47A3C41A1} = {F446ED94-368F-4F67-913B-16E82CA80DFC} + {A02A4245-3AEB-4549-9037-D89DFDC7E74D} = {F446ED94-368F-4F67-913B-16E82CA80DFC} EndGlobalSection EndGlobal diff --git a/samples/aspnetcore/BasicSample/Controllers/ValuesController.cs b/samples/aspnetcore/BasicSample/Controllers/ValuesController.cs index 920d3f45..00cb9a8a 100644 --- a/samples/aspnetcore/BasicSample/Controllers/ValuesController.cs +++ b/samples/aspnetcore/BasicSample/Controllers/ValuesController.cs @@ -10,7 +10,7 @@ [Route( "api/[controller]" )] public class ValuesController : Controller { - // GET api/values?api-version-1.0 + // GET api/values?api-version=1.0 [HttpGet] public string Get() => $"Controller = {GetType().Name}\nVersion = {HttpContext.GetRequestedApiVersion()}"; } diff --git a/samples/webapi/AdvancedODataWebApiSample/AdvancedODataWebApiSample.csproj b/samples/webapi/AdvancedODataWebApiSample/AdvancedODataWebApiSample.csproj new file mode 100644 index 00000000..fb777289 --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/AdvancedODataWebApiSample.csproj @@ -0,0 +1,183 @@ + + + + + + + Debug + AnyCPU + + + 2.0 + {E496EED0-F8C9-4FE9-83E6-75E47A3C41A1} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Microsoft.Examples + AdvancedODataWebApiSample + v4.5 + true + + + + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + True + + + + ..\..\..\packages\Microsoft.OData.Core.6.15.0\lib\portable-net45+win+wpa81\Microsoft.OData.Core.dll + True + + + ..\..\..\packages\Microsoft.OData.Edm.6.15.0\lib\portable-net45+win+wpa81\Microsoft.OData.Edm.dll + True + + + ..\..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + True + + + ..\..\..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + True + + + ..\..\..\packages\Microsoft.Spatial.6.15.0\lib\portable-net45+win+wpa81\Microsoft.Spatial.dll + True + + + ..\..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll + True + + + ..\..\..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + + ..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + True + + + + + + + + + + + + ..\..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + True + + + ..\..\..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll + True + + + ..\..\..\packages\Microsoft.AspNet.OData.5.9.1\lib\net45\System.Web.OData.dll + True + + + + + + + + + + WebApi + + + WebApi.OData + + + + + + Web.config + + + Web.config + + + + + + + + + + + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + True + True + 1044 + / + http://localhost:1044/ + False + False + + + False + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Configuration/OrderModelConfiguration.cs b/samples/webapi/AdvancedODataWebApiSample/Configuration/OrderModelConfiguration.cs new file mode 100644 index 00000000..8e4a208f --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Configuration/OrderModelConfiguration.cs @@ -0,0 +1,30 @@ +namespace Microsoft.Examples.Configuration +{ + using Microsoft.Web.Http; + using Microsoft.Web.OData.Builder; + using Models; + using System.Web.OData.Builder; + + public class OrderModelConfiguration : IModelConfiguration + { + private static readonly ApiVersion V2 = new ApiVersion( 2, 0 ); + + private EntityTypeConfiguration ConfigureCurrent( ODataModelBuilder builder ) + { + var order = builder.EntitySet( "Orders" ).EntityType; + + order.HasKey( p => p.Id ); + + return order; + } + + public void Apply( ODataModelBuilder builder, ApiVersion apiVersion ) + { + // note: the EDM for orders is only available in version 2.0 + if ( apiVersion == V2 ) + { + ConfigureCurrent( builder ); + } + } + } +} \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Configuration/PersonModelConfiguration.cs b/samples/webapi/AdvancedODataWebApiSample/Configuration/PersonModelConfiguration.cs new file mode 100644 index 00000000..440e7f44 --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Configuration/PersonModelConfiguration.cs @@ -0,0 +1,44 @@ +namespace Microsoft.Examples.Configuration +{ + using Microsoft.Web.Http; + using Microsoft.Web.OData.Builder; + using Models; + using System.Web.OData.Builder; + + public class PersonModelConfiguration : IModelConfiguration + { + private void ConfigureV1( ODataModelBuilder builder ) + { + var person = ConfigureCurrent( builder ); + person.Ignore( p => p.Email ); + person.Ignore( p => p.Phone ); + } + + private void ConfigureV2( ODataModelBuilder builder ) => ConfigureCurrent( builder ).Ignore( p => p.Phone ); + + private EntityTypeConfiguration ConfigureCurrent( ODataModelBuilder builder ) + { + var person = builder.EntitySet( "People" ).EntityType; + + person.HasKey( p => p.Id ); + + return person; + } + + public void Apply( ODataModelBuilder builder, ApiVersion apiVersion ) + { + switch ( apiVersion.MajorVersion ) + { + case 1: + ConfigureV1( builder ); + break; + case 2: + ConfigureV2( builder ); + break; + default: + ConfigureCurrent( builder ); + break; + } + } + } +} \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Controllers/Orders2Controller.cs b/samples/webapi/AdvancedODataWebApiSample/Controllers/Orders2Controller.cs new file mode 100644 index 00000000..ab6f863b --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Controllers/Orders2Controller.cs @@ -0,0 +1,26 @@ +namespace Microsoft.Examples.Controllers +{ + using Microsoft.Web.Http; + using Models; + using System.Threading.Tasks; + using System.Web.Http; + using System.Web.OData; + using System.Web.OData.Query; + using System.Web.OData.Routing; + + [ApiVersion( "2.0" )] + [ControllerName( "Orders" )] + [ODataRoutePrefix( "Orders" )] + public class Orders2Controller : ODataController + { + // GET ~/orders?api-version=2.0 + [ODataRoute] + public IHttpActionResult Get( ODataQueryOptions options ) => + Ok( new[] { new Order() { Id = 1, Customer = $"Customer v{Request.GetRequestedApiVersion()}" } } ); + + // GET ~/orders({id})?api-version=2.0 + [ODataRoute( "({id})" )] + public IHttpActionResult Get( [FromODataUri] int id, ODataQueryOptions options ) => + Ok( new Order() { Id = id, Customer = $"Customer v{Request.GetRequestedApiVersion()}" } ); + } +} \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Controllers/Orders3Controller.cs b/samples/webapi/AdvancedODataWebApiSample/Controllers/Orders3Controller.cs new file mode 100644 index 00000000..78c4f410 --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Controllers/Orders3Controller.cs @@ -0,0 +1,27 @@ +namespace Microsoft.Examples.Controllers +{ + using Microsoft.Web.Http; + using Models; + using System.Threading.Tasks; + using System.Web.Http; + using System.Web.OData; + using System.Web.OData.Query; + using System.Web.OData.Routing; + + // note: even though this version of the controller uses attribute routing, other controllers use convention-based + // routing. if we don't apply the ControllerName attribute, then the "controller" route parameter is not populated, + // which will cause version 1.0 and 2.0 to not be discovered since they are convention-based. + [ApiVersion( "3.0" )] + [ControllerName( "Orders" )] + [RoutePrefix( "api/orders" )] + public class Orders3Controller : ApiController + { + // GET ~/orders?api-version=3.0 + [Route] + public IHttpActionResult Get() => Ok( new[] { new Order() { Id = 1, Customer = $"Customer v{Request.GetRequestedApiVersion()}" } } ); + + // GET ~/orders/{id}?api-version=3.0 + [Route( "{id}" )] + public IHttpActionResult Get( int id ) => Ok( new Order() { Id = id, Customer = $"Customer v{Request.GetRequestedApiVersion()}" } ); + } +} \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Controllers/OrdersController.cs b/samples/webapi/AdvancedODataWebApiSample/Controllers/OrdersController.cs new file mode 100644 index 00000000..50be16bb --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Controllers/OrdersController.cs @@ -0,0 +1,23 @@ +namespace Microsoft.Examples.Controllers +{ + using Microsoft.Web.Http; + using Models; + using System.Threading.Tasks; + using System.Web.Http; + using System.Web.OData; + using System.Web.OData.Query; + using System.Web.OData.Routing; + + // note: since the application is configured with AssumeDefaultVersionWhenUnspecifed, this controller + // is implicitly versioned to the DefaultApiVersion, which has the default value 1.0. + public class OrdersController : ApiController + { + // GET ~/orders + // GET ~/orders?api-version=1.0 + public IHttpActionResult Get() => Ok( new[] { new Order() { Id = 1, Customer = $"Customer v{Request.GetRequestedApiVersion()}" } } ); + + // GET ~/orders/{id} + // GET ~/orders/{id}?api-version=1.0 + public IHttpActionResult Get( int id ) => Ok( new Order() { Id = id, Customer = $"Customer v{Request.GetRequestedApiVersion()}" } ); + } +} \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Controllers/People2Controller.cs b/samples/webapi/AdvancedODataWebApiSample/Controllers/People2Controller.cs new file mode 100644 index 00000000..5ef2f70c --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Controllers/People2Controller.cs @@ -0,0 +1,26 @@ +namespace Microsoft.Examples.Controllers +{ + using Microsoft.Web.Http; + using Models; + using System.Threading.Tasks; + using System.Web.Http; + using System.Web.OData; + using System.Web.OData.Query; + using System.Web.OData.Routing; + + [ApiVersion( "3.0" )] + [ControllerName( "People" )] + [ODataRoutePrefix( "People" )] + public class People2Controller : ODataController + { + // GET ~/people?api-version=3.0 + [ODataRoute] + public IHttpActionResult Get( ODataQueryOptions options ) => + Ok( new[] { new Person() { Id = 1, FirstName = "Bill", LastName = "Mei", Email = "bill.mei@somewhere.com", Phone = "555-555-5555" } } ); + + // GET ~/people({id})?api-version=3.0 + [ODataRoute( "({id})" )] + public IHttpActionResult Get( [FromODataUri] int id, ODataQueryOptions options ) => + Ok( new Person() { Id = id, FirstName = "Bill", LastName = "Mei", Email = "bill.mei@somewhere.com", Phone = "555-555-5555" } ); + } +} \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Controllers/PeopleController.cs b/samples/webapi/AdvancedODataWebApiSample/Controllers/PeopleController.cs new file mode 100644 index 00000000..bf58536d --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Controllers/PeopleController.cs @@ -0,0 +1,45 @@ +namespace Microsoft.Examples.Controllers +{ + using Microsoft.Web.Http; + using Models; + using System.Threading.Tasks; + using System.Web.Http; + using System.Web.OData; + using System.Web.OData.Query; + using System.Web.OData.Routing; + + // note: since the application is configured with AssumeDefaultVersionWhenUnspecifed, this controller + // is resolved without or without an API version, even though it is explicitly versioned + [ApiVersion( "1.0" )] + [ApiVersion( "2.0" )] + [ODataRoutePrefix( "People" )] + public class PeopleController : ODataController + { + // GET ~/people + // GET ~/people?api-version=[1.0|2.0] + [ODataRoute] + public IHttpActionResult Get( ODataQueryOptions options ) => + Ok( new[] { new Person() { Id = 1, FirstName = "Bill", LastName = "Mei", Email = "bill.mei@somewhere.com", Phone = "555-555-5555" } } ); + + // GET ~/people({id}) + // GET ~/people({id})?api-version=[1.0|2.0] + [ODataRoute( "({id})" )] + public IHttpActionResult Get( [FromODataUri] int id, ODataQueryOptions options ) => + Ok( new Person() { Id = id, FirstName = "Bill", LastName = "Mei", Email = "bill.mei@somewhere.com", Phone = "555-555-5555" } ); + + // PATCH ~/people({id})?api-version=2.0 + [MapToApiVersion( "2.0" )] + [ODataRoute( "({id})" )] + public IHttpActionResult Patch( [FromODataUri] int id, Delta delta, ODataQueryOptions options ) + { + if ( !ModelState.IsValid ) + return BadRequest( ModelState ); + + var person = new Person() { Id = id, FirstName = "Bill", LastName = "Mei", Email = "bill.mei@somewhere.com", Phone = "555-555-5555" }; + + delta.Patch( person ); + + return Updated( person ); + } + } +} \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Models/Order.cs b/samples/webapi/AdvancedODataWebApiSample/Models/Order.cs new file mode 100644 index 00000000..db06e016 --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Models/Order.cs @@ -0,0 +1,20 @@ +namespace Microsoft.Examples.Models +{ + using System; + using System.Collections.Generic; + using System.ComponentModel.DataAnnotations; + using System.Linq; + using System.Web; + + public class Order + { + public int Id { get; set; } + + public DateTimeOffset CreatedDate { get; set; } = DateTimeOffset.Now; + + public DateTimeOffset EffectiveDate { get; set; } = DateTimeOffset.Now; + + [Required] + public string Customer { get; set; } + } +} \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Models/Person.cs b/samples/webapi/AdvancedODataWebApiSample/Models/Person.cs new file mode 100644 index 00000000..682aa36b --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Models/Person.cs @@ -0,0 +1,23 @@ +namespace Microsoft.Examples.Models +{ + using System; + using System.Collections.Generic; + using System.ComponentModel.DataAnnotations; + + public class Person + { + public int Id { get; set; } + + [Required] + [StringLength( 25 )] + public string FirstName { get; set; } + + [Required] + [StringLength( 25 )] + public string LastName { get; set; } + + public string Email { get; set; } + + public string Phone { get; set; } + } +} \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Properties/AssemblyInfo.cs b/samples/webapi/AdvancedODataWebApiSample/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..d2a17363 --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle( "AdvancedODataWebApiSample" )] +[assembly: AssemblyDescription( "" )] +[assembly: AssemblyConfiguration( "" )] +[assembly: AssemblyCompany( "" )] +[assembly: AssemblyProduct( "AdvancedODataWebApiSample" )] +[assembly: AssemblyCopyright( "Copyright © 2016" )] +[assembly: AssemblyTrademark( "" )] +[assembly: AssemblyCulture( "" )] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible( false )] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid( "e496eed0-f8c9-4fe9-83e6-75e47a3c41a1" )] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion( "1.0.0.0" )] +[assembly: AssemblyFileVersion( "1.0.0.0" )] diff --git a/samples/webapi/AdvancedODataWebApiSample/Startup.cs b/samples/webapi/AdvancedODataWebApiSample/Startup.cs new file mode 100644 index 00000000..becd1bc0 --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Startup.cs @@ -0,0 +1,58 @@ +[assembly: Microsoft.Owin.OwinStartup( typeof( Microsoft.Examples.Startup ) )] + +namespace Microsoft.Examples +{ + using Configuration; + using global::Owin; + using Microsoft.Web.Http.Versioning; + using Microsoft.Web.OData.Builder; + using System.Web.Http; + using System.Web.OData.Batch; + using System.Web.OData.Builder; + using System.Web.OData.Extensions; + using static System.Web.Http.RouteParameter; + + public class Startup + { + public void Configuration( IAppBuilder appBuilder ) + { + var configuration = new HttpConfiguration(); + var httpServer = new HttpServer( configuration ); + + configuration.MapHttpAttributeRoutes(); + configuration.AddApiVersioning( + o => + { + o.ReportApiVersions = true; + o.AssumeDefaultVersionWhenUnspecified = true; + o.ApiVersionReader = new QueryStringOrHeaderApiVersionReader() + { + HeaderNames = + { + "api-version", + "x-ms-version" + } + }; + } ); + configuration.EnableCaseInsensitive( true ); + configuration.EnableUnqualifiedNameCall( true ); + + var modelBuilder = new VersionedODataModelBuilder( configuration ) + { + ModelBuilderFactory = () => new ODataConventionModelBuilder().EnableLowerCamelCase(), + ModelConfigurations = + { + new PersonModelConfiguration(), + new OrderModelConfiguration() + } + }; + var models = modelBuilder.GetEdmModels(); + var batchHandler = new DefaultODataBatchHandler( httpServer ); + + configuration.MapVersionedODataRoutes( "odata", "api", models, batchHandler ); + configuration.Routes.MapHttpRoute( "orders", "api/{controller}/{id}", new { id = Optional } ); + + appBuilder.UseWebApi( httpServer ); + } + } +} \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Web.Debug.config b/samples/webapi/AdvancedODataWebApiSample/Web.Debug.config new file mode 100644 index 00000000..2e302f9f --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Web.Debug.config @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Web.Release.config b/samples/webapi/AdvancedODataWebApiSample/Web.Release.config new file mode 100644 index 00000000..c3584446 --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Web.Release.config @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/Web.config b/samples/webapi/AdvancedODataWebApiSample/Web.config new file mode 100644 index 00000000..0905143e --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/Web.config @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/webapi/AdvancedODataWebApiSample/packages.config b/samples/webapi/AdvancedODataWebApiSample/packages.config new file mode 100644 index 00000000..2275831d --- /dev/null +++ b/samples/webapi/AdvancedODataWebApiSample/packages.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/webapi/BasicODataWebApiSample/BasicODataWebApiSample.csproj b/samples/webapi/BasicODataWebApiSample/BasicODataWebApiSample.csproj index d8cb7026..17bcb614 100644 --- a/samples/webapi/BasicODataWebApiSample/BasicODataWebApiSample.csproj +++ b/samples/webapi/BasicODataWebApiSample/BasicODataWebApiSample.csproj @@ -33,7 +33,8 @@ DEBUG;TRACE prompt 4 - 1998 + + pdbonly diff --git a/samples/webapi/BasicODataWebApiSample/Configuration/OrderModelConfiguration.cs b/samples/webapi/BasicODataWebApiSample/Configuration/OrderModelConfiguration.cs index 52aacd06..d74b6a2a 100644 --- a/samples/webapi/BasicODataWebApiSample/Configuration/OrderModelConfiguration.cs +++ b/samples/webapi/BasicODataWebApiSample/Configuration/OrderModelConfiguration.cs @@ -7,6 +7,8 @@ public class OrderModelConfiguration : IModelConfiguration { + private static readonly ApiVersion V1 = new ApiVersion( 1, 0 ); + private EntityTypeConfiguration ConfigureCurrent( ODataModelBuilder builder ) { var order = builder.EntitySet( "Orders" ).EntityType; @@ -18,7 +20,11 @@ private EntityTypeConfiguration ConfigureCurrent( ODataModelBuilder build public void Apply( ODataModelBuilder builder, ApiVersion apiVersion ) { - ConfigureCurrent( builder ); + // note: the EDM for orders is only available in version 1.0 + if ( apiVersion == V1 ) + { + ConfigureCurrent( builder ); + } } } } \ No newline at end of file diff --git a/samples/webapi/BasicODataWebApiSample/Controllers/OrdersController.cs b/samples/webapi/BasicODataWebApiSample/Controllers/OrdersController.cs index f3f4a1fd..b30d2c38 100644 --- a/samples/webapi/BasicODataWebApiSample/Controllers/OrdersController.cs +++ b/samples/webapi/BasicODataWebApiSample/Controllers/OrdersController.cs @@ -13,13 +13,15 @@ public class OrdersController : ODataController { // GET ~/v1/orders + // GET ~/orders?api-version=1.0 [ODataRoute] - public async Task Get( ODataQueryOptions options ) => + public IHttpActionResult Get( ODataQueryOptions options ) => Ok( new[] { new Order() { Id = 1, Customer = "Bill Mei" } } ); // GET ~/v1/orders(1) + // GET ~/orders(1)?api-version=1.0 [ODataRoute( "({id})" )] - public async Task Get( [FromODataUri] int id, ODataQueryOptions options ) => + public IHttpActionResult Get( [FromODataUri] int id, ODataQueryOptions options ) => Ok( new Order() { Id = id, Customer = "Bill Mei" } ); } } \ No newline at end of file diff --git a/samples/webapi/BasicODataWebApiSample/Controllers/People2Controller.cs b/samples/webapi/BasicODataWebApiSample/Controllers/People2Controller.cs index 1ac7967e..ef4b383e 100644 --- a/samples/webapi/BasicODataWebApiSample/Controllers/People2Controller.cs +++ b/samples/webapi/BasicODataWebApiSample/Controllers/People2Controller.cs @@ -15,12 +15,12 @@ public class People2Controller : ODataController { // GET ~/people?api-version=3.0 [ODataRoute] - public async Task Get( ODataQueryOptions options ) => + public IHttpActionResult Get( ODataQueryOptions options ) => Ok( new[] { new Person() { Id = 1, FirstName = "Bill", LastName = "Mei", Email = "bill.mei@somewhere.com", Phone = "555-555-5555" } } ); // GET ~/people(1)?api-version=3.0 [ODataRoute( "({key})" )] - public async Task Get( [FromODataUri] int id, ODataQueryOptions options ) => + public IHttpActionResult Get( [FromODataUri] int id, ODataQueryOptions options ) => Ok( new Person() { Id = id, FirstName = "Bill", LastName = "Mei", Email = "bill.mei@somewhere.com", Phone = "555-555-5555" } ); } } \ No newline at end of file diff --git a/samples/webapi/BasicODataWebApiSample/Controllers/PeopleController.cs b/samples/webapi/BasicODataWebApiSample/Controllers/PeopleController.cs index d42e2da0..985ce39c 100644 --- a/samples/webapi/BasicODataWebApiSample/Controllers/PeopleController.cs +++ b/samples/webapi/BasicODataWebApiSample/Controllers/PeopleController.cs @@ -13,23 +13,27 @@ [ODataRoutePrefix( "People" )] public class PeopleController : ODataController { + // GET ~/v1/people // GET ~/people?api-version=[1.0|2.0] [ODataRoute] - public async Task Get( ODataQueryOptions options ) => + public IHttpActionResult Get( ODataQueryOptions options ) => Ok( new[] { new Person() { Id = 1, FirstName = "Bill", LastName = "Mei", Email = "bill.mei@somewhere.com", Phone = "555-555-5555" } } ); + // GET ~/v1/people(1) // GET ~/people(1)?api-version=[1.0|2.0] [ODataRoute( "({id})" )] - public async Task Get( [FromODataUri] int id, ODataQueryOptions options ) => + public IHttpActionResult Get( [FromODataUri] int id, ODataQueryOptions options ) => Ok( new Person() { Id = id, FirstName = "Bill", LastName = "Mei", Email = "bill.mei@somewhere.com", Phone = "555-555-5555" } ); // PATCH ~/people(1)?api-version=2.0 [MapToApiVersion( "2.0" )] [ODataRoute( "({id})" )] - public async Task Patch( [FromODataUri] int id, Delta delta, ODataQueryOptions options ) + public IHttpActionResult Patch( [FromODataUri] int id, Delta delta, ODataQueryOptions options ) { if ( !ModelState.IsValid ) + { return BadRequest( ModelState ); + } var person = new Person() { Id = id, FirstName = "Bill", LastName = "Mei", Email = "bill.mei@somewhere.com", Phone = "555-555-5555" }; diff --git a/samples/webapi/BasicWebApiSample/BasicWebApiSample.csproj b/samples/webapi/BasicWebApiSample/BasicWebApiSample.csproj index 9769aed1..9bca0dd8 100644 --- a/samples/webapi/BasicWebApiSample/BasicWebApiSample.csproj +++ b/samples/webapi/BasicWebApiSample/BasicWebApiSample.csproj @@ -33,7 +33,8 @@ DEBUG;TRACE prompt 4 - 1998 + + pdbonly diff --git a/samples/webapi/BasicWebApiSample/Controllers/HelloWorldController.cs b/samples/webapi/BasicWebApiSample/Controllers/HelloWorldController.cs index 1112a939..bee35737 100644 --- a/samples/webapi/BasicWebApiSample/Controllers/HelloWorldController.cs +++ b/samples/webapi/BasicWebApiSample/Controllers/HelloWorldController.cs @@ -12,6 +12,6 @@ public class HelloWorldController : ApiController { // GET api/v{version}/helloworld - public async Task Get() => Ok( new { controller = GetType().Name, version = Request.GetRequestedApiVersion().ToString() } ); + public IHttpActionResult Get() => Ok( new { controller = GetType().Name, version = Request.GetRequestedApiVersion().ToString() } ); } } \ No newline at end of file diff --git a/samples/webapi/BasicWebApiSample/Controllers/Values2Controller.cs b/samples/webapi/BasicWebApiSample/Controllers/Values2Controller.cs index 7df35375..052c75e1 100644 --- a/samples/webapi/BasicWebApiSample/Controllers/Values2Controller.cs +++ b/samples/webapi/BasicWebApiSample/Controllers/Values2Controller.cs @@ -12,6 +12,6 @@ public class Values2Controller : ApiController { // GET api/values?api-version=2.0 - public async Task Get() => Ok( new { controller = GetType().Name, version = Request.GetRequestedApiVersion().ToString() } ); + public IHttpActionResult Get() => Ok( new { controller = GetType().Name, version = Request.GetRequestedApiVersion().ToString() } ); } } \ No newline at end of file diff --git a/samples/webapi/BasicWebApiSample/Controllers/ValuesController.cs b/samples/webapi/BasicWebApiSample/Controllers/ValuesController.cs index 1875d012..2e57d71e 100644 --- a/samples/webapi/BasicWebApiSample/Controllers/ValuesController.cs +++ b/samples/webapi/BasicWebApiSample/Controllers/ValuesController.cs @@ -11,7 +11,7 @@ [Route( "api/values" )] public class ValuesController : ApiController { - // GET api/values?api-version-1.0 - public async Task Get() => Ok( new { controller = GetType().Name, version = Request.GetRequestedApiVersion().ToString() } ); + // GET api/values?api-version=1.0 + public IHttpActionResult Get() => Ok( new { controller = GetType().Name, version = Request.GetRequestedApiVersion().ToString() } ); } } \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/ByNamespaceWebApiSample.csproj b/samples/webapi/ByNamespaceWebApiSample/ByNamespaceWebApiSample.csproj new file mode 100644 index 00000000..92733dab --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/ByNamespaceWebApiSample.csproj @@ -0,0 +1,162 @@ + + + + + + + Debug + AnyCPU + + + 2.0 + {A02A4245-3AEB-4549-9037-D89DFDC7E74D} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Microsoft.Examples + ByNamespaceWebApiSample + v4.5 + true + + + + + + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + ..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll + True + + + + ..\..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + True + + + ..\..\..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + True + + + ..\..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll + True + + + ..\..\..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + + ..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + True + + + + + + + + + + + + ..\..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + True + + + ..\..\..\packages\Microsoft.AspNet.WebApi.Owin.5.2.3\lib\net45\System.Web.Http.Owin.dll + True + + + + + + + + + + WebApi + + + + + + Web.config + + + Web.config + + + + + + + + + + + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + True + True + 1676 + / + http://localhost:1676/ + False + False + + + False + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/Properties/AssemblyInfo.cs b/samples/webapi/ByNamespaceWebApiSample/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..f27d3a87 --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle( "ByNamespaceWebApiSample" )] +[assembly: AssemblyDescription( "" )] +[assembly: AssemblyConfiguration( "" )] +[assembly: AssemblyCompany( "" )] +[assembly: AssemblyProduct( "ByNamespaceWebApiSample" )] +[assembly: AssemblyCopyright( "Copyright © 2016" )] +[assembly: AssemblyTrademark( "" )] +[assembly: AssemblyCulture( "" )] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible( false )] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid( "a02a4245-3aeb-4549-9037-d89dfdc7e74d" )] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion( "1.0.0.0" )] +[assembly: AssemblyFileVersion( "1.0.0.0" )] diff --git a/samples/webapi/ByNamespaceWebApiSample/Startup.cs b/samples/webapi/ByNamespaceWebApiSample/Startup.cs new file mode 100644 index 00000000..0ff0bb66 --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/Startup.cs @@ -0,0 +1,35 @@ +[assembly: Microsoft.Owin.OwinStartup( typeof( Microsoft.Examples.Startup ) )] + +namespace Microsoft.Examples +{ + using global::Owin; + using Microsoft.Web.Http.Routing; + using System.Web.Http; + using System.Web.Http.Routing; + using static System.Web.Http.RouteParameter; + + public class Startup + { + public void Configuration( IAppBuilder builder ) + { + var configuration = new HttpConfiguration(); + var httpServer = new HttpServer( configuration ); + + // reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions" + configuration.AddApiVersioning( o => o.ReportApiVersions = true ); + + configuration.Routes.MapHttpRoute( + "VersionedQueryString", + "api/{controller}/{accountId}", + new { accountId = Optional } ); + + configuration.Routes.MapHttpRoute( + "VersionedUrl", + "v{apiVersion}/{controller}/{accountId}", + new { accountId = Optional }, + new { apiVersion = new ApiVersionRouteConstraint() } ); + + builder.UseWebApi( httpServer ); + } + } +} \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/V1/Controllers/AgreementsController.cs b/samples/webapi/ByNamespaceWebApiSample/V1/Controllers/AgreementsController.cs new file mode 100644 index 00000000..b1dbfa08 --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/V1/Controllers/AgreementsController.cs @@ -0,0 +1,15 @@ +namespace Microsoft.Examples.V1.Controllers +{ + using Microsoft.Web.Http; + using Models; + using System; + using System.Web.Http; + + [ApiVersion( "1.0" )] + public class AgreementsController : ApiController + { + // GET ~/v1/agreements + // GET ~/agreements?api-version=1.0 + public IHttpActionResult Get( string accountId ) => Ok( new Agreement( GetType().FullName, accountId, Request.GetRequestedApiVersion().ToString() ) ); + } +} \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/V1/Models/Agreement.cs b/samples/webapi/ByNamespaceWebApiSample/V1/Models/Agreement.cs new file mode 100644 index 00000000..13ee0b7c --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/V1/Models/Agreement.cs @@ -0,0 +1,20 @@ +namespace Microsoft.Examples.V1.Models +{ + using System; + + public class Agreement + { + public Agreement( string controller, string accountId, string apiVersion ) + { + Controller = controller; + AccountId = accountId; + ApiVersion = apiVersion; + } + + public string Controller { get; set; } + + public string AccountId { get; set; } + + public string ApiVersion { get; set; } + } +} \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/V2/Controllers/AgreementsController.cs b/samples/webapi/ByNamespaceWebApiSample/V2/Controllers/AgreementsController.cs new file mode 100644 index 00000000..8d18060c --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/V2/Controllers/AgreementsController.cs @@ -0,0 +1,15 @@ +namespace Microsoft.Examples.V2.Controllers +{ + using Microsoft.Web.Http; + using Models; + using System; + using System.Web.Http; + + [ApiVersion( "2.0" )] + public class AgreementsController : ApiController + { + // GET ~/v2/agreements + // GET ~/agreements?api-version=2.0 + public IHttpActionResult Get( string accountId ) => Ok( new Agreement( GetType().FullName, accountId, Request.GetRequestedApiVersion().ToString() ) ); + } +} \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/V2/Models/Agreement.cs b/samples/webapi/ByNamespaceWebApiSample/V2/Models/Agreement.cs new file mode 100644 index 00000000..57c5d353 --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/V2/Models/Agreement.cs @@ -0,0 +1,20 @@ +namespace Microsoft.Examples.V2.Models +{ + using System; + + public class Agreement + { + public Agreement( string controller, string accountId, string apiVersion ) + { + Controller = controller; + AccountId = accountId; + ApiVersion = apiVersion; + } + + public string Controller { get; set; } + + public string AccountId { get; set; } + + public string ApiVersion { get; set; } + } +} \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/V3/Controllers/AgreementsController.cs b/samples/webapi/ByNamespaceWebApiSample/V3/Controllers/AgreementsController.cs new file mode 100644 index 00000000..35831b9f --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/V3/Controllers/AgreementsController.cs @@ -0,0 +1,15 @@ +namespace Microsoft.Examples.V3.Controllers +{ + using Microsoft.Web.Http; + using Models; + using System; + using System.Web.Http; + + [ApiVersion( "3.0" )] + public class AgreementsController : ApiController + { + // GET ~/v3/agreements + // GET ~/agreements?api-version=3.0 + public IHttpActionResult Get( string accountId ) => Ok( new Agreement( GetType().FullName, accountId, Request.GetRequestedApiVersion().ToString() ) ); + } +} \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/V3/Models/Agreement.cs b/samples/webapi/ByNamespaceWebApiSample/V3/Models/Agreement.cs new file mode 100644 index 00000000..a1b9fd34 --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/V3/Models/Agreement.cs @@ -0,0 +1,20 @@ +namespace Microsoft.Examples.V3.Models +{ + using System; + + public class Agreement + { + public Agreement( string controller, string accountId, string apiVersion ) + { + Controller = controller; + AccountId = accountId; + ApiVersion = apiVersion; + } + + public string Controller { get; set; } + + public string AccountId { get; set; } + + public string ApiVersion { get; set; } + } +} \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/Web.Debug.config b/samples/webapi/ByNamespaceWebApiSample/Web.Debug.config new file mode 100644 index 00000000..2e302f9f --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/Web.Debug.config @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/Web.Release.config b/samples/webapi/ByNamespaceWebApiSample/Web.Release.config new file mode 100644 index 00000000..c3584446 --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/Web.Release.config @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/Web.config b/samples/webapi/ByNamespaceWebApiSample/Web.config new file mode 100644 index 00000000..6ca37064 --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/Web.config @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/webapi/ByNamespaceWebApiSample/packages.config b/samples/webapi/ByNamespaceWebApiSample/packages.config new file mode 100644 index 00000000..26592d44 --- /dev/null +++ b/samples/webapi/ByNamespaceWebApiSample/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file