I am trying to display messages to a list box in a WinForms application but it is not working. I am using the most recent Azure namespace, hence using asynchronous methods.
Below is Program.cs:
namespace App
{
public class Program
{
static ServiceBusClient client;
static ServiceBusProcessor processor;
public static List<string> data = new List<string>();
[STAThread]
public static async Task MessageHandler(ProcessMessageEventArgs args)
{
string body = args.Message.Body.ToString();
data.Add(body);
// complete the message. messages is deleted from the subscription.
await args.CompleteMessageAsync(args.Message);
}
public static void Main(string[] args)
{
Application.Run(new Form1());
}
public static async Task MainAsync()
{
client = new ServiceBusClient(_serviceBusConn);
// create a processor that we can use to process the messages
processor = client.CreateProcessor(_serviceBustopic, _ServiceBusSubscription, new ServiceBusProcessorOptions());
try
{
// add handler to process messages
processor.ProcessMessageAsync += MessageHandler;
// add handler to process any errors
processor.ProcessErrorAsync += ErrorHandler;
// start processing
await processor.StartProcessingAsync();
}
finally
{
await processor.DisposeAsync();
await client.DisposeAsync();
}
}
}
}
//end of Program.cs
And the Form.cs:
namespace App
{
public partial class Form1 : Form
{
public static List<string> AppNames = new List<string>();
public Form1()
{
InitializeComponent();
}
public static async Task receiveMessage()
{
await Program.MainAsync();
AppNames = Program.data;
}
public async void button1_Click(object sender, EventArgs e)
{
await receiveMessage();
for (int i = 0; i < AppNames.Count; i++)
{
listBox1.Items.Add("item" + AppNames[i].ToString());
}
}
}
}
There is a console version of this program that is functional, but I cannot seem to get it to display the messages in this Winforms Application. Some debugging showed me that the program was getting into the Main async. method upon the button being clicked, but it was not going into the Message Handler despite messages being sent through the service bus.
The pattern that you're using for the Service Bus client and processor isn't going to work in your scenario.
In MainAsync, when you call StartProcessingAsync, the method will return once the processor has started. Execution is then going to reach the finally block, where the processor and client are disposed. At that point, the processor is not running and, therefore, is not receiving messages.
Each time button1_Click runs, you're creating a new set of clients, establishing a new connection to Azure, and then immediately throwing them away.
The processor is intended to be a long-lived type that runs continuously in the background, calling back into your code as messages are available. Likewise, the client is intended to be used as a singleton for the lifetime of your application. I'd suggest reading through the Service Bus "Hello World" sample, which would help to explain some of the types and recommended patterns for use.
Related
I'm writing a Xamarin Forms Android app that connects to a SignalR server. My goal is to alert the user when their server connection is lost, but when the HubConnection.Reconnecting Event is fired, the content of my handler (shown below) doesn't run. Here's the code:
public static class SignalRService
{
private static HubConnection _connection { get; set; }
public static void SetupSignalRService(string url, string hubEndpoint)
{
_connection = new HubConnectionBuilder()
.WithUrl($"{url}/{hubEndpoint}")
.WithAutomaticReconnect()
.Build();
_connection.Reconnecting += Connection_Reconnecting;
}
public static async Task Connect()
{
await _connection.StartAsync();
}
public static Task Connection_Reconnecting(Exception arg)
{
Application.Current.MainPage.DisplayAlert("Reconnecting", "Check your server status.", "ok");
return Task.CompletedTask;
}
}
When using breakpoints, I can see that the thread makes its way to the opening code block { and first line, but jumps out of the method after I continue. I've tried very similar code on a C# console app project which worked right away (with Console.WriteLine instead of DisplayAlert). Any ideas on what else I can try?
Many thanks to users/1338/jason for supplying the answer:
have you tried running the DisplayAlert on the MainThread?
With the Xamarin.Essentials' MainThread class, the code indeed worked:
public static Task Connection_Reconnecting(Exception arg)
{
MainThread.BeginInvokeOnMainThread(() =>
Application.Current.MainPage.DisplayAlert("Reconnecting", "Check your server status.", "ok"));
return Task.CompletedTask;
}
Can I somehow register nonblocking handler on marshalled signal in different app domain?
I have a class that cannot be MarhsalByRef, yet I need to be able to call a method A on in in a different app domain D and then method B in the same app domain D.
This is could be easily solved by MarshalByRef - but I cannot use due to other code.
So I use a simple marshallable event and signal to the other app domain. I'd want to register a nonblocking handler in the other app domain - but it doesn't seem possible. I'm left with active wait?
Below is the repro:
[Serializable]
//this cannot be MarshalByRefObject
public class AppDomainTest
{
private readonly ManualResetEvent _mrse = new ManualResetEvent(false);
public static void Test()
{
AppDomainTest ap = new AppDomainTest();
Task.Factory.StartNew(() => ap.CreateDomainAndRun());
Thread.Sleep(1000);
ap.CallIntoDomain();
}
public void CreateDomainAndRun()
{
var otherDomain = AppDomain.CreateDomain("MyDomain", AppDomain.CurrentDomain.Evidence);
Task.Run(() => otherDomain.DoCallBack(RunInternal));
}
public void CallIntoDomain()
{
this._mrse.Set();
}
private void RunInternal()
{
//----------- HERE IS THE REPRO ---------------- //
//This crashes
//"Cannot wait on a transparent proxy"
//ThreadPool.RegisterWaitForSingleObject(_mrse, CancellationCallBack, null,
// Timeout.InfiniteTimeSpan, true);
Task.Factory.StartNew(() =>
{
//This works just fine
_mrse.WaitOne();
CallIntoDomainInternal();
}, TaskCreationOptions.LongRunning).Wait();
}
private void CancellationCallBack(object state, bool timedOut)
{
CallIntoDomainInternal();
}
private void CallIntoDomainInternal()
{
Console.WriteLine($"App domain: {AppDomain.CurrentDomain.FriendlyName}");
}
}
Registering callback with ThreadPool throws 'Cannot wait on a transparent proxy'. Active wait in task works just fine.
I am consuming one data streaming source which pushes data in interval >= 5 seconds. I have one observer like below to receive push notifications:
public class ConsoleDataObserver : IObserver<DataPipeEvent>
{
private DataPipeType _dataPipeType;
private LimitedConcurrencyLevelTaskScheduler _scheduler;//This is based on msdn parallel extensions examples
private TaskFactory _factory;
public ConsoleDataObserver(DataPipeType afDataPipeType)
{
_dataPipeType = afDataPipeType;
_scheduler = new LimitedConcurrencyLevelTaskScheduler(5);
_factory = new TaskFactory(_scheduler);
}
public void OnNext(DataPipeEvent dataPipeEvent)
{
_factory.StartNew(() => ProcessDataNow(dataPipeEvent));
}
private void ProcessDataNow(DataPipeEvent dataPipeEvent)
{
Thread.Sleep(8000); //just want to simulate long running tasks
}
public void OnError(Exception error)
{
Console.WriteLine("Provider has sent an error");
}
public void OnCompleted()
{
Console.WriteLine("Provider has terminated sending data");
}
}
I have following requirements:
In my OnNext, I don't want to block main thread and want to do long running processing tasks in other thread. I am using TaskScheduler to used ThreadPool. Is it good implementation? OnNext can get 500-1000 events per second. ProcessDataNow will log in case of any exception.
I am building a windows service that communicates with other processes using named pipe.
My unit test for the named pipe communication is throwing this error message 4 times:
System.AppDomainUnloadedException: Attempted to access an unloaded
AppDomain. This can happen if the test(s) started a thread but did not
stop it. Make sure that all the threads started by the test(s) are
stopped before completion.
Here's my unit test:
[TestMethod]
public void ListenToNamedPipeTest()
{
var watcher = new ManualResetEvent(false);
var svc = new WindowService();
svc.ClientMessageHandler += (connection, message) => watcher.Reset();
svc.ListenToNamedPipe();
sendMessageToNamedPipe("bla");
var wait = watcher.WaitOne(1000);
svc.Dispose();
Assert.IsTrue(wait, "No messages received after 1 seconds");
}
private void sendMessageToNamedPipe(string text)
{
var client = new NamedPipeClient<Message, Message>(DeviceCertificateService.PIPE_NAME);
client.ServerMessage += (conn, message) => Console.WriteLine("Server says: {0}", message.Text);
// Start up the client asynchronously and connect to the specified server pipe.
// This method will return immediately while the client runs in a separate background thread.
client.Start();
client.PushMessage(new Message { Text = text });
client.Stop();
}
How do I make all threads stop before my unit test stops?
Thanks
UPDATE:
The named pipe client does not have a close() function:
// Type: NamedPipeWrapper.NamedPipeClient`2
// Assembly: NamedPipeWrapper, Version=1.5.0.0, Culture=neutral, PublicKeyToken=null
// MVID: D2B99F4D-8C17-4DB6-8A02-29DCF82A4118
// Assembly location: C:\Users\Thang.Duong\Source\Workspaces\Post Tracking System\Applications\Dev\OHD\packages\NamedPipeWrapper.1.5.0\lib\net40\NamedPipeWrapper.dll
using System;
namespace NamedPipeWrapper
{
public class NamedPipeClient<TRead, TWrite> where TRead : class where TWrite : class
{
public NamedPipeClient(string pipeName);
public void Start();
public void PushMessage(TWrite message);
public void Stop();
public void WaitForConnection();
public void WaitForConnection(int millisecondsTimeout);
public void WaitForConnection(TimeSpan timeout);
public void WaitForDisconnection();
public void WaitForDisconnection(int millisecondsTimeout);
public void WaitForDisconnection(TimeSpan timeout);
public bool AutoReconnect { get; set; }
public event ConnectionMessageEventHandler<TRead, TWrite> ServerMessage;
public event ConnectionEventHandler<TRead, TWrite> Disconnected;
public event PipeExceptionEventHandler Error;
}
}
My WindowsService inherits the ServiceBase class which has the Dispose() function to close all threads. That's why I get all racing errors.
I had to avoid calling Dispose() function and replace it with client.Close() and svc.Close() function. The svc.Close() function is my custom implementation to stop and close the named pipe server.
I am trying to create a Windows Service that executes a job on a timer and has graceful shutdown. I've used various questions/answers on here to come up with the code below. It works but I want to make sure it's the most correct and elegant solution. And I have specific questions too (after code).
This is the main service class.
using System;
using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
namespace MyService
{
public class MyService : ServiceBase
{
CancellationTokenSource cancellationTokenSource;
System.Timers.Timer serviceTimer;
Task workTask;
public static void Main(string[] args)
{
if (!Environment.UserInteractive)
{
Run(new MyService());
}
}
protected override void OnStart(string[] args)
{
cancellationTokenSource = new CancellationTokenSource();
serviceTimer = new System.Timers.Timer(30000);
serviceTimer.Elapsed += new ElapsedEventHandler(serviceTimer_Elapsed);
serviceTimer.Start();
}
protected override void OnStop()
{
try
{
serviceTimer.Stop();
cancellationTokenSource.Cancel();
if (workTask != null)
{
workTask.Wait(10000);
}
}
finally
{
serviceTimer.Dispose();
serviceTimer = null;
cancellationTokenSource.Dispose();
cancellationTokenSource = null;
}
}
private void serviceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
serviceTimer.Stop();
workTask = Task.Run(() => StartWorkMethod()).ContinueWith(WorkCompleted);
}
private void WorkCompleted(Task completedTask)
{
workTask = null;
serviceTimer.Start();
}
private void StartWorkMethod()
{
Work work = new Work(cancellationTokenSource.Token);
work.StartWork();
}
}
}
This is the class that performs the (currently simulated) work.
using System.Threading;
namespace MyService
{
public class Work
{
CancellationToken cancellationToken;
public Work(CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
}
public void StartWork()
{
for (int i = 0; i < 4; i++)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
Thread.Sleep(10000);
}
}
}
}
The service works and runs all tasks without blocking the handler threads. If the service is stopped, the OnStop method will wait for the task's current block of work to complete for a certain period of time before stopping anyways (thanks Ian of Oz!).
Here are my specific questions:
To prevent the service from stopping immediately and waiting for the current block to complete, I am using the working variable and a while loop to wait for the Work class to complete and the bool to be set to false. Is this the best way to handle this? Already answered by Ian of Oz.
I also want to have a "feature" where if the current block is taking too long to complete, the OnStop method will only wait a certain amount of time before exiting anyways. What is the best way to implement that? Already answerd by Ian of Oz.
I've tried to make sure I handle all threading issues with my code. Is there anything I missed or that might cause trouble later with this implementation?
Also some notes to avoid any confusion:
Service install code is not included, I am using an installer to install the service.
The timer controls the time between executions so that there aren't overlapping executions if the previous execution takes longer; this is why the timer stops before starting the work and restarts after.
I've seen where the Main method is sometimes placed in it's own file, but mostly where the executable is also the installer; in this case it would only simplify this file by the Main method itself.
Edited to incorporate suggestion from Ian of Oz.