Веб-API Queryable – как применять AutoMapper?

У меня есть простой метод WebApi, подобный этому, с атрибутом запроса OData.

[Queryable] public virtual IQueryable Get() { return uow.Person().GetAll()); // Currently returns Person instead of PersonD } 

То, что я хочу сделать, – это преобразовать результат запроса из типа Person для ввода PersonDto с использованием AutoMapper до того, как WebAPI преобразует результат в JSON.

Кто-нибудь знает, как я могу это сделать? Я знаю, что я могу применить Mapper.Map после вызова GetAll (), а затем преобразовать обратно в IQueryable, однако это приведет к тому, что вся таблица будет возвращена и отображена до того, как будет применен фильтр OData (не хорошо!).

Похоже, что этот вопрос ASP.NET Web API возвращает запрашиваемые DTO? охватывает ту же проблему (см. второй ответ для лучшего ответа), где предлагается использовать AutoMapper в конце цепочки с использованием настраиваемого MediaTypeFormatter, однако я не знаю, как это сделать на примере, который я видел.

Любая помощь будет с благодарностью получена!

– Дополнительная информация

Я посмотрел исходный код для IQueryable, но, к сожалению, я не вижу способа использовать этот код для этой цели. Мне удалось написать дополнительный фильтр, который, похоже, работает, однако он, конечно, не является изящным.

 public class PersonToPersonDtoConvertAttribute : ActionFilterAttribute { public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext) { HttpResponseMessage response = actionExecutedContext.Response; if (response != null) { ObjectContent responseContent = response.Content as ObjectContent; var query = (responseContent.Value as IQueryable).ToList(); response.Content = new ObjectContent<IEnumerable>(query.ToList().Select(Mapper.Map), responseContent.Formatter); } } } 

Затем я украсил действие, как

  [Queryable] [PersonToPersonDtoConvert] public IQueryable Get() { return uow.GetRepo<IRepository>().GetAll(); } 

Существует лучшее решение. Попробуй это:

 public virtual IQueryable Get(ODataQueryOptions query) { var people = query.ApplyTo(uow.Person().GetAll()); return ConvertToDtos(people); } 

Это позволит убедиться, что запрос выполняется на Person вместо PersonDTO. Если вы хотите, чтобы преобразование происходило через атрибут, а не в коде, вы все равно захотите реализовать фильтр действий, подобный тому, что вы положили.

Используйте Queryable Extensions для AutoMapper.

Сначала определим отображение.

 Mapper.CreateMap(); 

Затем вы можете использовать что-то вроде этого:

 [EnableQuery] public IQueryable Get() { return this.dbContext.Persons.Project().To(); } 

ИМХО принятое решение неверно. Вообще говоря, если ваша служба использует DTO, вы не хотите раскрывать базовые объекты (Person) для этой службы. Почему вы запрашиваете модель Person и возвращаете объекты PersonDTO ?

Поскольку вы уже используете его, Automapper имеет Queryable Extensions, который позволяет выставлять только ваши DTO и применять фильтрацию к базовому типу в источнике данных. Например:

 public IQueryable Get(ODataQueryOptions options) { Mapper.CreateMap(); var persons = _personRepository.GetPersonsAsQueryable(); var personsDTOs = persons.Project().To(); // magic happens here... return options.ApplyTo(personsDTOs); } 

Что касается активной загрузки навигационных свойств …

@philreed: Я не смог добавить достойный ответ в комментарии, поэтому добавил его здесь. Было сообщение о том, как это сделать здесь, но сегодня я получаю 403s. Надеюсь, это временно.

В основном вы изучаете предложения Select и Expand для вашего свойства навигации. Если он присутствует, вы IQueryable Include EF с нетерпением загрузки через метод расширения IQueryable Include .

controller

 public IQueryable GetMyDtos(ODataQueryOptions options) { var eagerlyLoad = options.IsNavigationPropertyExpected(t => t.MyNavProperty); var queryable = _myDtoService.GetMyDtos(eagerlyLoad); // _myDtoService will eagerly load to prevent select N+1 problems // return (eagerlyLoad) ? efResults.Include(t => t.MyNavProperty) : efResults; return queryable; } 

Метод расширения

 public static class ODataQueryOptionsExtensions { public static bool IsNavigationPropertyExpected(this ODataQueryOptions source, Expression> keySelector) { if (source == null) { throw new ArgumentNullException("source"); } if (keySelector == null) { throw new ArgumentNullException("keySelector"); } var returnValue = false; var propertyName = (keySelector.Body as MemberExpression ?? ((UnaryExpression)keySelector.Body).Operand as MemberExpression).Member.Name; var expandProperties = source.SelectExpand == null || string.IsNullOrWhiteSpace(source.SelectExpand.RawExpand) ? new List().ToArray() : source.SelectExpand.RawExpand.Split(','); var selectProperties = source.SelectExpand == null || string.IsNullOrWhiteSpace(source.SelectExpand.RawSelect) ? new List().ToArray() : source.SelectExpand.RawSelect.Split(','); returnValue = returnValue ^ expandProperties.Contains(propertyName); returnValue = returnValue ^ selectProperties.Contains(propertyName); return returnValue; } } 

У меня есть несколько замечаний / комментариев по предлагаемому решению. 1. Если Person используется в контексте запроса и возвращается PersonDTO, вся концепция MVVM исчезает. Наверное, он крепко связан. Я бы предпочел просто использовать Person полностью или если вы не хотите возвращать дочерние записи, то, по моему мнению, Automapper имеет расширение «Project», попробуйте его использовать. 2. При таком подходе опция запроса $ inlinepagecount не будет функционировать должным образом, потому что она получит счет PersonDTO вместо Person. (Ну, одним из способов обойти эту проблему было бы использование PageResult и настройка свойств самостоятельно.) С уважением.

  • Неавторизованный webapi вызов, возвращающий страницу входа, а не 401
  • Загрузка Webapi formdata (в DB) с дополнительными параметрами
  • WebAPI для возврата XML
  • Каков рекомендуемый нами способ частичного обновления веб-API?
  • Обнаружен цикл саморегуляции - Возврат данных из WebApi в браузер
  • Не удалось выполнить сериализацию ответа в Web API с помощью Json
  • Передача параметров сервера asp.net в приложение Angular 2
  • Удалить пространство имен в XML из веб-интерфейса ASP.NET
  • Как написать Json-файл в C #?
  • JSON.NET как сериализатор OAP для WebAPI 2 и ODataMediaTypeFormatter
  • Async WebApi Thread.CurrentCulture
  • Interesting Posts

    Не удалось добавить окно [email protected] – разрешено разрешение для этого типа windows

    Таинственный новый ESP-накопитель в Windows 10

    Как я могу использовать Android KeyStore для безопасного хранения произвольных строк?

    Сохранить видео Youtube для iPhone в приложении

    Вызовите по имени vs call по значению в Scala, необходимо разъяснение

    Почему fork () дважды

    Bootstrap 4 Center Вертикальное и горизонтальное выравнивание

    Есть ли способ вызвать скрипт, когда Ubuntu просыпается из режима ожидания или спящего режима?

    Звук иногда не работает для некоторых программ в Windows 7, даже из диалога Mixer

    Смешать ОЗУ с различными тактовыми частотами

    Как установить текст для просмотра из макета заголовка ящика в навигационном ящике без раздувания

    Привязать к переменной массива bash косвенно, динамически сконструированным именем переменной

    Почему этот фильтр CSS: not () не фильтруется?

    Как пройти через это двойственное застопорившееся соединение?

    Функция tellg () дает неправильный размер файла?

    Давайте будем гением компьютера.