diff --git a/License.txt b/License.txt
index b6a9e37..c2633c9 100644
--- a/License.txt
+++ b/License.txt
@@ -24,7 +24,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Certain portions of this code is Copyright (c) 2013, Richard Morris - All rights reserved.
-For those portions, the following license applies:
+For those portions, the following license applies:
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
@@ -34,4 +34,4 @@ Redistribution and use in source and binary forms, with or without modification,
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHA
\ No newline at end of file
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
\ No newline at end of file
diff --git a/Swashbuckle.OData.NuGetPackage/Swashbuckle.OData.NuGetPackage.nuproj b/Swashbuckle.OData.NuGetPackage/Swashbuckle.OData.NuGetPackage.nuproj
index 88e554a..bd34fbf 100644
--- a/Swashbuckle.OData.NuGetPackage/Swashbuckle.OData.NuGetPackage.nuproj
+++ b/Swashbuckle.OData.NuGetPackage/Swashbuckle.OData.NuGetPackage.nuproj
@@ -19,7 +19,7 @@
Swashbuckle.OData
- 3.1.0
+ 3.1.1
Swashbuckle.OData
Richard Beauchamp
Richard Beauchamp
diff --git a/Swashbuckle.OData.Sample/ApiControllers/Client.cs b/Swashbuckle.OData.Sample/ApiControllers/Client.cs
index 4f2819c..505be35 100644
--- a/Swashbuckle.OData.Sample/ApiControllers/Client.cs
+++ b/Swashbuckle.OData.Sample/ApiControllers/Client.cs
@@ -2,12 +2,24 @@
namespace SwashbuckleODataSample.ApiControllers
{
+ ///
+ /// Client Comment
+ ///
public class Client
{
+ ///
+ /// Client ID
+ ///
public int Id { get; set; }
+ ///
+ /// Client Name
+ ///
public string Name { get; set; }
+ ///
+ /// Client Projects
+ ///
public IList Projects { get; set; }
}
}
\ No newline at end of file
diff --git a/Swashbuckle.OData.Sample/App_Start/SwaggerConfig.cs b/Swashbuckle.OData.Sample/App_Start/SwaggerConfig.cs
index 9163ebf..6531b04 100644
--- a/Swashbuckle.OData.Sample/App_Start/SwaggerConfig.cs
+++ b/Swashbuckle.OData.Sample/App_Start/SwaggerConfig.cs
@@ -176,7 +176,7 @@ public static void Register()
{
// Set this flag to include navigation properties in your entity swagger models
//
- //odataConfig.IncludeNavigationProperties();
+ odataConfig.IncludeNavigationProperties();
}));
})
.EnableSwaggerUi(c =>
diff --git a/Swashbuckle.OData.Sample/Models/Customer.cs b/Swashbuckle.OData.Sample/Models/Customer.cs
index 8e83094..5d738d9 100644
--- a/Swashbuckle.OData.Sample/Models/Customer.cs
+++ b/Swashbuckle.OData.Sample/Models/Customer.cs
@@ -1,13 +1,30 @@
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations.Schema;
namespace SwashbuckleODataSample.Models
{
+ ///
+ /// Customer comment
+ ///
public class Customer
{
+ public Customer()
+ {
+ Orders = new HashSet();
+ }
+ ///
+ /// Customer Id
+ ///
public int Id { get; set; }
+ ///
+ /// customer Name
+ ///
public string Name { get; set; }
- public IList Orders { get; set; }
+ ///
+ /// Customer Orders
+ ///
+ public virtual ICollection Orders { get; }
}
}
\ No newline at end of file
diff --git a/Swashbuckle.OData.Sample/Models/Order.cs b/Swashbuckle.OData.Sample/Models/Order.cs
index 78468f3..16b935e 100644
--- a/Swashbuckle.OData.Sample/Models/Order.cs
+++ b/Swashbuckle.OData.Sample/Models/Order.cs
@@ -15,10 +15,9 @@ public class Order
public double UnitPrice { get; set; }
+ [ForeignKey("Customer")]
public int CustomerId { get; set; }
- [ForeignKey("CustomerId")]
- [ActionOnDelete(EdmOnDeleteAction.Cascade)]
- public Customer Customer { get; set; }
+ public virtual Customer Customer { get; set; }
}
}
\ No newline at end of file
diff --git a/Swashbuckle.OData.Sample/ODataControllers/CustomersController.cs b/Swashbuckle.OData.Sample/ODataControllers/CustomersController.cs
index 4dfa9f1..5b76df5 100644
--- a/Swashbuckle.OData.Sample/ODataControllers/CustomersController.cs
+++ b/Swashbuckle.OData.Sample/ODataControllers/CustomersController.cs
@@ -7,6 +7,10 @@
using System.Web.OData;
using SwashbuckleODataSample.Models;
using SwashbuckleODataSample.Repositories;
+using System.Data.Entity;
+using Swashbuckle.Swagger.Annotations;
+using Swashbuckle.OData;
+using System.Web.OData.Routing;
namespace SwashbuckleODataSample.ODataControllers
{
@@ -17,10 +21,12 @@ public class CustomersController : ODataController
///
/// Query customers
///
- [EnableQuery]
- public IQueryable GetCustomers()
+ [EnableQuery(PageSize = 5)]
+ [SwaggerResponse(HttpStatusCode.OK, Type= typeof(ODataListResponse))]
+ public async Task GetCustomers()
{
- return _db.Customers;
+ var customers = await _db.Customers.ToListAsync();
+ return Ok(customers);
}
///
@@ -152,8 +158,7 @@ public async Task Delete([FromODataUri] int key)
[EnableQuery]
public IQueryable GetOrders([FromODataUri] int key)
{
- return _db.Customers.Where(m => m.Id == key)
- .SelectMany(m => m.Orders);
+ return _db.Orders.Where(o => o.CustomerId == key);
}
///
diff --git a/Swashbuckle.OData.Sample/ODataControllers/OrdersController.cs b/Swashbuckle.OData.Sample/ODataControllers/OrdersController.cs
index f3a5461..73ef414 100644
--- a/Swashbuckle.OData.Sample/ODataControllers/OrdersController.cs
+++ b/Swashbuckle.OData.Sample/ODataControllers/OrdersController.cs
@@ -9,6 +9,7 @@
using SwashbuckleODataSample.Models;
using SwashbuckleODataSample.Repositories;
using SwashbuckleODataSample.Utils;
+using System.Collections.Generic;
namespace SwashbuckleODataSample.ODataControllers
{
@@ -20,11 +21,22 @@ public class OrdersController : ODataController
/// Query orders
///
[EnableQuery]
- public IQueryable GetOrders()
+ public IQueryable Get()
{
return _db.Orders;
}
+
+ ///
+ /// Query orders by Customer Id
+ ///
+ [EnableQuery]
+ public ICollection Get([FromODataUri]int customerId)
+ {
+ return _db.Orders.Where(o => o.CustomerId == customerId).ToList();
+ }
+
+
///
/// An example of a custom route. Create a new order for the customer with the given id
///
@@ -54,7 +66,7 @@ public async Task Post([FromODataUri] int customerId, Order o
[EnableQuery]
public SingleResult GetOrder([FromODataUri] Guid key)
{
- return SingleResult.Create(_db.Orders.Where(order => order.OrderId == key));
+ return SingleResult.Create(_db.Orders.Where(order => order.OrderId ==key));
}
///
@@ -139,8 +151,11 @@ public async Task Delete([FromODataUri] Guid key)
[EnableQuery]
public SingleResult GetCustomer([FromODataUri] Guid key)
{
- return SingleResult.Create(_db.Orders.Where(m => m.OrderId == key)
- .Select(m => m.Customer));
+ var custId = _db.Orders.Where(m => m.OrderId == key)
+ .Select(m => m.CustomerId).First();
+ return SingleResult.Create(_db.Customers.Where(c => c.Id == custId));
+ //return SingleResult.Create(_db.Orders.Where(m => m.OrderId == key)
+ // .Select(m => m.Customer));
}
protected override void Dispose(bool disposing)
diff --git a/Swashbuckle.OData.Sample/Repositories/SwashbuckleODataContext.cs b/Swashbuckle.OData.Sample/Repositories/SwashbuckleODataContext.cs
index 8543159..b8cd12b 100644
--- a/Swashbuckle.OData.Sample/Repositories/SwashbuckleODataContext.cs
+++ b/Swashbuckle.OData.Sample/Repositories/SwashbuckleODataContext.cs
@@ -12,7 +12,6 @@ static SwashbuckleODataContext()
Database.SetInitializer(null);
}
-
public SwashbuckleODataContext() : base("name=SwashbuckleODataContext")
{
Customers = new TestDbSet();
@@ -34,10 +33,95 @@ private static void Seed(SwashbuckleODataContext context)
var customerOne = new Customer { Id = 1, Name = "CustomerOne" };
context.Customers.Add(customerOne);
- context.Customers.Add(new Customer { Id = 2, Name = "CustomerTwo" });
+ context.Orders.Add(new Order {
+ OrderId = new System.Guid("ce37ae8d-4efe-2d5f-10a0-39ddd2436a52"),
+ OrderName = "OrderOne",
+ CustomerId = 1,
+ UnitPrice = 4.0
+ });
+ context.Orders.Add(new Order {
+ OrderId = new System.Guid("03b20510-a693-9504-b040-39ddd2436a52"),
+ OrderName = "OrderTwo",
+ CustomerId = 1,
+ UnitPrice = 3.5
+ });
+
+ var customerTwo = new Customer { Id = 2, Name = "CustomerTwo" };
+ context.Customers.Add(customerTwo);
+ context.Orders.Add(new Order {
+ OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd),
+ OrderName = "OrderOne",
+ CustomerId = customerTwo.Id,
+ UnitPrice = 4.0
+ });
+ context.Orders.Add(new Order {
+ OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd),
+ OrderName = "OrderTwo",
+ CustomerId = customerTwo.Id,
+ UnitPrice = 3.5
+ });
+
+ var customerThree = new Customer { Id = 3, Name = "CustomerThree" };
+ context.Customers.Add(customerThree);
+ context.Orders.Add(new Order {
+ OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd),
+ OrderName = "OrderOne",
+ CustomerId = customerThree.Id,
+ UnitPrice = 4.0
+ });
+ context.Orders.Add(new Order {
+ OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd),
+ OrderName = "OrderTwo",
+ CustomerId = customerThree.Id,
+ UnitPrice = 3.5
+ });
+
+ var customerFour = new Customer { Id = 4, Name = "CustomerFour" };
+ context.Customers.Add(customerFour);
+ context.Orders.Add(new Order {
+ OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd),
+ OrderName = "OrderOne",
+ CustomerId = customerFour.Id,
+ UnitPrice = 4.0
+ });
+ context.Orders.Add(new Order {
+ OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd),
+ OrderName = "OrderTwo",
+ CustomerId = customerFour.Id,
+ UnitPrice = 3.5
+ });
+
+
+ var customerFive = new Customer { Id = 5, Name = "CustomerFive" };
+ context.Customers.Add(customerFive);
+ context.Orders.Add(new Order {
+ OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd),
+ OrderName = "OrderOne",
+ CustomerId = customerFive.Id,
+ UnitPrice = 4.0
+ });
+ context.Orders.Add(new Order {
+ OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd),
+ OrderName = "OrderTwo",
+ CustomerId = customerFive.Id,
+ UnitPrice = 3.5
+ });
+
- context.Orders.Add(new Order { OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd), OrderName = "OrderOne", Customer = customerOne, UnitPrice = 4.0 });
- context.Orders.Add(new Order { OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd), OrderName = "OrderTwo", Customer = customerOne, UnitPrice = 3.5 });
+ var customerSix = new Customer { Id = 6, Name = "CustomerSix" };
+ context.Customers.Add(customerSix);
+ context.Orders.Add(new Order {
+ OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd),
+ OrderName = "OrderOne",
+ CustomerId = customerSix.Id,
+ UnitPrice = 4.0
+ });
+ context.Orders.Add(new Order {
+ OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd),
+ OrderName = "OrderTwo",
+ CustomerId = customerSix.Id,
+ UnitPrice = 3.5
+ });
}
public DbSet Customers { get; set; }
diff --git a/Swashbuckle.OData.Sample/Swashbuckle.OData.Sample.csproj b/Swashbuckle.OData.Sample/Swashbuckle.OData.Sample.csproj
index a654c6e..239702f 100644
--- a/Swashbuckle.OData.Sample/Swashbuckle.OData.Sample.csproj
+++ b/Swashbuckle.OData.Sample/Swashbuckle.OData.Sample.csproj
@@ -180,7 +180,9 @@
-
+
+ Designer
+
Web.config
@@ -195,7 +197,9 @@
-
+
+ Designer
+
diff --git a/Swashbuckle.OData.Sample/Web.config b/Swashbuckle.OData.Sample/Web.config
index e6bebc3..e13fcc4 100644
--- a/Swashbuckle.OData.Sample/Web.config
+++ b/Swashbuckle.OData.Sample/Web.config
@@ -1,65 +1,65 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -67,7 +67,7 @@
-
+
diff --git a/Swashbuckle.OData.Tests/AppBuilderExtensions.cs b/Swashbuckle.OData.Tests/AppBuilderExtensions.cs
index 02b6871..12e41b8 100644
--- a/Swashbuckle.OData.Tests/AppBuilderExtensions.cs
+++ b/Swashbuckle.OData.Tests/AppBuilderExtensions.cs
@@ -4,6 +4,8 @@
using Owin;
using Swashbuckle.Application;
using SwashbuckleODataSample;
+using System.Reflection;
+using System.IO;
namespace Swashbuckle.OData.Tests
{
@@ -40,6 +42,13 @@ public static HttpConfiguration ConfigureHttpConfig(this IAppBuilder appBuilder,
//
c.CustomProvider(defaultProvider => new ODataSwaggerProvider(defaultProvider, c, config).Configure(odataSwaggerDocsConfig));
+ //Add the xml comments File
+ var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
+ var commentsFileName = "SwashbuckleODataSample.XML";
+ var commentsFile = Path.Combine(baseDirectory, commentsFileName);
+ if (File.Exists(commentsFile))
+ c.IncludeXmlComments(commentsFile);
+
// Apply test-specific configs
swaggerDocsConfig?.Invoke(c);
}).EnableSwaggerUi();
diff --git a/Swashbuckle.OData.Tests/Fixtures/SummaryTests.cs b/Swashbuckle.OData.Tests/Fixtures/SummaryTests.cs
new file mode 100644
index 0000000..040cf8f
--- /dev/null
+++ b/Swashbuckle.OData.Tests/Fixtures/SummaryTests.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Threading.Tasks;
+using System.Web.Http.Dispatcher;
+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 SwashbuckleODataSample.Models;
+using System.Xml;
+using System.IO;
+using SwashbuckleODataSample.ODataControllers;
+using System.Net.Http;
+using System.Linq;
+
+namespace Swashbuckle.OData.Tests
+{
+ [TestFixture]
+ public class SummaryTests
+ {
+ [Test]
+ public async Task It_gets_the_method_summary_from_xml_comments()
+ {
+ var xmlCommentsFilePath = GetXMLFileNameIfExists(typeof(Customer).Assembly);
+ xmlCommentsFilePath.Should().NotBeNullOrEmpty("The xml comments file of the sample project should be generated to test this behaviour");
+ var xmlCommentsDoc = new XmlDocument();
+ xmlCommentsDoc.Load(xmlCommentsFilePath);
+
+ XmlNode xmlGetCustomersSummaryNode = xmlCommentsDoc.SelectSingleNode(
+ "//member[contains(@name, 'CustomersController.GetCustomers')]/summary");
+
+ xmlGetCustomersSummaryNode.Should().NotBeNull("Method GetCustomers not found in customersController in the xml comments");
+
+ var getCustomersSummaryText = xmlGetCustomersSummaryNode.InnerText.Trim();
+
+ using (WebApp.Start(HttpClientUtils.BaseAddress, appBuilder => Configuration(appBuilder, typeof(CustomersController))))
+ {
+ // Arrange
+ var httpClient = HttpClientUtils.GetHttpClient(HttpClientUtils.BaseAddress);
+
+ // Act
+ var swaggerDocument = await httpClient.GetJsonAsync("swagger/docs/v1");
+
+ // Assert
+ PathItem pathItem;
+ swaggerDocument.paths.TryGetValue("/odata/Customers", out pathItem);
+ pathItem.Should().NotBeNull();
+ var summary = pathItem.get.summary;
+ summary.Should().NotBeNullOrEmpty();
+ summary.Trim().ShouldBeEquivalentTo(getCustomersSummaryText);
+
+ await ValidationUtils.ValidateSwaggerJson();
+ }
+ }
+
+ [Test]
+ public async Task It_gets_the_properties_summary_from_xml_comments()
+ {
+ var xmlCommentsFilePath = GetXMLFileNameIfExists(typeof(Customer).Assembly);
+ xmlCommentsFilePath.Should().NotBeNullOrEmpty("The xml comments file of the sample project should be generated to test this behaviour");
+ var xmlCommentsDoc = new XmlDocument();
+ xmlCommentsDoc.Load(xmlCommentsFilePath);
+
+ XmlNode xmlCustommerIdSummaryNode = xmlCommentsDoc.SelectSingleNode(
+ "//member[contains(@name, 'Models.Customer.Id')]/summary");
+
+ xmlCustommerIdSummaryNode.Should().NotBeNull("Id property not found in Customer model in the xml comments");
+
+ var customerIdSummaryText = xmlCustommerIdSummaryNode.InnerText.Trim();
+
+ using (WebApp.Start(HttpClientUtils.BaseAddress, appBuilder => Configuration(appBuilder, typeof(CustomersController))))
+ {
+ // Arrange
+ var httpClient = HttpClientUtils.GetHttpClient(HttpClientUtils.BaseAddress);
+
+ // Act
+ var swaggerDocument = await httpClient.GetJsonAsync("swagger/docs/v1");
+
+ // Assert
+ swaggerDocument.definitions.Should().ContainKey("Customer");
+ var customerSchema = swaggerDocument.definitions["Customer"];
+ customerSchema.Should().NotBeNull();
+ customerSchema.properties.Should().NotBeNull();
+ customerSchema.properties.Should().ContainKey("Id");
+ customerSchema.properties["Id"].description.Should().Be(customerIdSummaryText);
+
+ await ValidationUtils.ValidateSwaggerJson();
+ }
+ }
+
+ private static string GetXMLFileNameIfExists(System.Reflection.Assembly assembly)
+ {
+ var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
+ var commentsFileName = "SwashbuckleODataSample.XML";
+ var xmlPath = Path.Combine(baseDirectory, commentsFileName);
+ if (File.Exists(xmlPath))
+ return xmlPath;
+
+ return "";
+ }
+
+ private static void Configuration(IAppBuilder appBuilder, Type targetController)
+ {
+ var config = appBuilder.GetStandardHttpConfig(targetController);
+
+ config.MapODataServiceRoute("DefaultODataRoute", "odata", GetDefaultModel());
+
+ config.EnsureInitialized();
+ }
+
+ private static IEdmModel GetDefaultModel()
+ {
+ var builder = new ODataConventionModelBuilder();
+ builder.EntitySet("Customers");
+ builder.EntitySet("Orders");
+ return builder.GetEdmModel();
+ }
+
+ }
+
+}
\ 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 fbc763a..bdfa37d 100644
--- a/Swashbuckle.OData.Tests/Swashbuckle.OData.Tests.csproj
+++ b/Swashbuckle.OData.Tests/Swashbuckle.OData.Tests.csproj
@@ -51,10 +51,6 @@
..\packages\FluentAssertions.4.14.0\lib\net45\FluentAssertions.Core.dll
True
-
- ..\packages\Flurl.1.1.2\lib\portable-net40+sl50+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Flurl.dll
- True
-
..\packages\Microsoft.Extensions.DependencyInjection.1.0.0\lib\netstandard1.1\Microsoft.Extensions.DependencyInjection.dll
True
@@ -152,6 +148,7 @@
+
diff --git a/Swashbuckle.OData.Tests/packages.config b/Swashbuckle.OData.Tests/packages.config
index dc5226f..5674db1 100644
--- a/Swashbuckle.OData.Tests/packages.config
+++ b/Swashbuckle.OData.Tests/packages.config
@@ -3,7 +3,6 @@
-
diff --git a/Swashbuckle.OData/Descriptions/EntityDataModelRouteGenerator.cs b/Swashbuckle.OData/Descriptions/EntityDataModelRouteGenerator.cs
index a10003e..fd0aed1 100644
--- a/Swashbuckle.OData/Descriptions/EntityDataModelRouteGenerator.cs
+++ b/Swashbuckle.OData/Descriptions/EntityDataModelRouteGenerator.cs
@@ -49,7 +49,8 @@ private static IEnumerable GenerateEntitySetRoutes(ODataRoute oDat
return oDataRoute.GetEdmModel()
.EntityContainer
.EntitySets()?
- .Select(entitySet => new SwaggerRoute(ODataSwaggerUtilities.GetPathForEntitySet(entitySet), oDataRoute, ODataSwaggerUtilities.CreateSwaggerPathForEntitySet(entitySet, oDataRoute)));
+ .Select(entitySet => new SwaggerRoute(ODataSwaggerUtilities.GetPathForEntitySet(entitySet), oDataRoute,
+ ODataSwaggerUtilities.CreateSwaggerPathForEntitySet(entitySet, oDataRoute)));
}
private static IEnumerable GenerateEntityRoutes(ODataRoute oDataRoute)
@@ -60,7 +61,8 @@ private static IEnumerable GenerateEntityRoutes(ODataRoute oDataRo
return oDataRoute.GetEdmModel()
.EntityContainer
.EntitySets()?
- .Select(entitySet => new SwaggerRoute(ODataSwaggerUtilities.GetPathForEntity(entitySet, oDataRoute), oDataRoute, ODataSwaggerUtilities.CreateSwaggerPathForEntity(entitySet, oDataRoute)));
+ .Select(entitySet => new SwaggerRoute(ODataSwaggerUtilities.GetPathForEntity(entitySet, oDataRoute), oDataRoute,
+ ODataSwaggerUtilities.CreateSwaggerPathForEntity(entitySet, oDataRoute)));
}
private static IEnumerable GenerateOperationImportRoutes(ODataRoute oDataRoute)
@@ -71,7 +73,8 @@ private static IEnumerable GenerateOperationImportRoutes(ODataRout
return oDataRoute.GetEdmModel()
.EntityContainer
.OperationImports()?
- .Select(operationImport => new SwaggerRoute(ODataSwaggerUtilities.GetPathForOperationImport(operationImport), oDataRoute, ODataSwaggerUtilities.CreateSwaggerPathForOperationImport(operationImport, oDataRoute)));
+ .Select(operationImport => new SwaggerRoute(ODataSwaggerUtilities.GetPathForOperationImport(operationImport), oDataRoute,
+ ODataSwaggerUtilities.CreateSwaggerPathForOperationImport(operationImport, oDataRoute)));
}
///
diff --git a/Swashbuckle.OData/Descriptions/HttpActionDescriptorExtensions.cs b/Swashbuckle.OData/Descriptions/HttpActionDescriptorExtensions.cs
index 773578c..a9626d3 100644
--- a/Swashbuckle.OData/Descriptions/HttpActionDescriptorExtensions.cs
+++ b/Swashbuckle.OData/Descriptions/HttpActionDescriptorExtensions.cs
@@ -11,10 +11,13 @@ internal static class HttpActionDescriptorExtensions
public static ResponseDescription CreateResponseDescription(this HttpActionDescriptor actionDescriptor)
{
Contract.Requires(actionDescriptor != null);
-
- var responseTypeAttribute = actionDescriptor.GetCustomAttributes();
- var responseType = responseTypeAttribute?.Select(attribute => attribute.ResponseType).FirstOrDefault();
-
+
+ var responseType = actionDescriptor.GetCustomAttributes()?
+ .Select(attribute => attribute.Type).FirstOrDefault();
+ if (responseType == null)
+ responseType = actionDescriptor.GetCustomAttributes()?
+ .Select(attribute => attribute.ResponseType).FirstOrDefault();
+
return new ResponseDescription
{
DeclaredType = actionDescriptor.ReturnType,
diff --git a/Swashbuckle.OData/Descriptions/ODataSwaggerUtilities.cs b/Swashbuckle.OData/Descriptions/ODataSwaggerUtilities.cs
index d348c28..299a66d 100644
--- a/Swashbuckle.OData/Descriptions/ODataSwaggerUtilities.cs
+++ b/Swashbuckle.OData/Descriptions/ODataSwaggerUtilities.cs
@@ -191,7 +191,6 @@ public static PathItem CreateSwaggerPathForEntity(IEdmEntitySet entitySet, OData
keyDefinitionAsType,
true);
}
-
return new PathItem
{
get = new Operation()
@@ -199,9 +198,7 @@ public static PathItem CreateSwaggerPathForEntity(IEdmEntitySet entitySet, OData
.OperationId(entitySet.Name + "_GetById")
.Description("Returns the entity with the key from " + entitySet.Name)
.Tags(entitySet.Name)
- .Parameters(keyParameters.DeepClone()
- .Parameter("$expand", "query", "Expands related entities inline.", "string", false)
- .Parameter("$select", "query", "Selects which properties to include in the response.", "string", false))
+ .Parameters(AddQueryOptionParametersForEntity(keyParameters.DeepClone()))
.Parameters(AddRoutePrefixParameters(oDataRoute))
.Responses(new Dictionary().Response("200", "EntitySet " + entitySet.Name, entitySet.GetEntityType()).DefaultErrorResponse()),
@@ -226,7 +223,8 @@ public static PathItem CreateSwaggerPathForEntity(IEdmEntitySet entitySet, OData
.Parameters(AddRoutePrefixParameters(oDataRoute))
.Responses(new Dictionary().Response("204", "Empty response").DefaultErrorResponse()),
- delete = new Operation().Summary("Delete entity in EntitySet " + entitySet.Name)
+ delete = new Operation()
+ .Summary("Delete entity in EntitySet " + entitySet.Name)
.OperationId(entitySet.Name + "_DeleteById")
.Description("Delete entity in EntitySet " + entitySet.Name)
.Tags(entitySet.Name)
diff --git a/Swashbuckle.OData/EnableQueryFilter.cs b/Swashbuckle.OData/EnableQueryFilter.cs
index 1cce723..9f04ac5 100644
--- a/Swashbuckle.OData/EnableQueryFilter.cs
+++ b/Swashbuckle.OData/EnableQueryFilter.cs
@@ -47,13 +47,42 @@ private static bool ReturnsCollection(ApiDescription apiDescription)
Type returnType = httpActionDescriptor.ReturnType;
- var responseTypeAttr = httpActionDescriptor.GetCustomAttributes().FirstOrDefault();
- if (responseTypeAttr != null)
- returnType = responseTypeAttr.ResponseType;
+ //Look if it has set a response type in the attributes
+ var swgResponseTypeAttr = httpActionDescriptor.GetCustomAttributes()?.FirstOrDefault();
+ if (swgResponseTypeAttr != null)
+ returnType = swgResponseTypeAttr.Type;
+ else
+ {
+ var responseTypeAttr = httpActionDescriptor.GetCustomAttributes()?.FirstOrDefault();
+ if (responseTypeAttr != null)
+ returnType = responseTypeAttr.ResponseType;
+ }
+
+ returnType = GetValueTypeFromODataResponseOrDescendants(returnType);
return returnType.IsCollection();
}
+ ///
+ /// if or one of its parents is an implementation of
+ /// returns TValue, otherwise, return type
+ ///
+ /// type to be evaluated
+ /// TValue or returntype
+ private static Type GetValueTypeFromODataResponseOrDescendants(Type returnType)
+ {
+ var type = returnType;
+
+ while (type != null && type != typeof(object))
+ {
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ODataResponse<>))
+ return type.GetGenericArguments().First();
+
+ type = type.BaseType;
+ }
+ return returnType;
+ }
+
}
}
\ No newline at end of file
diff --git a/Swashbuckle.OData/ODataListResponse.cs b/Swashbuckle.OData/ODataListResponse.cs
new file mode 100644
index 0000000..aec4cad
--- /dev/null
+++ b/Swashbuckle.OData/ODataListResponse.cs
@@ -0,0 +1,14 @@
+using Newtonsoft.Json;
+using System.Collections.Generic;
+
+namespace Swashbuckle.OData
+{
+ public class ODataListResponse : ODataResponse>
+ {
+ [JsonProperty("@odata.nextLink")]
+ public virtual string ODataNextLink { get; set; }
+
+ [JsonProperty("@odata.count")]
+ public virtual int? ODataCount { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Swashbuckle.OData/ODataResponse.cs b/Swashbuckle.OData/ODataResponse.cs
index 7d27318..2b0db0f 100644
--- a/Swashbuckle.OData/ODataResponse.cs
+++ b/Swashbuckle.OData/ODataResponse.cs
@@ -5,9 +5,9 @@ namespace Swashbuckle.OData
public class ODataResponse
{
[JsonProperty("@odata.context")]
- public string ODataContext { get; set; }
+ public virtual string ODataContext { get; set; }
[JsonProperty("value")]
- public TValue Value { get; set; }
+ public TValue Value { get; set; }
}
}
\ No newline at end of file
diff --git a/Swashbuckle.OData/ODataSwaggerDocsConfig.cs b/Swashbuckle.OData/ODataSwaggerDocsConfig.cs
index dd30031..ad64d57 100644
--- a/Swashbuckle.OData/ODataSwaggerDocsConfig.cs
+++ b/Swashbuckle.OData/ODataSwaggerDocsConfig.cs
@@ -7,6 +7,7 @@
using Swashbuckle.Application;
using Swashbuckle.OData.Descriptions;
using Swashbuckle.Swagger;
+using System.Xml.XPath;
namespace Swashbuckle.OData
{
@@ -95,8 +96,8 @@ private static IEnumerable GetParameterMappers()
internal SwashbuckleOptions GetSwashbuckleOptions()
{
AddGlobalDocumentFilters();
- AddODataDocumentFilters();
-
+ AddODataDocumentFilters();
+
var swaggerProviderOptions = new SwaggerProviderOptions(
_swaggerDocsConfig.GetFieldValue>("_versionSupportResolver"),
_swaggerDocsConfig.GetFieldValue>("_schemes"),
@@ -105,8 +106,8 @@ internal SwashbuckleOptions GetSwashbuckleOptions()
_swaggerDocsConfig.GetFieldValue>("_groupingKeySelector"),
_swaggerDocsConfig.GetFieldValue>("_groupingKeyComparer"),
GetODataCustomSchemaMappings(),
- _swaggerDocsConfig.GetFieldValue>>("_schemaFilters", true).Select(factory => factory()),
- _swaggerDocsConfig.GetFieldValue>>("_modelFilters", true).Select(factory => factory()),
+ _swaggerDocsConfig.GetFieldValue>>("_schemaFilters", true).Select(factory => factory()),
+ _swaggerDocsConfig.GetFieldValue>>("_modelFilters", true).Select(factory => factory()).ToList(),
_swaggerDocsConfig.GetFieldValue("_ignoreObsoleteProperties"),
_swaggerDocsConfig.GetFieldValue>("_schemaIdSelector"),
_swaggerDocsConfig.GetFieldValue("_describeAllEnumsAsStrings"),
@@ -114,8 +115,9 @@ internal SwashbuckleOptions GetSwashbuckleOptions()
GetODataOperationFilters(),
GetODataDocumentFilters(),
_swaggerDocsConfig.GetFieldValue, ApiDescription>>("_conflictingActionsResolver"),
- _swaggerDocsConfig.GetFieldValue("_applyFiltersToAllSchemas")
- );
+ _swaggerDocsConfig.GetFieldValue("_applyFiltersToAllSchemas"),
+ _swaggerDocsConfig.GetFieldValue>>("_xmlDocFactories").Select(factory=>factory).ToList()
+ );
return new SwashbuckleOptions(swaggerProviderOptions);
}
@@ -133,11 +135,11 @@ private IDictionary> GetODataCustomSchemaMappings()
///
/// Gets operation filters that will only be applied to OData operations.
///
- private IEnumerable GetODataOperationFilters()
+ private IList GetODataOperationFilters()
{
return _swaggerDocsConfig.GetFieldValue>>("_operationFilters", true)
.Select(factory => factory())
- .Concat(new EnableQueryFilter());
+ .Concat(new EnableQueryFilter()).ToList();
}
///
@@ -156,7 +158,7 @@ private IEnumerable GetODataDocumentFilters()
private void AddGlobalDocumentFilters()
{
_swaggerDocsConfig.DocumentFilter();
- }
+ }
///
/// Gets the API versions. I'd rather not use reflection because the implementation may change, but can't find a better way.
diff --git a/Swashbuckle.OData/SwaggerProviderOptions.cs b/Swashbuckle.OData/SwaggerProviderOptions.cs
index 5279c35..e40ab6e 100644
--- a/Swashbuckle.OData/SwaggerProviderOptions.cs
+++ b/Swashbuckle.OData/SwaggerProviderOptions.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Web.Http.Description;
using Swashbuckle.Swagger;
+using System.Xml.XPath;
namespace Swashbuckle.OData
{
@@ -16,15 +17,16 @@ public SwaggerProviderOptions(
IComparer groupingKeyComparer,
IDictionary> customSchemaMappings,
IEnumerable schemaFilters,
- IEnumerable modelFilters,
+ IList modelFilters,
bool ignoreObsoleteProperties,
Func schemaIdSelector,
bool describeAllEnumsAsStrings,
bool describeStringEnumsInCamelCase,
- IEnumerable operationFilters,
+ IList operationFilters,
IEnumerable documentFilters,
Func, ApiDescription> conflictingActionsResolver,
- bool applyFiltersToAllSchemas
+ bool applyFiltersToAllSchemas,
+ IList> xmlDocFactories
)
{
VersionSupportResolver = versionSupportResolver;
@@ -44,6 +46,7 @@ bool applyFiltersToAllSchemas
DocumentFilters = documentFilters;
ConflictingActionsResolver = conflictingActionsResolver;
ApplyFiltersToAllSchemas = applyFiltersToAllSchemas;
+ XmlDocFactories = xmlDocFactories;
}
public Func VersionSupportResolver { get; private set; }
@@ -62,7 +65,7 @@ bool applyFiltersToAllSchemas
public IEnumerable SchemaFilters { get; private set; }
- public IEnumerable ModelFilters { get; private set; }
+ public IList ModelFilters { get; private set; }
public bool IgnoreObsoleteProperties { get; private set; }
@@ -72,12 +75,14 @@ bool applyFiltersToAllSchemas
public bool DescribeStringEnumsInCamelCase { get; private set; }
- public IEnumerable OperationFilters { get; private set; }
+ public IList OperationFilters { get; private set; }
public IEnumerable DocumentFilters { get; private set; }
public Func, ApiDescription> ConflictingActionsResolver { get; private set; }
public bool ApplyFiltersToAllSchemas { get; private set; }
+
+ public IList> XmlDocFactories { get; private set; }
}
}
\ No newline at end of file
diff --git a/Swashbuckle.OData/Swashbuckle.OData.csproj b/Swashbuckle.OData/Swashbuckle.OData.csproj
index 8a7595c..bc5eb85 100644
--- a/Swashbuckle.OData/Swashbuckle.OData.csproj
+++ b/Swashbuckle.OData/Swashbuckle.OData.csproj
@@ -15,6 +15,10 @@
1
+ SAK
+ SAK
+ SAK
+ SAK
true
@@ -121,9 +125,15 @@
3
false
+
+ true
+
+
+ Swashbuckle.Odata.snk
+
-
- ..\packages\Flurl.1.1.2\lib\portable-net40+sl50+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Flurl.dll
+
+ ..\packages\Flurl.Signed.2.0.0\lib\portable-net40+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Flurl.dll
True
@@ -173,9 +183,11 @@
..\packages\Microsoft.AspNet.OData.6.0.0\lib\net45\System.Web.OData.dll
True
+
+
@@ -240,8 +252,11 @@
Designer
+
+
+
+
-