2015-01-18 3 views
0

페이징, 주문 및 사전 선택 결과 (데이터베이스 단위 : dto에 포함 된 열)와 같은 일부 쿼리 가능 끝점을 제공하려는 웹 API가 있습니다. 지금까지는 많은 일들이 진행되고 있지만 기술적 인 부분이 많은 컨트롤러 메소드가 많이 있습니다. 요구 사항을 쉽게 해결할 수 있을지 궁금합니다. 종종 같은 모양 많은 엔티티쿼리 가능한 웹 API

public HttpResponseMessage GetEntities(int page = MaximumPageIndex, 
    int pageSize = MinimumPageSize, 
    string orderBy = null, 
    [FromUri] EntitySearchCriteria criteria = null) 
{ 

    // ensure that page/pageSize lies within possible boundaries 
    page = page.ToMinimum(MinimumPageIndex); 
    pageSize = pageSize.ToBounds(MinimumPageSize, MaximumPageSize); 

    // create any criteria for entity if none is available 
    criteria = criteria ?? new AnyEntitySearchCriteria(); 

    // create ordering expressions based on string 
    var orderOptions = orderBy != null 
     ? ExpressionBuilder.CreateSelector<Entity, dynamic>(orderBy) 
     : ExpressionBuilder.CreateSelector<Entity, dynamic>("Id"); 

    // create paging options 
    var pagingOptions = new PagingOptions<Entity, dynamic>(page, pageSize, orderOptions); 

    try { 

     // get total count from database 
     var totalCount = _repository.Count(); 

     // get entities by criteria specification (IMemberSpecification<T, TMember>) 
     var results = _repository.GetEntitiesByCriteria(criteria, 
      x = new BlablaDto {} // apply result selectors (not shown in example, 
      // map to paged list 
      pagingOptions).ToPagedList(page, pageSize, totalCount); 

     // create "paged" response with paging http headers (rfc 5988) 
     return Request.CreatePagedResponse(HttpStatusCode.OK, results); 
     ... 
} 

이, 물론, 또 다시, :

일반적인 컨트롤러처럼 보인다. 이제는 Microsoft OData가 있다는 것을 알고 있습니다. 그러나 IQueryable, 이상한 응답에서만 작동합니다 (예 : 페이징 데이터가 HTTP 헤더가 아닌 json 결과에 포함됨). 그렇다면 컨트롤러를 간단하게 유지하고이 작업을 위해 코드 반복을 줄일 수있는 방법은 무엇입니까?

+0

답변은 _repository가 어떻게 설계되고 구현되는지에 달려 있습니다 ... 코드에서 볼 수 없습니다. –

+0

@Werlang 기본 CRUD와 ISpecification을 취하는 GetEntities() 메서드, 쿼리 공급자가 반환 한 기본 IQueryable에 적용되는 정렬/페이징 용 IQueryOptions 및 필드 및/또는 필드의 하위 집합을 반환하는 selector 식입니다. 또는 DTO 매핑. – xvdiff

+0

이 Repository.GetEntities()는 기본 컨트롤러의 템플릿 메서드로 이동할 수 있습니다. Controller.GetEntities()에서이 모든 로직을 구현하고 각 특정 엔터티 유형에 대해이 특정 페치를 처리하도록 할 수 있습니다. –

답변

0

컨트롤러에는 많은 로직이 있으며,이 로직을 API Facade/Engine 레이어와 같은 다른 레이어로 이동하는 것을 고려해야합니다. 입력을 정리하기 위해 일부 상속 기능이 내장 된 검색 필터를 설정할 수 있지만 최근의 많은 프로젝트에서이를 수행해야했습니다.

using System.Collections.Generic; 
using System.Runtime.Serialization; 

public interface IPaginatedFilter { 

    int DefaultLimit { get; } 
    int MaximumLimit { get; } 
    List<string> SupportedOrderBy { get; } 
    bool IsAscendingByDefault { get; } 
} 

[DataContract] 
public sealed class PaginationInput 
{ 
    [DataMember(Name = "limit", Order = 2)] 
    public int Limit { get; set; } 

    [DataMember(Name = "offset", Order = 3)] 
    public int Offset { get; set; } 

    [DataMember(Name = "orderBy", Order = 4)] 
    public string OrderBy { get; set; } 

    [DataMember(Name = "orderByDirection", Order = 5)] 
    public string OrderByDirection { get; set; } 

} 

/// <summary> 
///  Base search filter 
/// </summary> 
public class SearchBase { 
    /// <summary> 
    ///  Results page information 
    /// </summary> 
    [DataMember(Name = "page", Order = 1)] 
    public PaginationInput Page { get; set; } 

    /// <summary> 
    ///  Search phrase applicable to any member of the inheriting search filter 
    /// </summary> 
    [DataMember(Name = "any", Order = 1)] 
    public string Any { get; set; } 

} 

public class EntitySearchCriteria : SearchBase, IPaginatedFilter { 

    // columns to provide search functions for 


    #region Implementation of IPaginatedFilter 

    public int DefaultLimit { 
     get { return 20; } 
    } 

    public int MaximumLimit { 
     get { return 50; } 
    } 

    public List<string> SupportedOrderBy { 
     get { return new List<string> 
     { 
      // columns that support ordering 
     }; } 
    } 

    public bool IsAscendingByDefault { 
     get { return true; } 
    } 

    #endregion 

} 

이렇게하면 모든 검색 필터에 대해 동일한 API를 사용할 수 있습니다. 귀하의 컨트롤러가 정말 같아야합니다

필터 입력의 유효성을 검사해야하는 경우 요청을 처리하기 전에 유효성 검사 레이어에 입력을 보내야합니다. 특별히 응용 프로그램의 경계에서 우려를 분리하면 장기적으로는 대단한 성과를 거둘 수 있습니다.

+0

나 같은 경우 URL에서 호출하는 동안 limit 또는 offset과 같은 매개 변수를 사용하는 방법을 모르면 http : // myurl/api/Entities? page [limit] = 30 & page [offset] = 10 – Lithium