TL;DR: Deliver all the table content continuously paginated to the browser with .NET Core and Angular
Long Description:
I was thinking that delivering paginating data is kind of lame. Why should I,for seeing the whole data,should keep pressing next page / or scrolling down ? I understand that on the server it is necessary to do this – but on the client ?
And I was thinking – what about Observables in Angular ,combined with SignalR ? Those observables could obtain data every time – and SignalR is pushing cotinously,until it arrives at the end of the data.
Done with talking – let’s show some code:
We have an Employee classs
public class Employee
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }
code
and we are feeding with data in a DALEmployee
public class DalEmployee
    {
        public int FindCountEmployees(string name)
        {
            return ((name ?? "").Length + 1) * 10;
        }
        public async Task<Employee[]> FindEmployee(int pageNumber,int pageSize,string name)
        {
            await Task.Delay((pageNumber + 1) * 1000);
            var ret = new Employee[pageSize];
            int startNumber = (pageNumber - 1) * pageSize;
            for (int i = 0; i < pageSize; i++)
            {
                var e =new Employee();
                e.Id = startNumber + i;
                e.Name = e.Id + "employee ";
                ret[i] = e;
            }
            return ret;
        }
    }
We have SignalR that delivers continously the data via a Hub that is connected to an URL
//do not forget  services.AddSignalR().AddJsonProtocol()  ;
            app.UseSignalR(routes =>
            {
                routes.MapHub<MyHub>("/employees");
            })
and delivers all data continuously
 public class MyHub: Hub
    {
       
        public override async Task OnConnectedAsync()
        {
            Console.WriteLine("!!!!connected");
            await Task.Delay(1000);
        }
        public ChannelReader<Employee[]> GetEmps(string name)
        {
            var channel = Channel.CreateUnbounded<Employee[]>();
            _ = WriteItems(channel.Writer,name); //it not awaits!
            return channel.Reader;
        }
        private async Task WriteItems(ChannelWriter<Employee[]> writer,string name)
        {
            var dal = new DalEmployee();
            var nr = dal.FindCountEmployees(name);
            int nrPages = 10;
            for (int i = 0; i < nr / nrPages; i++)
            {
                var data = await dal.FindEmployee(i+1,nrPages,name);
                await writer.WriteAsync(data);
            }
            writer.TryComplete();            
        }
And this is all that is required on the .NET Core side
For the Angular Part
We have a hubconnectionbuilder that connect to the hub
export class MydataService {
  h:HubConnection;
  constructor(private http: HttpClient) { 
    this.h= new HubConnectionBuilder()
      .withUrl(environment.urlAPI + "/employees")
      .withHubProtocol(new JsonHubProtocol())
      //.withHubProtocol(new MessagePackHubProtocol())
      .build();
      window.alert('start');
    this.h.start()
    .catch((t) => window.alert(1));
  }
  
  
}
and a observable that returns the values
  public getAllEmpsStream(name:string): Observable<Employee[]>{
    
    const subject = new Subject<Employee[]>();
    this.h.stream<Employee[]>("GetEmps",name).subscribe(subject);
    return subject.asObservable();
  }
The code on the component is aggregating the values into an array
findEmployees(){
    this.load=true;
    this.service
      
      .getAllEmpsStream(this.nameEmp)
      //.getEmps(this.nameEmp)
      .pipe(finalize(() => this.load=false))
      .subscribe(it  => {
        
        //window.alert(it.length);
        this.emp.push(...it);
      });
  }
And that is all. All the values are returned page after page without the need of human intervention…
Leave a Reply