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

Service layer pagination, paged results (where to put logic?)

我想在我的 Web 中实现分页 API,但据我所知,大多数分页结果都包含指向自身、下一个、上一个、最后一个、第一个的 URL 或链接。

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

我怎样才能做到这一点?我想要带有分页的简单 CRUD。

控制器是否应该使用 URL 等生成我的 "Paging" 模型?而服务只会 return IQueryable?

Github API,例如 returns 页面 "Link" header:https://api.github.com/search/code?q=addClass+user:mozilla&per_page=2

url 代应该包括在内,你越接近 Mvc/WebApi 东西(在控制器、过滤器或任何你想要的机制中),你不应该把你的 url 代在服务层内部,除非您有定义 url 代的业务规则。

尝试从服务层生成 urls 将强制包含 HttpContext 和 Mvc 引用,最好避免。

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

将其视为尝试为 table 或视图重用相同的服务,那么您不需要 url 代的东西。您应该 return 数据、偏移量、限制、排序依据和总计数(如果 required),因为它需要查询该数据,而不是 url 信息。

我通常在服务或应用层中使用类似这样的东西 entity framework 和 crud 操作,它封装分页简化计数和跳过,采取行动

/// <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();
    }
}