Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

OData API explorer only showing $select and $expand, help #1038

Discussion options

Hi,

Does anyone know what might cause the API explorer to only show $select and $expand query options sometimes?

I've enabled all query options globally and query options like $filter do actually work, but they are simply not showing up in Swagger for some unknown reason.

image

I'm still targeting .NET 6.0, maybe I'm using an invalid combination of packages?

<ItemGroup>
 <PackageReference Include="Asp.Versioning.OData" Version="6.4.0" />
 <PackageReference Include="Asp.Versioning.OData.ApiExplorer" Version="6.4.1" />
 <PackageReference Include="Microsoft.AspNetCore.OData" Version="8.2.3" />
 <PackageReference Include="Microsoft.OData.Core" Version="7.18.0" />
 <PackageReference Include="Microsoft.OpenApi" Version="1.4.4" />
 <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>

My middleware pipeline config:

var mvc = services.AddControllers();
services.AddEndpointsApiExplorer();
mvc.AddOData((odata, sp) =>
{
 // Enable all query features globally
 // You can restrict features per endpoint using [EnableQuery(AllowedQueryOptions = ...)]
 odata.EnableQueryFeatures(maxTopValue: 100);
});
var versioning = services.AddApiVersioning(options =>
 {
 options.DefaultApiVersion = new ApiVersion(4, 0);
 // Reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions"
 options.ReportApiVersions = true;
 // Allows a client to make a request without specifying an api-version
 // The value of options.DefaultApiVersion will be assumed
 options.AssumeDefaultVersionWhenUnspecified = true;
 });
versioning.AddOData((odata) =>
{
 odata.AddRouteComponents("odata");
});
versioning.AddODataApiExplorer(options =>
{
 // Add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
 // Note: the specified format code will format the version as "'v'major[.minor][-status]"
 options.GroupNameFormat = "'v'VVV";
});

My controller:

I noticed the use of ProducesAttribute and ProducesResponseTypeAttribute affects the OData API explorer? Maybe not in a good way.

[ApiVersion(4.0)]
public class DocumentsController : ODataController
{
 private ILogger<DocumentsController> _logger;
 public DocumentsController(ILogger<DocumentsController> logger)
 {
 _logger = logger;
 }
 [EnableQuery]
 [Produces("application/json")]
 [ProducesResponseType(typeof(IQueryable<DocumentODataDTO>), Status200OK)]
 [ProducesResponseType(Status400BadRequest)]
 [ProducesResponseType(Status401Unauthorized)]
 [ProducesResponseType(Status403Forbidden)]
 public async Task<ActionResult<IQueryable<DocumentODataDTO>>> GetDocuments(
 [FromHeader(Name = "X-BusinessUnitCode"), Required] string businessUnit,
 [FromServices] IMediator mediator,
 [FromServices] IConfigurationProvider mapperConfiguration,
 CancellationToken ct)
 {
 
 }

If I remove the Produces attributes then I get the desired behavior, i.e. all OData query options are available in Swagger.

I might just be using the attributes incorrectly?

Thanks for any help.

You must be logged in to vote

OData, both in protocol and implementation, only supports returning JSON or XML. To be fully compliant, the payloads are supersets that are specific to OData. You cannot return just any 'ol JSON. I'm not sure if XML is even still supported. I know it's not by default.

In the context of OData, there should be no need to specify [Produces]. OData-based responses will list the equivalent values from the OData InputFormatter and OutputFormatter implementations. The API Explorer knows that the results are for OData because you are using ODataController, which has [ODataRouting] applied. You should notice that there are actually several media types reported (but you probably expected one). You'...

Replies: 1 comment 4 replies

Comment options

OData, both in protocol and implementation, only supports returning JSON or XML. To be fully compliant, the payloads are supersets that are specific to OData. You cannot return just any 'ol JSON. I'm not sure if XML is even still supported. I know it's not by default.

In the context of OData, there should be no need to specify [Produces]. OData-based responses will list the equivalent values from the OData InputFormatter and OutputFormatter implementations. The API Explorer knows that the results are for OData because you are using ODataController, which has [ODataRouting] applied. You should notice that there are actually several media types reported (but you probably expected one). You're free to filter down things how you like, but that is the true set of supported media types.

I have also found Swashbuckle was adding application/json if it wasn't specified, which is usually undesired and possibly problematic. The OData with OpenAPI example shows how to deal with that:

foreach ( var responseType in context.ApiDescription.SupportedResponseTypes )
You must be logged in to vote
4 replies
Comment options

Thanks, I removed the attributes, everything seems to work as expected now.

I don't really understand how content negotiation works in OData. I can see the media types you are talking about, but I've no clue what they are used for.

application/json;odata.metadata=minimal;odata.streaming=true
application/json;odata.metadata=minimal;odata.streaming=false
application/json;odata.metadata=minimal
application/json;odata.metadata=full;odata.streaming=true
application/json;odata.metadata=full;odata.streaming=false
application/json;odata.metadata=full
application/json;odata.metadata=none;odata.streaming=true
application/json;odata.metadata=none;odata.streaming=false
application/json;odata.metadata=none
application/json;odata.streaming=true
application/json;odata.streaming=false
application/json
application/xml
text/plain
application/octet-stream
text/json
Comment options

These are defined in the OData JSON Format v4.01 specification. streaming only applies if you are streaming content such as files (ex: images). metadata controls what, if any, OData metadata is returned. application/json will always work, but with assumed values for other parameters. Selecting different media types, particularly with metadata, should produce slightly different responses depending on the API.

Comment options

Okay that's pretty clear, thanks. I found the SwaggerDefaultValues workaround is not really needed? At least in my API project,

 // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1752#issue-663991077
 foreach ( var responseType in context.ApiDescription.SupportedResponseTypes )
 {
 // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/b7cf75e7905050305b115dd96640ddd6e74c7ac9/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs#L383-L387
 var responseKey = responseType.IsDefaultResponse ? "default" : responseType.StatusCode.ToString();
 var response = operation.Responses[responseKey];
 foreach ( var contentType in response.Content.Keys )
 {
 if ( !responseType.ApiResponseFormats.Any( x => x.MediaType == contentType ) )
 {
 response.Content.Remove( contentType );
 }
 }
 }

if I put a breakpoint on response.Content.Remove, it is never reached? I did remove all Produces attributes from my controller, so I guess maybe that's expected. Although I can still see the non-odata media types in Swagger, so I'm confused again. 😄

Comment options

The ODataInputFormatter and ODataOutputFormatter get their media types from:

https://github.com/OData/AspNetCoreOData/blob/main/src/Microsoft.AspNetCore.OData/Formatter/MediaType/ODataMediaTypes.cs#L20

The last few: text/plain, application/octet-stream, and text/json may be coming from another formatter. The reported media types is a union of everything defined. text/json is a valid, alternative media type, but is hardly used anymore. text/plain does show up out-of-the-box for return scalar values, even when it might still be valid JSON (it's actually ambiguous). application/octet-stream is a catch-all, but is usually for files. If you don't use any of these, it might be worth filtering them out.

Answer selected by sliekens
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /