WCF Data Services Pagination - c#

I implement in my WCF Services tha pagination throught Data Service but not work, the code from the activation is:
public class Profit : DataService<ProfitEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// Set page size defaults for the data service.
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.SetEntitySetPageSize("artEntities", 1);
}
}
I use EF 6 + Linq
I retrieve all my Product indeed without a problem but I need the pagination beacuse is a large data.
Thanks you
Code of my Query:
public List<Product> GetAllProduct()
{
ProfitEntities context = new ProfitEntities();
List<Product> product = new List<Product>();
foreach (artEntities art in context.art)
{
product.Add(new Product
{
coArt = art.co_art.Trim(),
desArt = art.art_des.Trim(),
stockAct = Convert.ToDecimal(art.stock_act),
precVta1 = Convert.ToDecimal(art.prec_vta1),
anulado = art.anulado
});
}
if (product.Count > 0)
{
return product;
}
else
throw new Exception("Imposible conseguir lista de Articulos");
}
Thanks you for your help.

I found other way to make the pagination to WCF Services...
I used a two class found in other proyect from MVC and change to my purpose...
Interface IPagedList
public interface IPagedList<T> : IList<T>
{
int PageCount { get; }
int TotalItemCount { get; }
int PageIndex { get; }
int PageNumber { get; }
int PageSize { get; }
bool HasPreviousPage { get; }
bool HasNextPage { get; }
bool IsFirstPage { get; }
bool IsLastPage { get; }
}
Paged Class
public class PagedList<T> : List<T>, IPagedList<T>
{
public PagedList(IEnumerable<T> source, int index, int pageSize, int? totalCount = null)
: this(source.AsQueryable(), index, pageSize, totalCount)
{
}
public PagedList(IQueryable<T> source, int index, int pageSize, int? totalCount = null)
{
if (index < 0)
throw new ArgumentOutOfRangeException("index", "Value can not be below 0.");
if (pageSize < 1)
throw new ArgumentOutOfRangeException("pageSize", "Value can not be less than 1.");
if (source == null)
source = new List<T>().AsQueryable();
var realTotalCount = source.Count();
PageSize = pageSize;
PageIndex = index;
TotalItemCount = totalCount.HasValue ? totalCount.Value : realTotalCount;
PageCount = TotalItemCount > 0 ? (int)Math.Ceiling(TotalItemCount / (double)PageSize) : 0;
HasPreviousPage = (PageIndex > 0);
HasNextPage = (PageIndex < (PageCount - 1));
IsFirstPage = (PageIndex <= 0);
IsLastPage = (PageIndex >= (PageCount - 1));
if (TotalItemCount <= 0)
return;
var realTotalPages = (int)Math.Ceiling(realTotalCount / (double)PageSize);
if (realTotalCount < TotalItemCount && realTotalPages <= PageIndex)
AddRange(source.Skip((realTotalPages - 1) * PageSize).Take(PageSize));
else
AddRange(source.Skip(PageIndex * PageSize).Take(PageSize));
}
#region IPagedList Members
public int PageCount { get; private set; }
public int TotalItemCount { get; private set; }
public int PageIndex { get; private set; }
public int PageNumber { get { return PageIndex + 1; } }
public int PageSize { get; private set; }
public bool HasPreviousPage { get; private set; }
public bool HasNextPage { get; private set; }
public bool IsFirstPage { get; private set; }
public bool IsLastPage { get; private set; }
#endregion
}
My Operation Contract (Class)
private int defaultPageSize = 10;
ProfitEntities context = new ProfitEntities();
public List<Product> GetAllProduct(string value)
{
var artprofit = context.art.Include("colores").Include("lin_art").Include("sub_lin").Include("cat_art").ToList();
int? page = Convert.ToInt32(value);
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
var productListPaged = artprofit.ToPagedList(currentPageIndex, defaultPageSize);
}

Related

How to use AutoMapper with PagedLists?

