У меня есть один универсальный контроллер (похожий на этот: .Net Core Override Controller Route для универсального контроллера ), который регистрирует универсальные реализации для всех динамических типов, которые у меня есть.
Это работает очень хорошо. Но при попытке реализовать поддержку навигационной маршрутизации с дополнительными значениями фильтра у меня возникают некоторые проблемы. Этот пример:
http://localhost/odata/EntityA(4711)/SubEntity?$filter=category экв 'ABC'
работает теоретически, но мне нужно извлечь ODataQueryOptions.
Итак, вот что у меня есть:
ExternalControllerFeatureProvider
public class ExternalControllerFeatureProvider : IApplicationFeatureProvider<ControllerFeature>
{
public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
{
foreach (var candidate in _entityCompiler.GetTypes())
{
feature.Controllers.Add(
typeof(GenericController<>).MakeGenericType(candidate).GetTypeInfo()
);
}
}
}
GenericController
[Produces("application/json")]
[GenericControllerNameConvention]
[EnableQuery]
public class GenericController<T> : ODataController
{
public async Task<IQueryable<T>> Get([FromServices] ODataQueryOptions odataQueryOptions)
{
var parameters = ExtractQueryParameter(odataQueryOptions);
return await InternalGet(parameters);
}
public async Task<IQueryable<T>> Get([FromServices] ODataQueryOptions odataQueryOptions, [FromODataUri] object key)
{
var parameters = ExtractQueryParameter(odataQueryOptions);
AppendKeyAttributeFilter(parameters, key);
return await InternalGet(parameters);
}
public async Task<IActionResult> GetNavigation(Guid key, string propertyName)
{
var parameters = new Dictionary<string, object>();
AppendKeyAttributeFilter(parameters, key);
AppendExpandFilter(parameters, propertyName);
var rootObject = await InternalGet(parameters);
if (rootObject.Any())
{
var info = typeof(T).GetProperty(propertyName);
object value = info.GetValue(rootObject.FirstOrDefault());
return Ok(value);
}
return NotFound();
}
Аналогично этому (http://odata.github.io/WebApi/03-04-custom-routing-convention/) Я создал NavigationRoutingConvention , который извлекает свойство навигации и вызывает GetNavigation -метод из GenericController с правильным propertyName .
Проблема в том, что этот метод GenericController не может возвращать IQueryable или IEnumerable , но только некоторые нетипизированные типы, такие как IActionResult .
Чтобы вручную отфильтровать источник данных в бэкэнде, мне нужны ODataQueryOptions , как в обоих методах Get. Проблема в том, что, похоже, базовая структура должна знать правильный возвращаемый тип.
Если я добавлю [FromServices] ODataQueryOptions к заголовку метода, я получу следующее исключение:
System.InvalidOperationException: невозможно создать модель EDM как
действие «GetNavigation» на контроллере «EntityA» имеет тип возврата
«System.Threading.Tasks.Task`1 [[Microsoft.AspNetCore.Mvc.IActionResult,
Microsoft.AspNetCore.Mvc.Abstractions, версия = 2.1.1.0,
Культура = нейтральная, PublicKeyToken = adb9793829ddae60]] ', которая не
реализовать IEnumerable. в
Microsoft.AspNet.OData.ODataQueryParameterBindingAttribute.ODataQueryParameterBinding.GetEntityClrTypeFromActionReturnType (ActionDescriptor
actionDescriptor) в
Microsoft.AspNet.OData.ODataQueryParameterBindingAttribute.ODataQueryParameterBinding.BindModelAsync (ModelBindingContext
bindingContext) в
Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BinderTypeModelBinder.BindModelAsync (ModelBindingContext
bindingContext) в
Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync (ActionContext
actionContext, IModelBinder modelBinder, IValueProvider valueProvider,
Параметр ParameterDescriptor, метаданные ModelMetadata, значение объекта)
в
. Microsoft.AspNetCore.Mvc.Internal.ControllerBinderDelegateProvider <> c__DisplayClass0_0 . D.MoveNext ()