diff --git a/Swashbuckle.OData.Nuget/Swashbuckle.OData.NuGet.nuproj b/Swashbuckle.OData.Nuget/Swashbuckle.OData.NuGet.nuproj index 6f054dc..dabf1d4 100644 --- a/Swashbuckle.OData.Nuget/Swashbuckle.OData.NuGet.nuproj +++ b/Swashbuckle.OData.Nuget/Swashbuckle.OData.NuGet.nuproj @@ -25,12 +25,12 @@ Richard Beauchamp Extends Swashbuckle with OData v4 support! Extends Swashbuckle with OData v4 support! - Support constructor dependency injection. Improve error detection and handling. Fix issue 41. + Support constructor dependency injection. Improve error detection and handling. Fixes issues 41, 28. https://github.com/rbeauchamp/Swashbuckle.OData https://github.com/rbeauchamp/Swashbuckle.OData/blob/master/License.txt Copyright 2015 Swashbuckle Swagger SwaggerUi OData Documentation Discovery Help WebApi AspNet AspNetWebApi Docs WebHost IIS - 2.8.4 + 2.8.5 diff --git a/Swashbuckle.OData.Tests/ODataQueryOptions/ODataQueryOptionsTests.cs b/Swashbuckle.OData.Tests/ODataQueryOptions/ODataQueryOptionsTests.cs new file mode 100644 index 0000000..0d25cec --- /dev/null +++ b/Swashbuckle.OData.Tests/ODataQueryOptions/ODataQueryOptionsTests.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Concurrent; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using System.Web.Http; +using System.Web.OData; +using System.Web.OData.Builder; +using System.Web.OData.Extensions; +using FluentAssertions; +using Microsoft.OData.Edm; +using Microsoft.Owin.Hosting; +using NUnit.Framework; +using Owin; +using Swashbuckle.Swagger; +using System.Web.OData.Query; + +namespace Swashbuckle.OData.Tests.ODataQueryOptions +{ + [TestFixture] + public class ODataQueryOptionsTests + { + [Test] + public async Task It_supports_controller_with_single_get_method_with_odataqueryoptions() + { + using (WebApp.Start(HttpClientUtils.BaseAddress, appBuilder => Configuration(appBuilder, typeof(Products3Controller)))) + { + // Arrange + var httpClient = HttpClientUtils.GetHttpClient(HttpClientUtils.BaseAddress); + // Verify that the OData route in the test controller is valid + var products = await httpClient.GetJsonAsync>("/odata/Products3"); + products.Should().NotBeNull(); + products.Value.Count.Should().Be(100); + var product = await httpClient.GetJsonAsync>("/odata/Products3(1)"); + product.Should().NotBeNull(); + product.Value.Count.Should().Be(100); + + // Act + var swaggerDocument = await httpClient.GetJsonAsync("swagger/docs/v1"); + + // Assert + PathItem pathItem; + swaggerDocument.paths.TryGetValue("/odata/Products3", out pathItem); + pathItem.Should().NotBeNull(); + pathItem.get.Should().NotBeNull(); + + PathItem pathItem2; + swaggerDocument.paths.TryGetValue("/odata/Products3({Id})", out pathItem2); + pathItem.Should().NotBeNull(); + pathItem.get.Should().NotBeNull(); + + await ValidationUtils.ValidateSwaggerJson(); + } + } + + private static void Configuration(IAppBuilder appBuilder, Type targetController) + { + var config = appBuilder.GetStandardHttpConfig(targetController); + + // Define a route to a controller class that contains functions + config.MapODataServiceRoute("FromUriArrayRoute", "odata", GetEdmModel()); + + config.EnsureInitialized(); + } + + private static IEdmModel GetEdmModel() + { + ODataModelBuilder builder = new ODataConventionModelBuilder(); + + builder.EntitySet("Products3"); + + return builder.GetEdmModel(); + } + } + + public class Product3 + { + [Key] + public int Id { get; set; } + + public string Name { get; set; } + + public double Price { get; set; } + } + + public class Products3Controller : ODataController + { + private static readonly ConcurrentDictionary Data; + + static Products3Controller() + { + Data = new ConcurrentDictionary(); + var rand = new Random(); + + Enumerable.Range(0, 100).Select(i => new Product3 + { + Id = i, + Name = "Product " + i, + Price = rand.NextDouble() * 1000 + }).ToList().ForEach(p => Data.TryAdd(p.Id, p)); + } + + [EnableQuery] + public Task Get(ODataQueryOptions queryOptions) + { + var results = (IQueryable)queryOptions.ApplyTo(Data.Values.AsQueryable()); + return Task.FromResult((IHttpActionResult)Ok(results)); + } + } +} \ No newline at end of file diff --git a/Swashbuckle.OData.Tests/Swashbuckle.OData.Tests.csproj b/Swashbuckle.OData.Tests/Swashbuckle.OData.Tests.csproj index 843e292..11d16a5 100644 --- a/Swashbuckle.OData.Tests/Swashbuckle.OData.Tests.csproj +++ b/Swashbuckle.OData.Tests/Swashbuckle.OData.Tests.csproj @@ -168,6 +168,7 @@ + diff --git a/Swashbuckle.OData/Descriptions/HttpParameterDescriptorExtensions.cs b/Swashbuckle.OData/Descriptions/HttpParameterDescriptorExtensions.cs new file mode 100644 index 0000000..a30c14c --- /dev/null +++ b/Swashbuckle.OData/Descriptions/HttpParameterDescriptorExtensions.cs @@ -0,0 +1,18 @@ +using System.Diagnostics.Contracts; +using System.Web.Http.Controllers; + +namespace Swashbuckle.OData.Descriptions +{ + internal static class HttpParameterDescriptorExtensions + { + public static bool IsODataQueryOptions(this HttpParameterDescriptor parameterDescriptor) + { + Contract.Requires(parameterDescriptor != null); + + var parameterType = parameterDescriptor.ParameterType; + Contract.Assume(parameterType != null); + + return parameterType.Name == "ODataQueryOptions`1"; + } + } +} \ No newline at end of file diff --git a/Swashbuckle.OData/Descriptions/MapByDescription.cs b/Swashbuckle.OData/Descriptions/MapByDescription.cs index d7e0327..52da451 100644 --- a/Swashbuckle.OData/Descriptions/MapByDescription.cs +++ b/Swashbuckle.OData/Descriptions/MapByDescription.cs @@ -13,7 +13,7 @@ public HttpParameterDescriptor Map(Parameter swaggerParameter, int parameterInde if (swaggerParameter.description != null && swaggerParameter.description.StartsWith("key:")) { var parameterDescriptor = actionDescriptor.GetParameters()?.SingleOrDefault(descriptor => descriptor.ParameterName == "key"); - if (parameterDescriptor != null) + if (parameterDescriptor != null && !parameterDescriptor.IsODataQueryOptions()) { var httpControllerDescriptor = actionDescriptor.ControllerDescriptor; Contract.Assume(httpControllerDescriptor != null); diff --git a/Swashbuckle.OData/Descriptions/MapByIndex.cs b/Swashbuckle.OData/Descriptions/MapByIndex.cs index 87b7f87..bf12a2e 100644 --- a/Swashbuckle.OData/Descriptions/MapByIndex.cs +++ b/Swashbuckle.OData/Descriptions/MapByIndex.cs @@ -11,7 +11,7 @@ public HttpParameterDescriptor Map(Parameter swaggerParameter, int parameterInde if (swaggerParameter.@in != "query" && parameterIndex < actionDescriptor.GetParameters().Count) { var parameterDescriptor = actionDescriptor.GetParameters()[parameterIndex]; - if (parameterDescriptor != null) + if (parameterDescriptor != null && !parameterDescriptor.IsODataQueryOptions()) { var httpControllerDescriptor = actionDescriptor.ControllerDescriptor; Contract.Assume(httpControllerDescriptor != null); diff --git a/Swashbuckle.OData/Properties/AssemblyInfo.cs b/Swashbuckle.OData/Properties/AssemblyInfo.cs index 2431d2f..a3cfb00 100644 --- a/Swashbuckle.OData/Properties/AssemblyInfo.cs +++ b/Swashbuckle.OData/Properties/AssemblyInfo.cs @@ -37,4 +37,4 @@ [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: AssemblyInformationalVersion("2.8.4")] \ No newline at end of file +[assembly: AssemblyInformationalVersion("2.8.5")] \ No newline at end of file diff --git a/Swashbuckle.OData/Swashbuckle.OData.csproj b/Swashbuckle.OData/Swashbuckle.OData.csproj index 357a289..a73ac57 100644 --- a/Swashbuckle.OData/Swashbuckle.OData.csproj +++ b/Swashbuckle.OData/Swashbuckle.OData.csproj @@ -174,6 +174,7 @@ +