I had automapper working but then added in the PagedList and now it does not work. How
do I tell it just to map the RfReport to RfReportModel but keep the PagedList parameters?
AutoMapper.AutoMapperMappingException: 'Error mapping types.'
ArgumentException: PWDRS.Core.Helpers.PagedList`1[PWDRS.Application.Models.RfReportModel] needs to have a constructor with 0 args or only optional args.
public PagedList<RfReportModel> GetRfReportListPaged(RfReportParameters rfReportParameters)
{
PagedList<RfReport> rfReports = _rfReportRepository.GetRfReportListPaged(rfReportParameters);
PagedList<RfReportModel> mapped = _mapper.Map<PagedList<RfReportModel>>(rfReports);
return mapped;
}
public class PagedList<T> : List<T>
{
public int CurrentPage { get; private set; }
public int TotalPages { get; private set; }
public int PageSize { get; private set; }
public int TotalCount { get; private set; }
public bool HasPrevious => CurrentPage > 1;
public bool HasNext => CurrentPage < TotalPages;
public PagedList(List<T> items, int count, int pageNumber, int pageSize)
{
TotalCount = count;
PageSize = pageSize;
CurrentPage = pageNumber;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
AddRange(items);
}
public static PagedList<T> ToPagedList(IEnumerable<T> source, int pageNumber, int pageSize)
{
var count = source.Count();
var items = source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
return new PagedList<T>(items, count, pageNumber, pageSize);
}
}
EDIT 1: I could not figure out how to do it in automapper but I realized I could recreate the PagedList easily like this to effectively do the same thing.
public PagedList<RfReportModel> GetRfReportListPaged(RfReportParameters rfReportParameters)
{
PagedList<RfReport> rfReports = _rfReportRepository.GetRfReportListPaged(rfReportParameters);
IEnumerable<RfReportModel> mapped = _mapper.Map<IEnumerable<RfReportModel>>(rfReports);
PagedList<RfReportModel> plMapped = PagedList<RfReportModel>.ToPagedList(
mapped,
rfReportParameters.PageNumber,
rfReportParameters.PageSize);
return plMapped;
}

ASP.NET CORE 2.1 - FromQuery doesnt work?

I have class for capturing all parameters :
public class UserParams
{
private const int MaxPageSize = 50;
public int PageNumber { get; set; } = 1;
private int pageSize = 10;
public int PageSize
{
get { return pageSize;}
set { pageSize = (value > MaxPageSize) ? MaxPageSize : value;}
}
public int UserId { get; set; }
public string OrderBy { get; set; }
public bool isAll {get; set;} = true;
public bool isManagers { get; set; } = false;
public bool isPartners { get; set; } = false;
}
and my controllers:
[HttpGet]
public async Task<IActionResult> GetUsers([FromQuery] UserParams userParams)
{
var users = await _appRepo.GetUsers(userParams);
var usersDto = _mapper.Map<IEnumerable<UserSimpleDto>>(users);
Response.AddPagination(users.CurrentPage, users.PageSize, users.TotalCount, users.TotalPages);
return Ok(usersDto);
}
While my appRepo.GetUsers:
public async Task<PagedList<User>> GetUsers(UserParams userParams)
{
var users = _context.Users.OrderByDescending(p => p.FirstName).AsQueryable();
if(userParams.isManagers)
{
users = users.Where( u => u.IsManager == true);
}
if(userParams.isPartners)
{
users = users.Where( u => u.IsPartner == true);
}
return await PagedList<User>.CreateAsync(users, userParams.PageNumber, userParams.PageSize);
}
I tried to debug the code with Postman :
http://localhost:5000/api/user?isManagers=1
or
http://localhost:5000/api/user?isManagers=true
but it seems the params isManagers still false (the result is still get all users)
How to fix this bug?

Map generic type that receives constructor parameters with Automapper

My questions is related to a specific scenario that I don't know how to handle it.
I have a mapper registered between Application and ApplicationModel and vice verse.
Now I am calling a method that returns an IPagedList
GetApplications Method:
IPagedList<Application> GetApplications()
{
IQueryable items = context.Applications...
return new PagedList<Application>(items, 1, 10);
}
And this is where I get my error because PagedList doesn't have a default constructor when it tries to make the mapping.
IPagedList<Application> applications = GetApplications();
var toRet = Mapper.Map<IPagedList<ApplicationModel>>(applications); //here I get the error
I tried to figure out how this is done with ConstructUsing but honestly I need help to structure the call correctly if that is the correct path
Bellow are the interface and the implementation of IPagedList
Interface:
public interface IPagedList<T> : IList<T>
{
int CurrentPage { get; }
int TotalPages { get; }
int PageSize { get; }
int TotalCount { get; }
bool HasPrevious { get; }
bool HasNext { get; }
IEnumerable<T> Items { get; }
}
Implementation:
public class PagedList<T> : List<T>, IPagedList<T>
{
public PagedList(IEnumerable<T> items, int count, int pageNumber, int pageSize)
{
Items = items;
TotalCount = count;
PageSize = pageSize;
CurrentPage = pageNumber;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
AddRange(Items);
}
public PagedList(IQueryable<T> source, int pageNumber, int pageSize) : this(source.AsEnumerable(), source.Count(), pageNumber, pageSize)
{
}
public int CurrentPage { get; }
public int TotalPages { get; }
public int PageSize { get; }
public int TotalCount { get; }
public bool HasPrevious => CurrentPage > 1;
public bool HasNext => CurrentPage < TotalPages;
public IEnumerable<T> Items { get; }
}
Use ProjectTo<ApplicationModel>() or map the IQueryable<Applications> to List<ApplicationModels>, then throw it into PagedList's constructor and won't deal with the default constructor issue in AutoMapper.
ProjectTo Example:
var toRet = new PagedList<ApplicationModel>(context.Applications...ProjectTo<ApplicationModel>(), 1, 10);

Property/method definition

public class PaginationHelper<T> : IPagination<T>
{
public int PageNumber { get; set; }
public int PageSize { get; set; }
public IList<T> Items { get; set; }
public IList<T> PaginationItems => AsPagination();
public int TotalItems { get; set; }
public int FirstItem => (PageNumber - 1) * PageSize + 1;
public int LastItem => FirstItem + PageSize - 1;
public int TotalPages
{
get
{
var result = (int)Math.Ceiling((double)TotalItems / PageSize);
return result == 0 ? 1 : result;
}
}
public bool HasPreviousPage => PageNumber > 1;
public bool HasNextPage => PageNumber < TotalPages;
public List<T> AsPagination()
{
var numberToSkip = (PageNumber - 1) * PageSize;
var results = Items.Skip(numberToSkip).Take(PageSize).ToList();
return results;
}
}
public class Paginator<T>
{
public List<T> PaginationItems { get; set; }
public int TotalPages { get; set; }
}
My friend gave me this code, and I can't compile. When define a property/method in C#, is it possible to use in this way?
public int FirstItem => (PageNumber - 1) * PageSize + 1; Is it right syntax??
That syntax; formally known as an expression-bodied member was introduced in C# 6 and the VS 2015 C# compiler.
Earlier versions of Visual Studio will not compile it; you'll have to refactor to C# 5 compliant code:
public int FirstItem { get { return (PageNumber - 1) * PageSize + 1; } }

Set max count in for statement

I have a model with a nested collection:
public class SomeClass
{
public SomeClass()
{
this.OtherPart = new HashSet<OtherPart>();
}
[Key]
public int SomeClassId { get; set; }
public string SomeData { get; set; }
public string SomeOtherData { get; set; }
public virtual ICollection<OtherPart> OtherParts { get; set; }
public void CreateOthers(int count = 1)
{
for (int i = 0; i < count; i++)
{
OtherParts.Add(new OtherPart());
}
}
}
with this Controller action:
public ActionResult Create()
{
var abc = new SomeClass();
abc.CreateOthers();
return View(abc);
}
and it works perfectly. The problem I now have is that for my use case i need to set a maximum number of items to create ( in this case 5).
I have tried the following modification in the void above, but it is ignored:
public void CreateOthers(int count = 1, int max = 5)
{
for (int i = 0; i < count && count < max; i++)
{
OtherParts.Add(new OtherPart());
}
}
Any suggestions on how to effectively limit the max number of items added to the nested collection?
Thanks!
You probably need a custom validator, similar to this:
public class MaxItemsAttribute : ValidationAttribute
{
private readonly int _max;
public MaxItemsAttribute(int max) {
_max = max;
}
public override bool IsValid(object value) {
var list = value as IList;
if (list == null)
return false;
if (list.Count > _max)
return false;
return true;
}
}
In your model code, just do this:
[MaxItems(5)]
public virtual ICollection<OtherPart> OtherParts { get; set; }
Change to i < max
public void CreateOthers(int count = 1, int max = 5)
{
for (int i = 0; i < count && i < max; i++)
{
OtherParts.Add(new OtherPart());
}

Categories

Resources