-
Notifications
You must be signed in to change notification settings - Fork 712
Net core odata with versioning and template in url prefix #529
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Yes - this type of configuration will work. I suspect that this is purely a matter of configuration. I was able to get things working using the provided Basic OData Example with versioning. First, change your route mapping to: routeBuilder.MapVersionedODataRoutes(
"odata",
"api/v{version:apiVersion}/tenants/{tenantId:guid}",
models ); Then, make sure that your controller has all of OData route attributes. I recommend going either full attribute-based or full convention-based. It's hard to rationalize things otherwise and the results will be unpredictable. Here's a modified version of the Orders controller that works: [ApiVersion( "1.0" )]
[ODataRoutePrefix( "Orders" )]
public class OrdersController : ODataController
{
// GET ~/api/tenants/{tenantId}/v1/orders
[ODataRoute]
public IActionResult Get( Guid tenantId ) =>
Ok( new[] { new Order() { Id = 1, Customer = "Bill Mei" } } );
// GET ~/api/tenants/{tenantId}/v1/orders/{id}
[ODataRoute( "{id}" )]
public IActionResult Get( Guid tenantId, [FromODataUri] int id ) =>
Ok( new Order() { Id = id, Customer = "Bill Mei" } );
} I hope that helps. |
Hello, thanks for the fast answer! I retired the example with your suggestion but still cannot get it to work. The method gets indeed called but the tenantId will always be the default value (Guid.Empty). I attached the small changed that i made to the example, maybe there really is something obvious that i am missing. Thanks again for the help. |
Confirmed. I guess I blew right past that very small, but important detail. Model binding in OData can be infuriating at times. Sometimes you need attribution and sometimes you don't. In general, I've started always adding the attributes (ex: In this case, you just need change the parameter to I hope that helps. |
Thanks! With the extra attribute i got it to work! Next step for me was to try Swagger to get the parameter. Here its strange again. ODataQueryOptions seems to be expanded to more than 1700 query fields. I filtered it via an IOperationFilter with
but the output still is not correct. TenantId is now present twice for some reason and there are not all fields that are allowed present. What do I need to do to get the ODataQueryOptions properly read? Do I need to do something special? My Odata.ApiExplorer nuget is at version 3.2.2. |
1700?! That definitely doesn't sound right. ODataQueryOptions and ODataQueryOptions<T> should be ignored completely. They have a special parameter source that should result in them being ignored. What is the method signature of the action that causes this? The duplicate |
I would assume that for the same reason that the FromRoute attribute is required the tenantId is not properly matched.
for some reason i don't see the same behaviour in the example but cant see any difference in the config. For me it seems that the ODataQueryOptions class is not being recognized as a special type. There are no errors in the log so its very hard for me to pinpoint. So a pointer on what i can look for is highly appreciated. |
Hmmm... I know for sure that ODataQueryOptions, Delta, and a few other types have special handling by the OData model binder. This results in them not requiring attribution for them to resolve. They report themselves to the API Explorer as Custom or Special. This is similar to the behavior of CancellationToken and, now, the ApiVersion if defined as a parameter in your action. Do you have a partial sample (or repro) that demonstrates the options exploding? Do you have an example of one or more parameters that should not be there? From your description, it sounds like you're getting a bunch of junk. I do know, and recently faced a somewhat similar situation, that ASP.NET Core intrinsically handles complex model binding from a URL. This means that if you forget to use |
I believe the latest patch should fix the duplicate route template parameter issue. Were you able to confirm that? Were you also able to solve the query option explosion issue? |
Ok, i will try the new patch, thanks a lot! This week I could not really spend a lot of time to reproduce it but it behaved strange in general. Once I added AllowedQueryOptions the tenantid was still only taken from the querystring and not the route, when I only had the EnableQuery attribute it started working again. Then I did a request via swagger and subsequent calls always returned the default value. |
I spent a bit more time with it and worked from another angle. I created a new project with the same template as before (with angular), added an odata controller to it and can get the same behaviour. Unfortunately the project is not that small but it might still help to pinpoint the issue with swagger. |
As a workaround I am using this to filter all ODataQueryOptions fields in a IOperationFilter
|
I found out the following:
News:
How you can reproduce that:
May that will help you to help us to solve the problem :-) |
Thanks @orphisAG. This will be very useful is the investigation. |
Another information I found out: ModelBuilder: Controller: My attribute name was "activity" on the controller and ODataQueryOptions was not ignored in the documentation (Swagger). Then I renamed it to "Activity" and then it starts working. |
I got the same problem so i did some digging and found out why it marks it as query instead of body. src/Microsoft.AspNetCore.OData.Versioning.ApiExplorer/AspNetCore.Mvc.ApiExplorer/ODataApiDescriptionProvider.cs `static void UpdateBindingInfo( ApiParameterContext context, ParameterDescriptor parameter, ModelMetadata metadata ) {
}` So IsSpecialBindingSource needs to be changed to allow delta and body i think. |
Finally, circling back around... @GerjanVlot are you saying that the BindingSource for @ALL the controller name must match the entity set name. The ODataRoutePrefix does not influence the name that is used. I can't say why a name mismatch would cause this parameter explosion. Perhaps it's something of a union between multiple versions. Resuming investigation... |
@commonsensesoftware https://1drv.ms/v/s!Alu0uzi9pf9UhYEOVTxLQSqr7qQkkQ?e=2BOqjL Does this give you more context? |
@GerjanVlot a little. With the The video helps quite a bit. It's strange that the operation would not be for an entity set. That may be the culprit. This appears to be a vanilla
|
Hello,
it might be a stupid question but I coudn't find anything in the documentation about it.
The idea is to pass a tenantId in the URL and process that in a ODataController to select the current tenant. It should not be part of the odata query so I wanted to have it in such a setup.
I have a route setup like this
routes.MapVersionedODataRoutes("odata-bypath", "api/v{version:apiVersion}/tenants/{tenantId}", models);
and a controller such as
When accessing api/v1/tenants/00000000-0000-0000-0000-000000000001 i get the odata context as expected.
However, when accessing api/v1/tenants/00000000-0000-0000-0000-000000000001/WorkItemSearch i get a 404.
I also tried /api/v1/tenants/00000000-0000-0000-0000-000000000001/WorkItemSearch/00000000-0000-0000-0000-000000000001 just to make sure but there I get the same 404 response.
Swagger reports api/v1/tenants/{tenantId} as the path to the controller so I don't know what is going wrong.
Any ideas?
Thanks,
Klemens
The text was updated successfully, but these errors were encountered: