What is the recommended way to release the UI from a long running background task in Blazor client-side - azure

Our Blazor (client-side) app is made up of many components all existing on the UI at the same time. One of these has to do a number of large data calls to Azure SQL. This component does these calls regardless of whether it has UI focus or not. Each of calls these can take up to 3 seconds to return its result during which it renders the UI unresponsive. How can we keep the UI responsive during these calls without using Blazor server-side. Using Task.Run etc does not help in single threaded architecture. Using loading spinners is also not an option as this still leaves the UI unresponsive and may not be visible to the user. Is there any way to achieve this goal in current Blazor 0.9.0?
Running latest Blazor preview release (0.9.0-preview3-19154-02)

You can use Invoke, I modified counter example page to illustrate it, you will need a kind of singleton DI object to avoid running the process for twice.
Remember Blazor is an experimental project. Also, this answer is also an experimental approach.
#page "/counter"
<h1>Counter</h1>
<p>Current count: #currentCount</p>
<button class="btn btn-primary" onclick="#IncrementCount">Click me</button>
#functions {
int currentCount = 0;
void IncrementCount()
{
currentCount++;
}
protected override void OnInit()
{
Invoke(
//here your task.
async () =>
{
for(var i =0; i< 50; i++)
{
await Task.Delay(1000);
currentCount++;
StateHasChanged();
System.Console.WriteLine("Still running ...");
}
});
}
}

If async calls does not help then you can use browser workers, just need to implement some js interop.

I've had success with Task().Start()
put your work in an async Task like so:
async Task MyWork()
{
//sleep 10000
}
now from wherever you don't want this work to block call:
new Task( () => MyWork()).Start() );
I've only used this with Blazor Server, so haven't tested it with Client side Blazor which I hear can have different results because of its running on a single thread.

the suggested answer did not work, for me, I ended up using :
protected override void OnInitialized()
{
InvokeAsync(async () =>
{
myvar = await YourCodeHere();
StateHasChanged();
});
base.OnInitialized();
}
public async Task<MyVarType> YourCodeHere()
{
...
}
Explanation: I have a class called MyVarType that I am using to display values on the Razor component. I have a myVar variable instantiated with that class, and initially it is empty. The component will render its default values immediately. Upon initializing the variable is then also being asynchronously assigned from the OnInitialized method. The YourCodeHere function could take several seconds. The Razor component rerenders when calling StateHasChanged() so it displays the loaded values.

Related

How can I update progress bar without blocking UI? [duplicate]

