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