Poo*_*eld 10 c# asp.net odata asp.net-core-webapi
使用 Hassan Habib 的Supercharge ASP.NET Core API 和 OData博客文章中的示例代码,我能够使用 OData 查询获取记录计数$count=true:
需要配置什么才能将响应对象包装在 an 中,OData context以便显示该@odata.count属性?
在我自己的 ASP.NET Core Web API 项目中,我无法使用简单的$count参数,我也不知道为什么。
使用 Hassan 的示例代码,响应 JSON 被包装在 an 中OData context,有效负载(一个IEnumerable<Student>对象)位于valueJSON 响应的属性中。在我的项目中,OData context包装器不存在;我的代码从不返回OData context,它只返回类型的有效负载对象IEnumerable<T>:
我还注意到Content-Type响应头application/json; odata.metadata=minimal; odata.streaming=true; charset=utf-8中的 位于示例项目中,而它只是application/json; charset=utf-8在我的项目中。我在任何一个项目中都没有看到任何控制它的设置,所以我假设Microsoft.AspNetCore.OdataNuGet 包在正确配置时神奇地改变了响应。
我的项目也使用 .NET Core 2.2(从 2.1 升级),所有与 Hassan 示例项目相同版本的 NuGet 包,以及类中所有相同的设置StartUp.cs......虽然我StartUp.cs的方式更复杂(因此我我不会在这里发布它的内容。)
就我而言,我想扩展现有的 Api 方法,[EnableQuery]但让它包含计数元数据。
我最终扩展了 EnableQuery 属性以返回不同的响应,它工作得很好。
public class EnableQueryWithMetadataAttribute : EnableQueryAttribute
{
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
base.OnActionExecuted(actionExecutedContext);
if (actionExecutedContext.Result is ObjectResult obj && obj.Value is IQueryable qry)
{
obj.Value = new ODataResponse
{
Count = actionExecutedContext.HttpContext.Request.ODataFeature().TotalCount,
Value = qry
};
}
}
public class ODataResponse
{
[JsonPropertyName("@odata.count")]
public long? Count { get; set; }
[JsonPropertyName("value")]
public IQueryable Value { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
当我使用startup.cs时,我可以重现您的问题,如下[Route("api/[controller]")]所示:[ApiController]
app.UseMvc(routeBuilder =>
{
routeBuilder.Expand().Select().Count().OrderBy().Filter();
routeBuilder.EnableDependencyInjection();
});
Run Code Online (Sandbox Code Playgroud)
要修复此问题,请确保您已构建一个私有方法来在现有数据模型(本例中为 OData 模型)和 EDM 之间进行握手。
这是一个简单的演示:
Route1.Controller(属性和属性注释ApiController):
//[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;
}
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4776 次 |
| 最近记录: |