This question already has answers here:
How do I update the GUI from another thread?
(47 answers)
Closed 1 year ago.
Currently I am creating a background STA thread to keep the UI responsive but it slows down my function calls on the main thread.
Based on this thread How to update progress bar while working in the UI thread I tried the following but the UI only gets updated after all of the work has finished. I tried playing around with the Dispatcher priorities but none of them seem to work.
What I also tried is adding _frmPrg.Refresh() to my Progress callback but this does not seem to change anything.
Dim oProgress = New Progress(Of PrgObject)(Sub(runNumber)
_frmPrg.Invoke((Sub()
_frmPrg.Status = runNumber
End Sub))
End Sub)
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(Sub()
DoLongRunningWork(oProgress, _cancellationToken)
End Sub, System.Windows.Threading.DispatcherPriority.Background)
I can't really help you with your problem, but I'll try to clarify what happens in your posted code.
DoLongRunningWork will be invoked through Dispatcher on the UI thread, when the UI thread is not busy. But once started, it will block the UI thread until it completes. So you can't show a progress this way. Your single chance is, to let DoLongRunningWork run on a background thread. That brings you nothing, if the long-running methods come from office objects, which must be accessed from the UI thread...
The Progress class (see the remarks section) invokes your event handler on the UI thread automatically, so you don't need _frmPrg.Invoke in your event handler.
Maybe you can start a STAthread for your progress form and show it from there. The instance of your Progress class must be created in this thread too, but not before your form is shown to ensure, that the thread becomes a WindowsFormsSynchronisationContext (or you set one explicitly after starting the thread). A plain SynchronisationContext won't work!
At least you get updates in your form this way, but the UI thread of the office app will still be blocked. And of course, any action you make with your progress form must be invoked on the UI thread, if accessing office objects.
After reading some other posts, I decided to suggest another solution. My previous answer still contains usable information, so I'll leave it there. I'm not familiar with VB.NET syntax, so the samples are in C#. I have tested the code in a VSTO plugin for PowerPoint, but it should run in any office application.
Forget the Progress class and background threads. Run everything on the UI thread!
Now use some async code. To stay on the UI thread, we need a "good" SynchronizationContext.
private static void EnsureWinFormsSyncContext()
{
// Ensure that we have a "good" SynchronisationContext
// See https://stackoverflow.com/a/32866156/10318835
if (SynchronizationContext.Current is not WindowsFormsSynchronizationContext)
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
}
This is the event handler of a button. Note the manually added async keyword. The SynchronizationContext.Current gets resetted again and again, so ensure the good one in the EventHandler:
private async void OnButtonClick(object sender, EventArgs e)
{
EnsureWinFormsSyncContext();
// Return from event handler, ensure that we are really async
// See https://stackoverflow.com/a/22645114/10318835
await Task.Yield();
await RunLongOnUIThread();
}
This will be the worker method, also running on the UI thread.
private async Task RunLongOnUIThread()
{
//Dummy code, replace it with your code
var pres = addIn.Application.Presentations.Add();
for (int i = 0; i < 100; i++)
{
Debug.Print("Creating slide {0} on thread {1}", i, Thread.CurrentThread.ManagedThreadId);
// If you have some workloads that can be run on a background
// thread, execute them with await Task.Run(...).
try
{
var layout = pres.Designs[1].SlideMaster.CustomLayouts[1];
var slide = pres.Slides.AddSlide(i + 1, layout);
var shape = slide.Shapes.AddLabel(Microsoft.Office.Core.MsoTextOrientation.msoTextOrientationHorizontal, 0, 15 * i, 100, 15);
shape.TextFrame.TextRange.Text = $"Text on slide {i + 1}";
}
catch (Exception ex)
{
Debug.Print("I don't know what am I doing here, I'm not familiar with PowerPoint... {0}", ex);
}
// Update UI
statusLabel.Text = $"Slide {i + 1} done";
progressBar1.Value = i + 1;
// This is the magic! It gives the main thread the opportunity to update the UI.
// It also processes input messages so you need to disable unwanted buttons etc.
await IdleYield();
}
}
The following method is for Windows Forms Applications where it does the job perfect. I've tried it also in PowerPoint. If you are facing problems, try the WPF flavour with await Dispatcher.Yield(DispatcherPriority.ApplicationIdle) instead of await IdleYield().
private static Task IdleYield()
{
var idleTcs = new TaskCompletionSource<bool>();
void handler(object s, EventArgs e)
{
Application.Idle -= handler;
idleTcs.SetResult(true);
}
Application.Idle += handler;
return idleTcs.Task;
}
Here are the (clickable) links to the answers that I used (I can't put them in the code-blocks...).
Incorrect async/await working, Excel events in Excel Application Level Add-in
When would I use Task.Yield()?
Task.Yield - real usages?
If in your real code something runs not as expected, check the thread you are running on and SynchronizationContext.Current.

How to structure a nodejs application that requires many API calls for a single page display?

For a web page that requires several kinds of data (i.e. for different widgets), how do you structure the API calling from the client-side? For instance, I have an application that is currently doing something like the following...
api.doOne(function (resultOne) {
api.doTwo(..., function (resultTwo) {
api.doThree(..., function (resultThree) {
api.doFour(function (resultFour) {
...
api.doTen(function(resultTen) {
finallyDisplayPage(resultTen);
... and it seems so wrong. Apart from the fact that there is major "callback-hell", it seems to defeat the purpose of asynchronous programming, because each api call is waiting for the old one to finish processing. So it is really slow as well... but what is the alternative? Should the application do the following instead?
// essential information before display
api.doOne(function (resultOne) {
api.doTwo(..., function (resultTwo) {
displayPage(resultTwo);
}
}
// the remaining can data can be inserted after the inital page load
api.doThree(..., function (resultThree) {
displayPage(resultThree);
}
api.doFour(function (resultFour) {
displayPage(resultFour);
}
...
api.doTen(function(resultTen) {
displayPage(resultTen);
}
Any advice, hints, or pointers to examples I can view online would be appreciated.

Cross Thread UI

I have an issue with cross threading on a UI. I have read all the ways to do it and have implemented them as seen below.
public void UpdateList(object obj)
{
// do we need to switch threads?
if (listBox1.InvokeRequired)
{
MethodInvoker del = () => UpdateList(obj);
this.Invoke(del);
return;
}
// ok so now we're here, this means we're able to update the control
// so we unbox the object into a string
string text = (string)obj;
// and update
listBox1.Items.Add(text);
}
The issue comes when I try to do a
hubConnection.Start().Wait();
After that call I am trying to update my list.
Without the wait is fine. When I add the Wait it hangs on the UpdateList Invoke. There is no error...it just hangs.
I am handling this call in a button event.
Wait() is creating a deadlock on the mainthread.
Replace the hubconnection.Start.Wait() with:
await hubconnection.Start() in an async method:
public void async StartHubClickedEvent(...){
await hubconnection.Start()
}
The Microsoft Async library enables use of async/awaut on .net 4.0 and VS12.
Install-Package Microsoft.Bcl.Async
See Deadlock when thread uses dispatcher and the main thread is waiting for thread to finish
You've generated a recursive loop. Assuming an Invoke is Required, you'll call up the same method, hit if (listBox1.InvokeRequired) again (which will still pass true) and start looping as you keep calling up the same method again and again. It's better to do an If..Else pattern here where you directly invoke the change on the ListBox or simply perform the change without the invoke
An Example
if (listBox1.InvokeRequired)
{
listBox1.Invoke(()=> { listBox1.Items.Add((string)text) };
}
else
{
string text = (string)obj;
// and update
listBox1.Items.Add(text);
}

Nested IMessageQueueClient publish using Servicestack InMemoryTransientMessageService

We are using InMemoryTransientMessageService to chain several one-way notification between services. We can not use Redis provider, and we do not really need it so far. Synchronous dispatching is enough.
We are experimenting problems when using a publish inside a service that is handling another publish. In pseudo-code:
FirstService.Method()
_messageQueueClient.Publish(obj);
SecondService.Any(obj)
_messageQueueClient.Publish(obj);
ThirdService.Any(obj)
The SecondMessage is never handled. In the following code of ServiceStack TransientMessageServiceBase, when the second message is processed, the service "isRunning" so it does not try to handled the second:
public virtual void Start()
{
if (isRunning) return;
isRunning = true;
this.messageHandlers = this.handlerMap.Values.ToList().ConvertAll(
x => x.CreateMessageHandler()).ToArray();
using (var mqClient = MessageFactory.CreateMessageQueueClient())
{
foreach (var handler in messageHandlers)
{
handler.Process(mqClient);
}
}
this.Stop();
}
I'm not sure about the impact of changing this behaviour in order to be able to nest/chain message publications. Do you think it is safe to remove this check? Some other ideas?
After some tests, it seems there is no problem in removing the "isRunning" control. All nested publications are executed correctly.

How to optimize tests validating asynchronous code?

We are developing a WPF application using TDD. As we're already working on this solution for almost two years, we've written a huge bunch of tests (almost 2000 Unittests right now).
There are some classes, that need to implement functionality multithreaded and asynchronously. For example a communication-component that can both send and receive messages and parse them. The dependencies are always mocked using RhinoMocks.
Our Test-Methods targeting these classes look very similar, as following:
[TestMethod]
public void Method_Description_ExpectedResult(){
// Arrange
var myStub = MockRepository.GenerateStub<IMyStub>();
var target = new MyAsynchronousClass(myStub);
// Act
var target.Send("Foo");
Thread.Sleep(200);
//Assert
myStub.AssertWasCalled(x => x.Bar("Foo"));
}
As you can see, this test runs at least for 200 ms due to the Thread.Sleep(). We optimized the test replacing the AssertWasCalled with a active polling method, s.th. like this:
public static bool True(Func<bool> condition, int times, int waitTime)
{
for (var i = 0; i < times; i++)
{
if (condition())
return true;
Thread.Sleep(waitTime);
}
return condition();
}
We can now use this WaitFor.True(...) Method by changing the AssertWasCalled to:
var fooTriggered = false;
myStub.Stub(x => x.Bar("Foo")).Do((Action)(() => fooTriggered = true)));
WaitFor.True(() => fooTriggered, 20, 20);
Assert.IsTrue(fooTriggered);
This construct will terminate earlier if the condition matches, but anyway - this takes too long for us. Running all of our 2000 Tests need about 5 Minutes (building and running them).
Is there any smart trick how we could optimize code like this?
You can use a monitor. I'm making this up so please excuse me if it isn't quite compiling, but it'll look something like:
[TestMethod]
public void Method_Description_ExpectedResult(){
// Arrange
var waitingRoom = new object();
var myStub = MockRepository.GenerateStub<IMyStub>();
myStub.Setup(x => x.Bar("Foo")).Callback(x =>
{
Monitor.Enter(waitingRoom);
Monitor.Pulse(waitingRoom);
Monitor.Exit(waitingRoom);
}
var target = new MyAsynchronousClass(myStub);
// Act
Monitor.Enter(waitingRoom);
target.Send("Foo");
Monitor.Wait(waitingRoom);
Monitor.Exit(waitingRoom);
//Assert
myStub.AssertWasCalled(x => x.Bar("Foo"));
}
Code written within the Monitor can't run until it's free. The test will cause the acting thread to wait until Monitor.Wait has been called. Then the callback can enter and pulse the Monitor. The test then "wakes up", and once the callback has exited the monitor, it gets control back and exits too, allowing you to Assert.
The only thing I haven't covered is that if Bar("Foo") doesn't get called it will hang, so you might want to have a timer pulse the thread too.
You can create a class which does the complex monitoring bits for you if you use it a lot. This is one I wrote to deal with asynchronous checks in UI automation; adapting it for what you're doing might help you.

Resources