.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…
Where is the Angular part?
Starts at
” For the Angular Part “