问题
Using the sample code from Hassan Habib's Supercharging ASP.NET Core API with OData blog post, I am able to get the record count using an OData query of $count=true
:
What needs to be configured to get the response object to be wrapped in an OData context
so that the @odata.count
property will show?
In my own ASP.NET Core web API project, I cannot get the simple $count
parameter to work and I have no idea why.
With Hassan's sample code, the response JSON is wrapped in an OData context
and the payload (an IEnumerable<Student>
object) is in the value
property of the JSON response. In my project, the OData context
wrapper does not exist; my code never returns OData context
, it only returns the payload object of type IEnumerable<T>
:
I've also noticed that the Content-Type
in the response header is application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8
in the sample project, where as it is simply application/json; charset=utf-8
in my project. I don't see any setting that controls this in either project, so I'm assuming the Microsoft.AspNetCore.Odata
NuGet package is magically changing the response when it's configured properly.
My project is also using .NET Core 2.2 (Upgraded from 2.1), all the same versions of NuGet packages as Hassan's sample projects, and all the same settings in the StartUp.cs
class... although my StartUp.cs
is way more complicated (hence the reason I'm not posting it's content here.)
回答1:
I could reproduce your issue when i use [Route("api/[controller]")]
and [ApiController]
with the startup.cs like below:
app.UseMvc(routeBuilder =>
{
routeBuilder.Expand().Select().Count().OrderBy().Filter();
routeBuilder.EnableDependencyInjection();
});
To fix it,be sure you have built a private method to do a handshake between your existing data models (OData model in this case) and EDM.
Here is a simple demo:
1.Controller(comment on Route
attribute and ApiController
attribute):
//[Route("api/[controller]")]
//[ApiController]
public class StudentsController : ControllerBase
{
private readonly WSDbContext _context;
public StudentsController(WSDbContext context)
{
_context = context;
}
// GET: api/Students
[HttpGet]
[EnableQuery()]
public IEnumerable<Student> Get()
{
return _context.Students;
}
}
//[Route("api/[controller]")]
//[ApiController]
public class SchoolsController : ControllerBase
{
private readonly WSDbContext _context;
public SchoolsController(WSDbContext context)
{
_context = context;
}
// GET: api/Schools
[HttpGet]
[EnableQuery()]
public IEnumerable<School> Get()
{
return _context.Schools;
}
2.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.AddMvcCore(action => action.EnableEndpointRouting = false);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
var connection = @"Server=(localdb)\mssqllocaldb;Database=WSDB;Trusted_Connection=True;ConnectRetryCount=0";
services.AddDbContext<WSDbContext>(options => options.UseSqlServer(connection));
services.AddOData();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc(routeBuilder =>
{
routeBuilder.Expand().Select().Count().OrderBy().Filter();
routeBuilder.MapODataServiceRoute("api", "api", GetEdmModel());
});
}
private static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Student>("Students");
builder.EntitySet<Student>("Schools");
return builder.GetEdmModel();
}
}
来源:https://stackoverflow.com/questions/58838970/getting-odata-count-in-asp-net-core-webapi