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.
You need to add a finalizer/deconstructor to properly call the dispose. There is a recent article that describes the proper way to create a disposable class:
EVERYTHING THAT EVERY .NET DEVELOPER NEEDS TO KNOW ABOUT DISPOSABLE TYPES: PROPERLY IMPLEMENTING THE IDISPOSABLE INTERFACE
Here is the full example code he provides in the post:
public class PdfStreamer : IDisposable
{
private bool _disposed;
private readonly MemoryStream _stream = new MemoryStream();
public PdfStreamer()
{}
~PdfStreamer() => Dispose();
protected virtual void Dispose(bool disposing)
{
if (this._disposed)
{
return;
}
if (disposing)
{
this._stream?.Dispose();
}
this._disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Related
I am creating a Xamarin Forms application, and I am using the Xamarin Profiler to show that I have a memory leak. I have tracked the memory leak down to where it is happening, but I can't understand WHY it is happening.
I have a class (we will call it MyClass for now). And that class is using a Timer to call a service once every second. That service makes a REST call to retrieve a bunch of information, and then serializes the results back into an object....
MyClass:
public class MyClass : ContentPage
{
private readonly IMyService myService;
public MyClass() : base()
{
}
protected override async void OnAppearing()
{
StartTimer();
}
private void StartTimer()
{
Task.Run(async() =>
{
while(true)
{
myService = ((App)App.Current)
.serviceProvider
.GetRequiredService<IMyService>();
//--- everytime I call myService.GetSystemStatus(), my allocated memory continues to rise
MyResponse response = await myService.GetSystemStatus();
Device.BeginInvokeOnMainThread(() =>
{
// update the UI here...
});
await Task.Delay(1000);
}
});
}
}
MyService (Singleton):
public class MyService : IMyService
{
private readonly IMyHttpClientFactory httpClientFactory;
public MyService(IMyHttpClientFactory httpClientFactory)
{
this.httpClientFactory = httpClientFactory;
}
public async Task<MyResponse> GetSystemStatus()
{
return await httpClientFactory.Create().GetAsync<MyResponse>(
"http://example.com/api/status"
);
}
}
MyHttpClientFactory (Singleton):
public class MyHttpClientFactory : IMyHttpClientFactory
{
private readonly IServiceProvider _serviceProvider;
public MyHttpClientFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public MyHttpClient Create()
{
return _serviceProvider.GetRequiredService<MyHttpClient>();
}
}
MyHttpClient:
public class MyHttpClient : IDisposable
{
private HttpClient _httpClient;
public MyHttpClient ()
{
_httpClient = new HttpClient();
_httpClient.Timeout = TimeSpan.FromSeconds(10);
}
public async Task<T> GetAsync<T>(string url) where T : new()
{
string s = await GetStringAsync(url);
return JsonConvert.DeserializeObject<T>(s);
}
public async Task<string> GetStringAsync(string url)
{
using (var response = await _httpClient.GetAsync(url))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
}
My services are defined as follows:
public partial class App : Application
public ServiceProvider serviceProvider;
public App()
{
IServiceCollection services = new ServiceCollection();
ConfigureServices(services);
serviceProvider = services.BuildServiceProvider();
InitializeComponent();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<MyHttpClient>("MyHttpClient", x =>
{
x.Timeout = TimeSpan.FromSeconds(5);
});
services.AddSingleton<IMyHttpClientFactory, MyHttpClientFactory>();
services.AddSingleton<IMyService, MyService>();
}
}
Best I can tell, the memory is going up because I am referencing the DI MyService inside a separate thread. But I am not sure if this is the reason or if there is something else that would be causing the leak?
Any advice would be greatly appreciated!!!
Thanks!
From what I understand from your code and your comments, it looks like you're looping by calling StartTimer() inside the Device.StartTimer() method.
According to the documentation, Device.StartTimer() is recurring and will occur every X seconds, depending of your interval parameter.
By removing the call to StartTimer() (the one between t.Dispose() and return false of MyClass.StartTimer, your code should work as expected and you will not create a new timer every x seconds
What could be the cause of the leak:
Your MyHttpClient class implements the IDisposable interface, yet the code to use an instance of this class is not leveraging the disposable nature of the object.
Even though the internal HttpClient instance is wrapped in a using statement, the MyHttpClient instance will not be disposed of as you would expect.
// from MyHttpClient class
public async Task<MyResponse> GetSystemStatus()
{
// no using statement here
return await httpClientFactory.Create().GetAsync<MyResponse>(
"http://example.com/api/status"
);
}
// should be:
public async Task<MyResponse> GetSystemStatus()
{
using (var client = await httpClientFactory.Create())
{
return await client.GetAsync<MyResponse>("http://example.com/api/status");
}
}
Another thing to try is to change the location of the resolution of the MyService instance to inside the Task since this is where it is used. This will allow the task to own the resource, and allow it to be collected when the task is complete.
private void StartTimer()
{
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
Task t = Task.Run(async() =>
{
// resolve the service here
myService = ((App)App.Current)
.serviceProvider
.GetRequiredService<IMyService>();
MyResponse response = await myService.GetSystemStatus();
Device.BeginInvokeOnMainThread(() =>
{
// update the UI here...
});
});
t.Wait();
t.Dispose();
StartTimer();
return false;
});
}
A couple of additional observations of your code:
In your HttpClientFactory's Create() method, you are resolving an instance of your client from the DI container.
Your MyHttpClient class has a default constructor which means the resolution is not needed since there are no additional dependencies requiring DI support.
Your code could simply return a new MyHttpClient() instance from the Create() method without the need for DI.
Your MyHttpClient also implements the IMyHttpClient interface, but your factory returns the concrete type. This means you need to either remove the interface as unnecessary or change the return type to be the interface type since the interface is redundant unless it is used.
Thank you all for your answers....
I finally figured out the source of the memory leak.
The problem was that I was referencing "MyService" like this:
myService = ((App)App.Current)
.serviceProvider
.GetRequiredService<IMyService>();
The problem was that the serviceProvider object was a public property on my App. So each time I referenced the provider inside my loop, it was creating the leak.
To get around this, I added an abstract method to each of my pages that implemented MyClass to return the service correctly using DI. This has corrected my memory leak issue....
Thanks all for the help!
I don't think that your timer logic is the cause of the leak.
But in case it is useful to you, here is a clean way to do work periodically, yet if work takes a long time, avoid events "piling up".
Given await/async, no Timer is needed.
(There is an alternative solution that starts/stops a single System.Timers.Timer, but I won't go into that here.)
Replace StartTimer() declaration with the following:
/// <summary> Runs until keepRunning() returns false.
/// Delays by "msecDelay" AFTER finishing the previous loop's non-UI work. </summary>
private void StartTaskLoopWhileKeepRunning(Func<bool> keepRunning, int msecDelay = 250)
{
Task.Run(async () =>
{
while (keepRunning())
{
// Do non-UI work here.
// ... possibly slow work ...
Device.BeginInvokeOnMainThread(() =>
{
// NOTE: This work will run in parallel with the next delay.
// ... Do UI work here. ...
});
// Non-UI thread sleeps for msec.
await Task.Delay(msecDelay);
}
});
}
I am using log4net (.Net) to write kafka appender and I am running into an issue where I cannot use await ProduceAsync.
Error
An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it. ,
StackTrace : at
System.Web.AspNetSynchronizationContext.OperationStarted(at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Create()
Code
public class CustomAppender: AppenderSkeleton
{
private IProducer<Null, string> p;
public override void ActivateOptions()
{
// Setup kafka producer
}
protected override void Append(LoggingEvent loggingEvent)
{
// Get JSON from application
// Add additional data to the json
callBroker(json, topic);
}
private async void callBroker(string json, string topic)
{
var result = await p.ProduceAsync(Topic, new Message<Null, string>{Value=json});
}
}
I can return Task in my callBroker method but then there is no async override for Append method.
So my question is, Can I use Producer.Produce instead of ProduceAsync in a high volume environment? this program will be logging >500 messages/sec, is there a preference on which works better? I also need to handle some exceptions and take some action if it fails for specific error codes.
Sync version
protected override void Append(LoggingEvent loggingEvent)
{
CallBroker(topic, json);
}
private void CallBroker(string topic, string message)
{
producer.Produce(topic, new Message<Null, string> { Value = message });
}
Semi-async version
If you can't change the signature of the Append method
then you can call an async method in blocking mode via the following way:
protected override void Append(LoggingEvent loggingEvent)
{
CallBrokerAsync(topic, json).GetAwaiter().GetResult();
}
private async Task CallBrokerAsync(string topic, string message)
{
await producer.ProduceAsync(topic, new Message<Null, string> { Value = message });
}
Async shines when it is used all the way down (from the top most entry-point through all the layers till the lowest component which calls the async I/O operation)
As always measure, measure and measure to understand how does this change affect your application.
I'm just starting with Android Things with Xamarin, and I've already successfully turned on a LED, but I'm having trouble to detect a push button input.
I think the problem is the "RegisterGpioCallback" in the code below, but I'm not sure and really don't know how to fix it. Can somebody help me?? This is the code I'm using:
public class BlinkActivity : Activity
{
private IGpio gpio;
private IGpio button;
private IGpioCallback mButtonCallback;
protected override void OnCreate(Bundle savedInstanceState)
{
this.mButtonCallback = mButtonCallback;
PeripheralManager peripheralManager = PeripheralManager.Instance;
gpio = peripheralManager.OpenGpio("BCM17");
gpio.SetDirection(Gpio.DirectionOutInitiallyLow);
gpio.Value = false;
button = peripheralManager.OpenGpio("BCM4");
button.SetDirection(Gpio.DirectionIn);
button.SetEdgeTriggerType(Gpio.EdgeNone);
button.RegisterGpioCallback(new Handler(), mButtonCallback);
base.OnCreate(savedInstanceState);
Task.Run(() =>
{
if (mButtonCallback.OnGpioEdge(button) == true)
{
gpio.Value = !gpio.Value;
}
});
}
}
You need to actually implement the IGpioCallback interface so the com.google.android.things.pio library can make a "call back" into your application when the value of the GPIO changes.
Assign the RegisterGpioCallback to the actual object instance that has implemented the interface, in the following example, that will be on the Activity.
public class BlinkActivity : Activity, IGpioCallback
{
~~~~
button.RegisterGpioCallback(new Handler(), this);
~~~~
// remove the Task.Run block
public OnGpioEdge(Gpio gpio)
{
Log.Debug("SO", gpio.Value.ToString());
}
~~~~
}
I had some issues following this in Maui. I'd created an IGPIO interface in the shared code, and then a platform-specific GPIO class inside the Android platform code. The code would run, but then crash when it got to the Registration of the callback. The error said I had to pass a Java.Lang.Object or Java.Lang.Throwable as argument 2 to com.google.android.things.pio.impl.GpioImpl.registerGpioCallback(android.os.Handler, com.google.android.things.pio.GpioCallback).
I tried using each of these as the base class for my GPIO class, but then the app wouldn't build. When I'd autogenerated the IGpioCallback interface implementation in the class it had created a dispose method and a Handle property along with the OnGpioEdge callback method. Removing these allowed the app to work properly. so my class definition ended up looking something like this for the registration and event:
public class GPIO : Java.Lang.Throwable, IGPIO, IGpioCallback
{
public event EventHandler OnButtonEdge;
IGpio ButtonPin;
public void registerPinForEdgeDetection(string pinName)
{
using (var peripheralManager = PeripheralManager.Instance)
{
ButtonPin = peripheralManager?.OpenGpio(pinName);
ButtonPin.SetDirection(Gpio.DirectionIn);
ButtonPin.SetEdgeTriggerType(Gpio.EdgeBoth);
ButtonPin.RegisterGpioCallback(new Android.OS.Handler(), this);
}
}
public bool OnGpioEdge(IGpio gpio)
{
OnButtonEdge?.Invoke(ButtonPin, EventArgs.Empty);
return true;
}
}
I'm using a very simple asp.net mvc application with Entity Framework 6.0.2, .Net 4.5.1:
public class HomeController : Controller
{
public ActionResult Index()
{
int count;
using (var db = new LocalContext())
{
count = db.Counters.Count();
}
return View(count);
}
}
public class Counter
{
public int Id { get; set; }
}
public class LocalContext : DbContext
{
public DbSet<Counter> Counters { get; set; }
}
If I do a load test on it, I eventually get an Out Of Memory Exception. (tinyget -srv:localhost -port:<port> -uri:/home/index/ -threads:30 -loop:5000). In Performance monitor I see the generation 2 Heap steadily grow. If I use a smaller loop value (say 500), the size grows until tinyget stops. Then the heap size stays the same (for at least 20 minutes, after that I stopped the server).
What am I doing wrong?
EDIT
So I tried Simon Mouriers suggestion and left out the EF code. Then I don't have memory problems. So I thought, maybe if I use Release instead of Debug, it will make a difference. And it did! Memory was released after a while and I could put high load on the site. Then I switched back to Debug to see if I could get more info and... even in Debug mode no problems anymore. FML, I worked a day on it and now I can't reproduce it anymore.
In your case the internally managed class that inherits from DbContext would then need to implement IDisposable and inside of the LocalContext add the following:
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Manage any native resources.
}
//Handle any other cleanup.
}
Without specifically overriding the call to dispose, the using statement is only going to call Dispose() against the base class, while you need to dispose of the parent and base.
I don't see anything wrong with your code. Maybe this could be an issue with the underlying ADO.NET provider. Which database are you using?
I remember having issues with some unit test that did not release SQLite database files which I eventually solved with this code (in my DbContext class)
public class LocalContext : DbContext
{
protected override void Dispose(bool disposing)
{
var connection = this.Database.Connection;
base.Dispose(disposing);
connection.Dispose();
}
}
May be unrelated but I would give it a try.
This might not be the correct answer, but i suggest to keep your context managed by a IoC container. And add it with TrasientScope, or PerHttpRequest scope(example not provided due to a large varierty of ioc container syntax). If you want a specfic example, please reply for what DI you want
I would go for creating a class connection to the DB ..
public class DBconnection : IDisposable
{
private ChatEntities _db = new ChatEntities();
protected ChatEntities Db {
get { return _db; }
}
public void Dispose()
{
if (_db != null)
{
_db.Dispose();
}
}
}
Then when you would like to connect and manipulate .. Lets call it the DBlogic class ..
public class DBlogic : DBconnection
{
internal void WriteToDB(String str){
//Do something ...
Db.SaveChanges();
}
}
This will eventually cause the Dispose to empty resources.. plus its cleaner .. at least for my eyes :D
Actually, the OutOfMemotyException is normal in this situation since the Garbage Collector does not occur immediately after you've finished with the object. In this scenario, you need to use GC.Collect() to perform a collection on all generations of memory and reclaim all memory that is inaccessible, immediately.
public class HomeController : Controller
{
public ActionResult Index()
{
int count;
using (var db = new LocalContext())
{
count = db.Counters.Count();
}
GC.Collect();
return View(count);
}
}
Note that you should not use GC.Collect() in production code since it interferes with the Garbage Collection mechanism.
Using C# I'd like to take control over the reading of the HTTP Requests from a POST. Primarily to read the stream of a multipart/form-data file upload to track the stream as it's received from the client.
Using the ProcessRequest or the Async BeginProcessRequest the body has already been parsed by ASP.net / IIS.
Is there a way to override the built-in reading via a HTTPHandler, or will I have to use another mechanism?
Many thanks
Andy
Update - Added code example as requested, albeit no different to a normal class that's implemented IHttpHandler
public class MyHandler : IHttpHandler
{
public bool IsReusable { get { return true; } }
public void ProcessRequest(HttpContext context)
{
// The body has already been received by the server
// at this point.
// I need a way to access the stream being passed
// from the Client directly, before the client starts
// to actually send the Body of the Request.
}
}
It appears that you can capture the stream via the context.BeginRequest event of a HttpModule.
For example :
public class Test : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(onBeginRequest);
}
public void onBeginRequest(object sender, EventArgs e)
{
HttpContext context = (sender as HttpApplication).Context;
if( context == nul ) { return; }
if (context.Request.RawUrl.Contains("test-handler.ext"))
{
Logger.SysLog("onBeginRequest");
TestRead(context);
}
}
// Read the stream
private static void TestRead(HttpContext context)
{
using (StreamReader reader = new StreamReader(context.Request.GetBufferlessInputStream()))
{
Logger.SysLog("Start Read");
reader.ReadToEnd();
Logger.SysLog("Read Completed");
}
}
}
Really I was trying to avoid HttpModules, as they are processed for every .net request, so really I'd stil like to know how to do it via a HTTPHandler.
You can definitely do that by implementing an IHttpHandler.
This example will get you started. There is no need to override the built-in reading.
You receive all the data in the Request, and can process it as required.