I've a Blazor WebAssembly Hosted application in which I've the following component:
liveStreaming.razor
@if (_isStreaming) {
<img src="@_streamUrl">
} else {
// show loading circle
}
liveStreaming.razor.cs
using Microsoft.AspNetCore.Components;
using System;
using System.Threading.Tasks;
using System.Timers;
public partial class LiveStreaming: ComponentBase, IDisposable
{
private bool _isStreaming;
private string _streamUrl;
private string _placeholderImgUrl;
private Timer _checkConnectionTimer;
protected override async Task OnInitializedAsync() {
_isStreaming = false;
_placeholderImgUrl = "emptyImage.jpg";
_checkConnectionTimer = new Timer();
_checkConnectionTimer.Interval = 6000;
_checkConnectionTimer.Elapsed += CheckConnection;
_checkConnectionTimer.Start();
// [...]
}
private async void CheckConnection(object sender, ElapsedEventArgs e) {
_checkConnectionTimer.Stop();
if (IsConnectionEstablished()) {
_isStreaming = true;
_streamUrl = "http://192.168.0.2/axis-cgi/mjpg/video.cgi";
StateHasChanged();
} else {
_isStreaming = false;
StateHasChanged();
}
_checkConnectionTimer.Start();
}
public void Clean() {
_checkConnectionTimer.Stop();
_streamUrl = _placeholderImgUrl;
StateHasChanged();
}
public async void Dispose() {
if (_checkConnectionTimer != null) { _checkConnectionTimer.Dispose(); }
}
}
The problem is that, without the Close() method, if I navigate to another component of the Blazor app, the stream request from the img tag is not interrupted despite the Dispose() method being called. I can see this from the bandwitdh usage. Furthermore, if I come back to the page, let's say the stream bandwitdh is 3Mb/s, another 3Mb/s is added to the currently used bandwidth. And this happens every time I leave and then come back to the page. It's like http stream request is never interrupted and a new one is created every time, without removing the old one.
In order to circumvent this problem I had to add the Clean() method you see. I've had to setup a complex mechanism in order to change the currently loaded component: every time a request to navigate to a different component arrives, the mechanism calls the Clean() method on the current loaded component before invoking _navigationManager.NavigateTo("OtherComponentName"). In other words Clean() is always called just before Dispose() method.
I'm not very happy with this solution since I've had to arrange a complex mechanism in order to achieve something that should be a given. Do you know a better way to do this?
Some test I've done:
Moving the code that now lies in Clean() inside Dispose() does nothing. Even if after StateHasChanged() I invoke Task.Delay(1). I suppose once the Dispose method has been called, the component is not rendered anymore.
Changing the code in Clean() to
_checkConnectionTimer.Stop(); _isStreaming = false; StateHasChanged();
Does nothing. It's like I have to change the img src in order to force the http stream request to stop.
Any help will be greately appreciated. Thanks.
EDIT: I found out that in order to mitigate the problem, you can define a javascript method in charge of resetting the img 'src' attribute and invoking it in the Dispose() method. This way there is no need to use strange workarounds like the one I described above.