.NET Core SignalR Hub+ Angular Observable

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…