Comments (12)
I did some more research and debug the Swashbuckle.Odata code. Figure i'll help debug the issue and make it easier for you.
private static ODataPath GenerateSampleODataPath(ODataRoute oDataRoute, string sampleODataAbsoluteUri)
{
var oDataPathRouteConstraint = oDataRoute.GetODataPathRouteConstraint();
var model = oDataRoute.GetEdmModel();
string route = ServiceRoot.AppendPathSegment(oDataRoute.RoutePrefix);
ODataPath path = oDataPathRouteConstraint.PathHandler.Parse(model, route, sampleODataAbsoluteUri);
return path;
}
So the issue happens when it tries to Parse the IODataPathHandler. For some reason it cannot convert the parameters:
ServiceRoute: "http://any/"
route: "http://any/odata"
sampleODataAbsoluteUri : "http://any/odata/Orders(42)/Customers"
It throws an ODataException with an error message "Bad Request - Error in query syntax.".
But it's able to parse this successfully:
ServiceRoute: "http://any/"
route: "http://any/odata"
sampleODataAbsoluteUri : "http://any/odata/Customers(42)/Orders"
In the config file:
config.AddCustomSwaggerRoute(customODataRoute, "/Customers({Id})/Orders")
.Operation(HttpMethod.Post)
.PathParameter<int>("Id")
.BodyParameter<Order>("order");
config.AddCustomSwaggerRoute(customODataRoute, "/Orders({orderID})/Customers")
.Operation(HttpMethod.Post)
.PathParameter<int>("orderID")
.BodyParameter<Customer>("customer");
CustomersController:
public Task Post([FromODataUri] int orderID, Customer customer)
{
throw new NotImplementedException();
}
OrdersController:
public async Task Post([FromODataUri] int customerId, Order order)
{
order.OrderId = SequentialGuidGenerator.Generate(SequentialGuidType.SequentialAtEnd);
order.CustomerId = customerId;
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_db.Orders.Add(order);
await _db.SaveChangesAsync();
return Created(order);
}
It's not clear what is missing in the model that is causing the exception to be thrown when it tries to parse the OData path.
Source Code of Sample project:
from swashbuckle.odata.
ok. thanks for the investigation! it helps.
from swashbuckle.odata.
This configuration:
config.AddCustomSwaggerRoute(customODataRoute, "/Orders({orderID})/Customers")
.Operation(HttpMethod.Post)
.PathParameter<int>("orderID")
.BodyParameter<Customer>("customer");
and this controller action:
[ResponseType(typeof(Customer))]
public Task<IHttpActionResult> Post([FromODataUri] int orderID, Customer customer)
{
throw new NotImplementedException();
}
won't work because the Order entity has a primary key of type GUID.
I'll investigate the issue reported in your original post. I.e.,
I'm having issue displaying other custom route other then HttpMethod.Post & HttpMethod.Get
from swashbuckle.odata.
This path in your original post does not look correct:
config.AddCustomSwaggerRoute(customODataRoute, "/Customers({Id})/Orders/({orderID}")
You don't have a closing parenthesis on the orderID... Maybe you don't even want the opening parenthesis? Also, do you want the forward slash after Orders?
from swashbuckle.odata.
@darewreck54 A fix is available in v2.8.1. FYI, your custom route config should look like:
config.AddCustomSwaggerRoute(customODataRoute, "/Customers({Id})/Orders({orderID})")
.Operation(HttpMethod.Delete)
.PathParameter<int>("Id")
.PathParameter<Guid>("orderID");
and the OrdersController action:
public async Task<IHttpActionResult> Delete([FromODataUri] int customerId, [FromODataUri] Guid orderID)
{
throw new NotImplementedException();
}
See this unit test.
from swashbuckle.odata.
Thanks,
config.AddCustomSwaggerRoute(customODataRoute, "/Customers({Id})/Orders({orderID})")
.Operation(new HttpMethod("PATCH"))
.PathParameter("Id")
.PathParameter("orderID")
.BodyParameter("order");
with action:
public async Task Patch([FromODataUri] int customerId, [FromODataUri] Guid orderID, Order order)
{
throw new NotImplementedException();
}
This will result in issues with the swagger UI. Order Controller will not render at all.
Also is there a better way for error handling. It seems if if there is any issues with the configuration, you will either get controllers that do not render (user may never know) or stacktraces where it's hard to really determine what went wrong (A case is when you have incorrect parameters like you pointed out in my code)
If you update your unit test with:
[Test]
public async Task It_allows_definition_of_custom_patch_routes()
{
using (WebApp.Start(HttpClientUtils.BaseAddress, builder => Configuration(builder, typeof(OrdersController))))
{
// Arrange
var httpClient = HttpClientUtils.GetHttpClient(HttpClientUtils.BaseAddress);
// Act
var swaggerDocument = await httpClient.GetJsonAsync<SwaggerDocument>("swagger/docs/v1");
// Assert
PathItem pathItem;
swaggerDocument.paths.TryGetValue("/odata/Customers({Id})/Orders({orderID})", out pathItem);
pathItem.Should().NotBeNull();
pathItem.patch.Should().NotBeNull();
await ValidationUtils.ValidateSwaggerJson();
}
}
and
private static void Configuration(IAppBuilder appBuilder, Type targetController)
{
var config = appBuilder.GetStandardHttpConfig(targetController);
// Define a custom route with custom routing conventions
var conventions = ODataRoutingConventions.CreateDefault();
conventions.Insert(0, new CustomNavigationPropertyRoutingConvention());
var customODataRoute = config.MapODataServiceRoute("CustomODataRoute", "odata", GetCustomRouteModel(), batchHandler: null, pathHandler: new DefaultODataPathHandler(), routingConventions: conventions);
config.AddCustomSwaggerRoute(customODataRoute, "/Customers({Id})/Orders")
.Operation(HttpMethod.Post)
.PathParameter<int>("Id")
.BodyParameter<Order>("order");
config.AddCustomSwaggerRoute(customODataRoute, "/Customers({Id})/Orders({orderID})")
.Operation(HttpMethod.Delete)
.PathParameter<int>("Id")
.PathParameter<Guid>("orderID");
config.AddCustomSwaggerRoute(customODataRoute, "/Customers({Id})/Orders({orderID})")
.Operation(new HttpMethod("PATCH"))
.PathParameter<int>("Id")
.PathParameter<Guid>("orderID")
.BodyParameter<Order>("order");
config.EnsureInitialized();
}
all the custom route test will fail now.
from swashbuckle.odata.
You're welcome,
I'll research the PATCH issue. Re-opening this issue.
Also is there a better way for error handling
I'm working on some error handling now that might help. Yeah, it's sometimes hard for me (and users) to determine the root cause/scenario for an issue. Better handling will develop over time as the assumptions are understood and documented. Suggestions and, better yet, pull requests are welcome. Thanks!
from swashbuckle.odata.
Actually, I found the problem. It deals with the CustomNavigationPropertyRoutingConvention class and how you have to specify the correct parameters for each controller.
This is the updated code to make the new test changes I put above:
else if (typeof(OrdersController) == controllerType)
{
if (odataPath.PathTemplate.Equals("/entityset/key/navigation")) //POST OR GET/entityset/key/navigation/key")) //PATCH OR DELETE
{
controllerContext.RouteData.Values["customerID"] = (odataPath.Segments[1] as KeyValuePathSegment).Value;
return controllerContext.Request.Method.ToString();
}
if (odataPath.PathTemplate.Equals("
{
controllerContext.RouteData.Values["customerID"] = (odataPath.Segments[1] as KeyValuePathSegment).Value;
controllerContext.RouteData.Values["orderID"] = (odataPath.Segments[3] as KeyValuePathSegment).Value;
return controllerContext.Request.Method.ToString();
}
}
Notice the "orderID" matches with the controller Patch function and the configuration parameters in the .PathParamter.
I guess when you use custom routing, with the way it's implemented you have to be very careful.
Removing the need to specify the addition routes via config.AddCustomSwaggerRoute() would help elevate this problem which is more of a feature enhancement as discussed in previous issues.
Thanks,
D
from swashbuckle.odata.
As the root cause of the issue you mentioned and resolved isn't in the Swashbuckle.OData code base, I'm closing this issue. Thanks.
from swashbuckle.odata.
@darewreck54 - after 2 years now.. do you know if AddCustomSwaggerRoute
now supports PATCH.. or is there a link you can post to the issue in the Swashbuckle.OData code base (was an issue opened?)
UPDATE: I misread @ghost's comment above. Disregard. I now see what you guys are talking about
from swashbuckle.odata.
from swashbuckle.odata.
The other side of the coin is correctly describing custom PATCH actions in WebApiConfig.cs using the ODataConventionModelBuilder
- getting all the stars to align is a non-trivial task
from swashbuckle.odata.
Related Issues (20)
- SchemaRegistryExtensions.GetPropertyNameForEdmModel returns wrong Edm Property name HOT 2
- Calling for Maintainers HOT 6
- Swagger generation resulting in error. Error thrown from SwaggerRouteStrategy.cs line 62
- AdjustRelativePathForStringParams is not working case-insensitive (param names)
- Method not found: 'Flurl.Url Flurl.Url.AppendPathSegment(System.Object)' HOT 1
- Precondition Failure
- Swagger docs don't have type information for Get method when it returns IHttpActionResult HOT 2
- Add custom property resolver to 4.0.0
- Unbound actions generate invalid swagger HOT 2
- Entity bound actions can have ODataActionParameters type parameters only
- Custom type parameters for OData functions HOT 1
- Exploring different version at the same time throw an error.
- Support for Microsoft.AspNet.OData 7? HOT 10
- Swashbuckle.OData.Core throws Specified argument was out of the range of valid values exception and failing to generate swagger ui HOT 1
- Need Help OData V4 REST Web API Documentation HOT 4
- Swashbuckle.OData.Core is too slow, consume 60% memory while open swagger in chrome browser HOT 4
- OData Web API Controller Summary not showing in swagger
- Swashbuckle.OData compatibility with OData V3 Controllers HOT 1
- Swagger generation fails for Entities having DataContractAttribute fails with "Sequence contains no matching element" when used in OData Actions. HOT 1
- Accurate OData response schema
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from swashbuckle.odata.