服务层分页,分页结果(在哪里放逻辑?)

时间:2018-04-18 09:29:15

标签: c# asp.net-core entity-framework-core asp.net-core-webapi n-tier-architecture

我想在我的Web API中实现分页,但从我看到的大多数分页结果包含URL或指向self,next,previous,last,first的链接。

我不确定在哪里放置分页逻辑,因为服务层无法生成URL。而且我不想将我的服务层与ASP NET Core结合起来。

我怎样才能做到这一点?我希望简单的CRUD与分页。

控制器是否应该使用URL等生成“寻呼”模型?服务只返回IQueryable

例如,

Github API会在“链接”标题中返回页面:https://api.github.com/search/code?q=addClass+user:mozilla&per_page=2

1 个答案:

答案 0 :(得分:3)

应该尽可能地包含url生成到Mvc / WebApi内容(内部控制器,过滤器或任何你想要的机制),你不应该将你的url生成放在服务层内,除非你有定义的业务规则网址生成。

尝试从服务层生成网址将强制包含HttpContext和Mvc引用,这比躲避更好。

服务应该了解业务数据,而不是ui层组件。

将其视为尝试为表或视图重用相同的服务,然后您不需要该url生成的东西。您应该返回数据,偏移量,限制,订单和总数(如果需要),因为它需要查询该数据,而不是网址信息。

我通常在服务或应用层内部使用实体框架和crud操作这样的东西,它封装了分页简化Count和Skip,采取行动

/// <summary>
/// Paged queryable
/// </summary>
/// <typeparam name="T">T</typeparam>
public sealed class PagedQueryable<T> : IPagedEnumerable<T> ,IEnumerable<T>
{
    IQueryable<T> _source = null;
    int? _totalCount = null;

    /// <summary>
    /// Ctor
    /// </summary>
    /// <param name="source">source</param>
    /// <param name="offset">start element</param>
    /// <param name="limit">max number of items to retrieve</param>
    public PagedQueryable(IQueryable<T> source, int offset, int? limit)
    {
        if (source == null)
            throw new ArgumentNullException(nameof(source));

        _source = source;
        Limit = limit;
        Offset = Math.Max(offset, 0);
    }

    public int TotalCount
    {
        get
        {
            if (!_totalCount.HasValue && _source != null)
                _totalCount = _source.Count();

            return _totalCount.GetValueOrDefault();
        }
    }

    public int? Limit { get; }
    public int Offset { get; }

    public IEnumerator<T> GetEnumerator()
    {
        if (_source is IOrderedQueryable<T>)
        {
            var query = _source.Skip(Offset);
            if (Limit.GetValueOrDefault() > 0)
                query = query.Take(Limit.GetValueOrDefault());

            return query.ToList().GetEnumerator();
        }
        else
            return Enumerable.Empty<T>().GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}