-
Notifications
You must be signed in to change notification settings - Fork 161
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
Odata is not compatible with AddOpenApi of Microsoft.AspNetCore.OpenApi #1381
Comments
@Angelinsky7 would you mind sharing a link to where that recommendation is made? That sounds like bad advice to me. I assume it is linked to the requirement that Yet another reason to consider deprecating routing conventions in OData (IMHO). |
@julealgon thanks for your answer... here you can find it : https://github.com/OData/AspNetCoreOData/blob/main/docs/routing-pitfalls.md the thing is that to make odata works correctly the only solution that i have found is to EXACTLY do the incorrect code... some code for those you are interested to try to make this work correctly Program.cs builder.Services.AddControllersWithViews()
.AddApplicationPart(typeof(_ApiAssembly).Assembly)
.AddControllersAsServices()
.AddOData(options => {
options.EnableAttributeRouting = true;
options.TimeZone = TimeZoneInfo.Utc;
options.EnableQueryFeatures();
options.RouteOptions.EnableNonParenthesisForEmptyParameterFunction = true;
options.RouteOptions.EnableActionNameCaseInsensitive = true;
options.RouteOptions.EnableControllerNameCaseInsensitive = true;
options.RouteOptions.EnablePropertyNameCaseInsensitive = true;
options.RouteOptions.EnableKeyAsSegment = true;
options.RouteOptions.EnableKeyInParenthesis = false;
options.AddRouteComponents(routePrefix: "api", model: modelBuilder.GetEdmModel(), configureServices: services => {
//services.AddSingleton<IFilterBinder, CustomFilterBinder>();
services.AddOdataLinkProvider(typeof(_ApiAssembly).Assembly);
services.AddSingleton<IODataSerializerProvider, CustomODataSerializerProvider>();
});
})
.AddJsonOptions(options => {
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
builder.Services.AddOpenApi(); ModelBuilder EntitySetConfiguration<Thing> entitySet = modelBuilder.EntitySet<Thing>("things");
EntityTypeConfiguration<Thing> entityType = entitySet .EntityType;
entityType .HasKey(p => p.Id); Controller using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Results;
using Microsoft.AspNetCore.OData.Routing.Controllers;
using Microsoft.EntityFrameworkCore;
namespace Controllers {
[ApiController]
[Route("/api/things")]
public class ThingsController : ODataController {
[HttpGet]
[EnableQuery]
[ProducesResponseType(typeof(PageResult<Thing>), statusCode: (Int32)HttpStatusCode.OK)]
public async Task<ActionResult<IAsyncEnumerable<Thing>>> Get(CancellationToken cancellationToken = default) {}
[HttpGet("{key}")]
[EnableQuery]
[ProducesResponseType(typeof(SingleResult<Thing>), statusCode: (Int32)HttpStatusCode.OK)]
[ProducesResponseType(typeof(ProblemDetails), statusCode: (Int32)HttpStatusCode.NotFound)]
[ProducesResponseType((Int32)HttpStatusCode.BadRequest)]
[ProducesResponseType((Int32)HttpStatusCode.InternalServerError)]
public async Task<IActionResult> GetById([FromRoute] Int64 key, CancellationToken cancellationToken = default) {}
[HttpPost]
[ProducesResponseType(typeof(CreatedAtActionResult), statusCode: (Int32)HttpStatusCode.OK)]
[ProducesResponseType(typeof(ProblemDetails), statusCode: (Int32)HttpStatusCode.NotFound)]
[ProducesResponseType((Int32)HttpStatusCode.BadRequest)]
[ProducesResponseType((Int32)HttpStatusCode.InternalServerError)]
public async Task<IActionResult> Post([FromBody] ThingCreateRequest request, CancellationToken cancellationToken = default) {}
[HttpPut("{key}")]
[ProducesResponseType((Int32)HttpStatusCode.NoContent)]
[ProducesResponseType(typeof(ProblemDetails), statusCode: (Int32)HttpStatusCode.NotFound)]
[ProducesResponseType((Int32)HttpStatusCode.BadRequest)]
[ProducesResponseType((Int32)HttpStatusCode.InternalServerError)]
public async Task<IActionResult> Put([FromRoute] Int64 key, [FromBody] ThingUpdateRequest request, CancellationToken cancellationToken = default) {}
[HttpDelete("{key}")]
[ProducesResponseType((Int32)HttpStatusCode.NoContent)]
[ProducesResponseType(typeof(ProblemDetails), statusCode: (Int32)HttpStatusCode.NotFound)]
[ProducesResponseType((Int32)HttpStatusCode.BadRequest)]
[ProducesResponseType((Int32)HttpStatusCode.InternalServerError)]
public async Task<IActionResult> Delete([FromRoute] Int64 key, CancellationToken cancellationToken = default) {}
}
} Model namespace Models {
public class Thing {
public Int64 Id { get; set; } = default!;
public required String Name { get; set; }
}
} With all of this... everything is working... in $odata i have everything in duplicate but it's working correctly. |
Yep.... this is a known problem: You can work around it by either making sure your methods don't match the built-in conventions (super cryptic approach, wouldn't recommend), or by disabling the OData route conventions (also not great as there is no "simple" API to do that, but is usually what I'd suggest). The only other comments I'd add based on your example @Angelinsky7 is that you can use API conventions to simplify some of that nasty And I would strongly recommend leveraging |
thanks i didn't know the api conventions things... and will do the stronger types for ActionResult... |
Assemblies affected
Microsoft.AspNetCore.OpenApi: 9.0.0
Microsoft.AspNetCore.OData: 9.1.1
Describe the bug
To be able to use
AddOpenApi
andMapOpenApi
the controllers need to have aApiControllerAttribute
but Odata documentation ask use to remove it. The controller is then not found inside the openApi document.The actual snippet of code to add openApiDocument create another document instead of adding the routes inside the already created document.
I would like to have only one openApi document and a usable openapi.json file.
Is there a workaround to be able to use
ApiController
and OData (without removing all routing conventions or have duplicate actions ? )Thanks !
The text was updated successfully, but these errors were encountered: