我正在尝试创建一个通用的 OData 控制器。我是根据做的this https://www.strathweb.com/2018/04/generic-and-dynamically-generated-controllers-in-asp-net-core-mvc link.
一切正常,但 http://localhost:65465/odata/Book 返回如下数据
[
{
"Id": 999,
"Title": null,
"Author": "Author 999"
}
]
代替
{
"@odata.context": "http://localhost:65465/odata/$metadata#Book",
"value": [
{
"Id": 999,
"Title": null,
"Author": "Author 999"
}]
}
经过进一步调查,我发现 edm 模型没有在通用控制器的 get 内的请求对象上设置。它似乎正在使用非OData路由;尽管所有 OData 过滤器、选择、orderby 都按预期工作。
请让我知道我缺少什么,它没有根据请求设置 edm 模型。
[Route("odata/[controller]")]
[Produces("application/json")]
public class CustomODataController<T> : ODataController where T : class,
ICustomEntity
{
[HttpGet]
[EnableQuery]
public IActionResult Get()
{
IEdmModel edmModel = Request.GetModel();
return Ok(_storage.GetAll().AsQueryable());
}
}
public class GenericTypeControllerFeatureProvider :IApplicationFeatureProvider<ControllerFeature>
{
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
{
var currentAssembly = typeof(GenericTypeControllerFeatureProvider).Assembly;
var candidates = currentAssembly.GetExportedTypes().Where(x => x.GetCustomAttributes<GeneratedControllerAttribute>().Any());
foreach (var candidate in candidates)
{
feature.Controllers.Add(typeof(CustomODataController<>).MakeGenericType(candidate).GetTypeInfo());
}
}
}
var mvcBuilder = services.AddMvc();
mvcBuilder.AddMvcOptions(o => o.Conventions.Add(new GenericControllerRouteConvention()));
mvcBuilder.ConfigureApplicationPartManager(c =>
{
c.FeatureProviders.Add(new GenericTypeControllerFeatureProvider());
});
app.UseMvc(b =>
{
GetEdmModel(), new DefaultODataPathHandler(),
routingConventions);
b.MapODataServiceRoute("ODataRoutes", "odata", GetEdmModel());
b.Expand().Select().Count().OrderBy().Filter();
b.EnableDependencyInjection();
});
private IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Book>(nameof(Book)).EntityType.Filter().OrderBy().Select();
var edmModel = builder.GetEdmModel();
return edmModel;
}
public class GenericControllerRouteConvention : IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
if (controller.ControllerType.IsGenericType)
{
var genericType = controller.ControllerType.GenericTypeArguments[0];
controller.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel(new RouteAttribute($"odata/{genericType.Name}"))
});
}
}
}