Skip to content

Instantly share code, notes, and snippets.

@nth-commit
Created February 4, 2017 22:46
Show Gist options
  • Save nth-commit/94e390b089ca662df972acd06d1d4fce to your computer and use it in GitHub Desktop.
Save nth-commit/94e390b089ca662df972acd06d1d4fce to your computer and use it in GitHub Desktop.
public class OkPagedResult : OkObjectResult
{
public int TotalItems { get; private set; }
public OkPagedResult(IEnumerable items, int totalItems) : base(items)
{
TotalItems = totalItems;
}
}
public abstract class PagedController : Controller
{
public OkPagedResult Ok(IEnumerable items, int totalItems)
{
return new OkPagedResult(items, totalItems);
}
}
public class PagingAttribute : Attribute, IActionFilter
{
private const string DefaultPageNumberKey = "page";
private const string DefaultPageSizeKey = "page-size";
public void OnActionExecuting(ActionExecutingContext context)
{
}
public void OnActionExecuted(ActionExecutedContext context)
{
var okPagedResult = context.Result as OkPagedResult;
if (okPagedResult != null)
{
AddTotalCountHeader(context, okPagedResult);
AddLinkHeader(context, okPagedResult);
}
}
private void AddTotalCountHeader(ActionExecutedContext context, OkPagedResult result)
{
var totalItems = result.TotalItems;
context.HttpContext.Response.Headers.Add("X-Total-Count", new StringValues(totalItems.ToString()));
}
private void AddLinkHeader(ActionExecutedContext context, OkPagedResult result)
{
var pageNumber = _pageRequest.Number;
var totalPages = (int)Math.Ceiling(result.TotalItems / (double)_pageRequest.Size);
var links = new List<LinkHeaderElement>()
{
new LinkHeaderElement()
{
Rel = "first",
Url = GetPageUrl(context, 1)
},
new LinkHeaderElement()
{
Rel = "last",
Url = GetPageUrl(context, totalPages)
}
};
if (totalPages > 1)
{
if (pageNumber < totalPages)
{
links.Add(new LinkHeaderElement()
{
Rel = "next",
Url = GetPageUrl(context, pageNumber + 1)
});
}
if (pageNumber > 1)
{
links.Add(new LinkHeaderElement()
{
Rel = "prev",
Url = GetPageUrl(context, pageNumber - 1)
});
}
}
var linksHeaderValues = links.Select(l => $"<{l.Url}>; rel=\"{l.Rel}\"");
context.HttpContext.Response.Headers.Add("Link", string.Join($", ", linksHeaderValues));
}
private string GetPageUrl(ActionExecutedContext context, int pageNumber)
{
var request = context.HttpContext.Request;
var requestQueryDictionary = QueryHelpers.ParseQuery(request.QueryString.Value);
requestQueryDictionary[DefaultPageNumberKey] = new StringValues(pageNumber.ToString());
requestQueryDictionary[DefaultPageSizeKey] = new StringValues(_pageRequest.Size.ToString());
return QueryHelpers.AddQueryString(
new Uri($"{request.Scheme}://{request.Host}{request.Path}").ToString(),
requestQueryDictionary
.Where(kvp => kvp.Value.Count() > 0)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.FirstOrDefault()));
}
private class LinkHeaderElement
{
public string Rel { get; set; }
public string Url { get; set; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment