2013-09-05 3 views
1

Каков правильный способ обслуживания запросов GET, запрашиваемых с помощью OET, в ASP.NET Web Api? Это может звучать как вопрос «что лучше», но это должен быть вопрос «что работает».ASP.NET Web Api: правильный способ обслуживания запросов GET, запрашиваемых OData

Некоторые предположения:

  • Чтобы включить OData-обработку запросов, вы должны поставить атрибут Queryable в метод действия, который возвращает IQueryable<Model>. Следовательно, вы должны разоблачить модель домена?
  • В доменной модели используется Entity Framework 5 и имеет свойства навигации. Сериализаторы XML и Json не любят прокси-серверы EF, поэтому вам нужно отключить их для запросов OData?
  • Сериализаторы выбирают свойства навигации и служат им для пользователя.

Так что, если у меня есть Category типа, который имеет навигационные свойства для родителей и детей, сериализаторы жалуются, что у меня есть циклические ссылки, и я не могу избавиться от этой ошибки.

Я прочитал, что должен использовать DTO, но КАК? Как я могу предоставить IQueryable<DTOModel> пользователю, который создаст соответствующий SQL для базы данных? Помните, я хочу использовать $filter и тому подобное.

Я просто хочу предоставить пользователю фильтруемый список объектов модели без сериализованных свойств навигации .... но КАК?

ответ

3

Вам не нужно выставлять IQueryable<> - вы можете создать метод, принимающий экземпляр ODataQueryOptions, и обработать его самостоятельно. Вот пример кода, который делает большую часть того, что вам нужно. Этого должно быть более чем достаточно для того, чтобы вы разработали решение, которое наилучшим образом подходит для вас. Этот метод также позволит вам сохранить классы прокси-сервера EF.

using System.Web.Http.OData; 
using System.Web.Http.OData.Builder; 
using System.Web.Http.OData.Query; 
[ActionName("Dto")] 
public IList<DtoModel> GetDto(ODataQueryOptions<DtoModel> queryOptions) 
{ 
    var data2 = DatabaseData(); 

    //Create a set of ODataQueryOptions for the internal class 
    ODataModelBuilder modelBuilder = new ODataConventionModelBuilder(); 
    modelBuilder.EntitySet<Model>("Model"); 
    var queryContext = new ODataQueryContext(
     modelBuilder.GetEdmModel(), typeof(Model)); 
    var newQueryOptions = new ODataQueryOptions<Model>(queryContext, Request); 

    var t = new ODataValidationSettings() { MaxTop = 25 }; 
    var s = new ODataQuerySettings() { PageSize = 25 }; 
    newQueryOptions.Validate(t); 
    IEnumerable<Model> results = 
     (IEnumerable<Model>)newQueryOptions.ApplyTo(data2, s); 

    int skip = newQueryOptions.Skip == null ? 0 : newQueryOptions.Skip.Value; 
    int take = newQueryOptions.Top == null ? 25 : newQueryOptions.Top.Value; 

    IList<Model> internalResults = results.Skip(skip).Take(take).ToList(); 

    // map from Model to Dto here using AutoMapper 
    AutoMapper.Mapper.CreateMap<Model, DtoModel>(); 
    IList<DtoModel> webResults = 
     AutoMapper.Mapper.Map<IList<Model>, IList<DtoModel>>(internalResults); 

    return webResults; 
} 

Данные, используемые в примере простой Queryable набор данных:

private IQueryable<Model> DatabaseData() 
{ 
    return (
     new Model[] { 
     new Model() { id = 1, name = "one", type = "a" }, 
     new Model() { id = 2, name = "two", type = "b" }, 
     new Model() { id = 3, name = "three", type = "c" }, 
     new Model() { id = 4, name = "four", type = "d" }, 
     new Model() { id = 5, name = "five", type = "e" }, 
     new Model() { id = 6, name = "six", type = "f" }, 
     new Model() { id = 7, name = "seven", type = "g" }, 
     new Model() { id = 8, name = "eight", type = "h" }, 
     new Model() { id = 9, name = "nine", type = "i" } 
    }) 
    .AsQueryable(); 
} 

Эти тестовые классы:

public class Poco 
{ 
    public int id { get; set; } 
    public string name { get; set; } 
    public string type { get; set; } 
} 
public class DtoModel 
{ 
    public int id { get; set; } 
    public string name { get; set; } 
    public string type { get; set; } 
} 
public class Model 
{ 
    public int id { get; set; } 
    public string name { get; set; } 
    public string type { get; set; } 
    public virtual ICollection<Poco> Pocos { get; set; } 
} 
+1

Как я могу сделать эту работу с расширения? –

Смежные вопросы