我正在尝试创建一个通用的OData控制器。我是根据 this链接。
一切正常;但是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"
}]
}
在进一步调查中,我发现在通用控制器的get内未在请求对象上设置edm模型。似乎正在使用非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}"))
});
}
}
}
答案 0 :(得分:0)
我使用不同的选项进行播放,最后能够使用通用控制器上的属性使它正常工作
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class GenericControllerNameConventionAttribute : Attribute, IControllerModelConvention
{
public void Apply(ControllerModel controller)
{
if (controller.ControllerType.GetGenericTypeDefinition() !=
typeof(CustomODataController<>))
{
// Not a GenericController, ignore.
return;
}
var entityType = controller.ControllerType.GenericTypeArguments[0];
controller.ControllerName = entityType.Name;
}
}
[Produces("application/json")]
[GenericControllerNameConvention]
public class CustomODataController<T> : ODataController where T : class, IDataEntity
{
private Storage<T> _storage;
public CustomODataController(Storage<T> storage)
{
_storage = storage;
}
[HttpGet]
[EnableQuery]
public IActionResult Get()
{
return Ok(_storage.GetAll().AsQueryable());
}
[EnableQuery]
public SingleResult<T> Get([FromODataUri] int key)
{
return SingleResult.Create(_storage.GetAll().Where( n => n.Id == key).AsQueryable());
}
[HttpPost]
[EnableQuery]
public IActionResult Post([FromBody]T value)
{
_storage.AddOrUpdate(value.Id, value);
return Created(value);
}
[HttpPut]
[EnableQuery]
public IActionResult Put([FromODataUri] int key, [FromBody]T value)
{
_storage.AddOrUpdate(key, value);
return Updated(value);
}
[HttpPatch]
[EnableQuery]
public IActionResult Patch([FromODataUri] int key, [FromBody] Delta<T> value)
{
var existing = _storage.GetById(key);
if (existing == null)
{
return NotFound();
}
value.Patch(existing);
_storage.AddOrUpdate(key, existing);
return Updated(existing);
}
[HttpDelete]
[EnableQuery]
public IActionResult Delete([FromODataUri] int key)
{
_storage.Delete(key);
return NoContent();
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(typeof(Storage<>));
services.AddOData();
var mvcBuilder = services.AddMvc();
mvcBuilder.ConfigureApplicationPartManager(c =>
{
c.FeatureProviders.Add(new GenericTypeControllerFeatureProvider());
});
mvcBuilder.AddJsonOptions(opt =>
{
opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
}