【问题标题】:Queryable web api可查询的 web api
【发布时间】:2015-01-18 20:54:08
【问题描述】:

我有一个 Web API,我想为分页、排序和预选结果等内容提供一些(有限的)可查询端点(数据库方面:dto 中包含的列)。到目前为止一切都很好,但是我有很多臃肿的控制器方法和很多技术内容,我想知道是否有更简单的方法来满足我的要求。

典型的控制器如下所示:

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,奇怪的响应 - 例如:分页数据包含在 json 结果中,而不是 HTTP 标头中)..那么,我怎样才能让我的控制器保持简单并减少这个任务的代码重复呢?

【问题讨论】:

  • 答案在于_repository是如何设计和实现的……我从代码中看不出来。
  • @Werlang Basic CRUD 加上一个方法 'GetEntities()',它接受一个 ISpecification、一个 IQueryOptions(用于排序/分页,应用于查询提供程序返回的底层 IQueryable)和一个选择器表达式返回字段和/或 DTO 映射的子集。
  • 这个 Repository.GetEntities() 可以移动到基本控制器中的模板方法......然后让你的 Controller.GetEntities() 实现所有这些逻辑并处理这个特定的获取,对于每个实体类型。

标签: c# json rest asp.net-web-api iqueryable


【解决方案1】:

您的控制器有很多逻辑,您应该考虑将这些逻辑移到另一个层,例如 API 外观/引擎层。为了清理输入,您可以使用内置的一些继承设置搜索过滤器。我在最近的许多项目中都必须这样做。

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。你的控制器应该看起来像

public HttpResponseMessage GetEntities(
        [FromUri] EntitySearchCriteria filter = null)
{

    // process input using your service layer

    // generate response

}

如果您需要先验证过滤器输入,则在尝试处理请求之前将输入发送到验证层。 从长远来看,特别是在应用程序边界的关注点分离将获得巨大回报

【讨论】:

猜你喜欢
  • 2012-04-11
  • 2018-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-26
  • 2018-08-08
  • 1970-01-01
  • 2012-08-05
相关资源
最近更新 更多