1

I am using Angular 15 and ASP.NET Core 5. I get the paged items from backend when the pageSize and pageIndex are passed as parameters to it.

The action method that receives pageSize and pageIndex parameters then sends the paged items as well as totalCount to frontend.

Here's that code:

[HttpGet("getPagedCommodities")]
public async Task<IActionResult> GetPagedCommodities([FromQuery] PagingParameters pagingParameters)
{
    try
    { 
        var commodities = await _repository.Commodity.GetAllCommoditiesAsync();
        var totalCount = commodities.Count();
                
        var pagedCommodities = await _repository.Commodity.GetPagedCommoditiesAsync(pagingParameters);
                
        Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(totalCount));                

        return Ok(pagedCommodities);
    }
    catch
    {
        return StatusCode(500, "Internal server error");
    }
}

In the frontend, this is the method that gets the paged items:

getPagedCommodities(pageSize: number, pageNumber: number): Observable<CommodityForList[]> {
    let params: HttpParams = new HttpParams();
    params = params.append('pageSize', pageSize);
    params = params.append('pageNumber', pageNumber);
    
    let httpOptions = {
      params: params
    };
    return this.http.get<CommodityForList[]>(this.baseUrl + '/getPagedCommodities/', httpOptions);
      
  }

How can I read the totalCount http header parameter sent from server?

Thank you for your help.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
R. Nourmandi
  • 157
  • 12

2 Answers2

1

How to access the header parameters of an API-response

I now integrated your code into my own Angular/ .NET project and eventually figured out a code that works:

Backend: Startup.cs

I had to add X-Pagination to the CORS policy, otherwise it would always be undefined. Click here to read why this is needed.

services.AddCors(options =>
{
    options.AddDefaultPolicy(builder =>
    {
        builder.AllowAnyHeader()
                .AllowAnyMethod()
                .AllowAnyOrigin()
                .WithExposedHeaders("X-Pagination"); // I had to add this line
    });
});

Backend: Controller-Method

I had to change the input parameters from PagingParameters pagingParameters to [FromQuery] int pageSize, [FromQuery] int pageNumber:

[HttpGet("getPagedCommodities")]
public async Task<IActionResult> GetPagedCommodities([FromQuery] int pageSize, [FromQuery] int pageNumber)
{
    try
    { 
        var commodities = await _repository.Commodity.GetAllCommoditiesAsync();
        var totalCount = commodities.Count();
                
        var pagedCommodities = await _repository.Commodity.GetPagedCommoditiesAsync(pagingParameters);
                
        Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(totalCount));                

        return Ok(pagedCommodities);
    }
    catch
    {
        return StatusCode(500, "Internal server error");
    }
}

Frontend: Service-Method

By adding observe: 'response', access to HttpResponse<YourJsonObject> will be granted. You can then get your header-values via response.headers.get("Header-Key").

I also had to change the way I assemble the httpOptions (which is the second parameter of this.http.get).

getPagedCommodities(pageSize: number, pageNumber: number): Observable<{commodities: CommodityForList[]; totalCount: number}> {

    const params: HttpParams = new HttpParams()
                                .append('pageSize', pageSize)
                                .append('pageNumber', pageNumber);

    const url = `${this.baseUrl}/getPagedCommodities/`;

    return this.http.get<CommodityForList[]>(url, { observe: 'response', params })
        .pipe(
            map(response => {

            // Access 'total count' in header:
            const totalCount = response?.headers?.get('X-Pagination');
            const parsedTotalCount = +(totalCount ?? 0);

            return { commodities: response?.body ?? [],
                     totalCount: parsedTotalCount };
            })
        );
}

Eventually I was able to access the returned values as follows:

this.getPagedCommodities(0, 1).subscribe(
    res => {
        console.log('Commodities-Array:', res.commodities);
        console.log('Total count:', res.totalCount);
    }
);
kellermat
  • 2,859
  • 2
  • 4
  • 21
  • I want to get pagedCommodities as observable in the Listcomponent : this.commoditiesForList$ = this.commoditiesService.getPagedCommodities(this.pageSize, this.pageIndex); where, commoditiesForList$!: Observable; and to get the totalCount as: this.commoditiesForList$.subscribe(res => this.length = res.totalCount). is it possible? and how can I solve this problem? – R. Nourmandi Jan 22 '23 at 06:16
  • I tried your suggestion in the ListComponent as follows: this.commoditiesService.getPagedCommodities(this.pageSize, this.pageIndex).subscribe(res =>{ const totalCount = res?.headers?.get('X-Pagination'); // totalCount = undefined; const ptotal = +(totalCount ?? 0) // ptotal = 0; const cts = res?.body ?? []; // cts = []; As you can see, the results are not satisfactory! – R. Nourmandi Jan 22 '23 at 06:36
  • Also, I couldn't use the map in the service get method, because I was prompted with an error. So I used its body directly in the ListComponent. – R. Nourmandi Jan 22 '23 at 06:57
  • I integrated your code into my own Angular / .Net project and I was eventually able to reproduce your issues and solve them. Can you try my new suggestion? – kellermat Jan 22 '23 at 11:32
  • About your first question: What exactly is your need there? You would like to be able to subscribe to `totalCount` and `CommodityForList[]` separately? – kellermat Jan 22 '23 at 11:39
  • Firstly, I am using commodities list as Observable to combine it with input search text to have dynamic search, therefore, I need to get Observable commodities list from service method, secondly, because I am using mat-paginator, I need totalCount to set the Length property of it. – R. Nourmandi Jan 22 '23 at 19:23
  • I think in this thread you asked a clear question: "How can I read the totalCount http header parameter sent from server?" I think my detailed post answers this question and goes even further. Sadly, you didn't even try if my updated solution worked. I think if you don't know how to proceed from there, you should open a new stackoverflow-thread. – kellermat Jan 22 '23 at 19:46
0

You can pass the setting observe: 'response' to the http get to observe the whole response and not just the body.

this.http.get(myUrl, {
  observe: 'response',
  params
}).subscribe(response => console.log(response))

So now instead of getting the body, you now get the whole response where headers and body is a property of that response:

{
  headers: {
    totalCount: 123
  },
  status: 200,
  body: {}
}
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338