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
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:
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:
It doesn't show anything!
This is my 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();
}
}
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 .
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.
My understanding is that the combination of:
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With