Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add Swagger in OData-enabled Web API running on ASP.NET Core 3.1

I want to use both OData and Swagger in my Web API. I'm running ASP.NET Core 3.1.

I have found these articles, one to enable OData and another to enable SwaggerUI

  • Enable OData: https://devblogs.microsoft.com/odata/enabling-endpoint-routing-in-odata/
  • Enable Swagger: https://www.coderjony.com/blogs/adding-swagger-to-aspnet-core-31-web-api/

However, I can't seem to enable both at the same time. It seems that I'm mixing them wrong.

This is the code that I have currently:

Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddOData();
        AddSwagger(services);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();
        app.UseRouting();
        app.UseAuthorization();

        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "Foo API V1");
        });

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.Select().Filter().OrderBy().Count().MaxTop(10);
            endpoints.MapODataRoute("odata", "odata", GetEdmModel());
        });
    }

    private IEdmModel GetEdmModel()
    {
        var odataBuilder = new ODataConventionModelBuilder();
        odataBuilder.EntitySet<WeatherForecast>("WeatherForecast");

        return odataBuilder.GetEdmModel();
    }

    private void AddSwagger(IServiceCollection services)
    {
        services.AddSwaggerGen(options =>
        {
            var groupName = "v1";

            options.SwaggerDoc(groupName, new OpenApiInfo
            {
                Title = $"Foo {groupName}",
                Version = groupName,
                Description = "Foo API",
                Contact = new OpenApiContact
                {
                    Name = "Foo Company",
                    Email = string.Empty,
                    Url = new Uri("https://example.com/"),
                }
            });
        });
    }
}

It works when I go to https://localhost:44363/odata/weatherforecast But when I try to load the Swagger interface, this is showing:

enter image description here

It doesn't show anything!

This is my controller:

Controller

[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };
    
    [EnableQuery]
    public IEnumerable<WeatherForecast> Get()
    {
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Id = Guid.NewGuid(),
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
    }
}
like image 560
SuperJMN Avatar asked Jun 16 '20 08:06

SuperJMN


People also ask

How do I add Swagger to .NET core Web API?

Add and configure Swagger middleware Launch the app and navigate to https://localhost:<port>/swagger/v1/swagger.json . The generated document describing the endpoints appears as shown in OpenAPI specification (openapi. json). The Swagger UI can be found at https://localhost:<port>/swagger .

What is ASP Net Web API OData?

The Open Data Protocol (OData) is a data access protocol for the web. OData provides a uniform way to query and manipulate data sets through CRUD operations (create, read, update, and delete). ASP.NET Web API supports both v3 and v4 of the protocol.


Video Answer


1 Answers

My understanding is that the combination of:

  • ASP.NET Core 3.1
  • Endpoint routing
  • OData (even 7.4+)
  • Swagger

does not really work at this time because there is no good ApiExplorer implementation for OData controllers/routing. However, I had the same issue and I was able to make actions appear in Swagger/UI using this :

[ApiExplorerSettings(IgnoreApi = false)]
[Route("Data")]
[HttpGet]
public async Task<IEnumerable<Data>> GetData()
{
  // ...
}

and by applying this in Startup code (adapted from This) :

services.AddControllers(options =>
{
    IEnumerable<ODataOutputFormatter> outputFormatters =
        options.OutputFormatters.OfType<ODataOutputFormatter>()
            .Where(formatter => !formatter.SupportedMediaTypes.Any());

    foreach (var outputFormatter in outputFormatters)
    {
        outputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/odata"));
    }

    IEnumerable<ODataInputFormatter> inputFormatters =
        options.InputFormatters.OfType<ODataInputFormatter>()
            .Where(formatter => !formatter.SupportedMediaTypes.Any());

    foreach (var inputFormatter in inputFormatters)
    {
        inputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/odata"));
    }
});

However, this works for some actions but I do not think this is a good fix since it forces you to reproduce OData conventions routing with non-OData API routing metadata ([Route] + HTTP verbs attributes) everywhere. This is non-sense !

It would be wonderful to be able to automatically generate an OpenAPI document from the entire API, using EDM and OData conventions...

Resources:

  • https://github.com/OData/WebApi/issues/2024
  • https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/581#issuecomment-482747072
like image 102
Aloene Avatar answered Sep 17 '22 19:09

Aloene