Reactive Extensions - Flushing Subject / IObservable in a synchronous fashion - c#

EDIT: I've edited a few lines of code, when running in the IDE it fails without an error or anything.
I'm new to Reactive Extensions and have a problem that I am trying to sort out. I'm using RX to queue events on a machine, then every so often send that data to a server. My problem appears to be that when the application is shutting down, anything that is an async call of any sort seems to just cancel and not run, thus the last batch of events never gets sent.
I have a Subject, where Event is my data class. I know now that a Subject might not be the best class to use, but here we are.
My code looks mostly like the following, added a few comments for clarity:
IObservable<IList<Event>> eventsObserver = Instance.EventBuffer.ToList<Event>();
var eventsEnumerable = eventsObserver.ToEnumerable();
List<Event> events = new List<Event>();
try
{
events = (List<Event>)eventsEnumerable.First(); // THIS LINE FAILS SILENTLY, EVEN IN DEBUGGER...
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine("Error: " + ex.Message);
}
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(someURI);
HttpResponseMessage response = client.PostAsync(somePage, new StringContent(SerializeToJSON(events))).Result;
response.EnsureSuccessStatusCode();
}
If I don't make the call to the web server synchronous (with the '.Result'), it fails there. I've tried a lot of ways to get the data from the IObservable into something I can send, but either the code fails (usually with a bad cast of some sort), or the events are not yet put into the data structure that I want to send. I know that RX is by nature async, and I'm asking to deal with it in a synchronous way, I would figure that there would be a solution. Thanks in advance!

Supposing that you control the Observable source, you could call Observable.OnComplete() like Enigmativity has pointed out. Otherwise, you could try to keep a copy of every value received before buffering it:
Observable.Do(x => localCopy = x).Buffer(..)
This local copy would be accessible to you at shutdown.
In any case, please note that .First() is marked obsolete in the latest Rx versions, possibly to avoid the problem you are experiencing.

Related

Finally block not executed when using HttpClient

I'm working on an Xamarin.Forms application with MVVM. In my viewmodel I want to Get all the patients from an API. This is the code:
public async Task GetAllPatients()
{
try
{
isFetchingData = true;
var response = await httpClient.GetStringAsync(baseUrl + "/patient?query=ma");
var resultPatients =
JsonConvert.DeserializeObject<ObservableRangeCollection<PatientViewModel>>
(testJson,jsonSerializerSettings);
AllPatients.ReplaceRange(resultPatients);
Patients.ReplaceRange(resultPatients);
}
catch(Exception e)
{
Console.WriteLine("*****ERROR kon API niet ophalen");
Console.WriteLine(e.Message);
}
finally
{
CheckIfEmptyList();
isFetchingData = false;
}
}
At first I just got the API hard coded from a json string (testJson) in my code and everything went smoothly. But from the moment I put the htppClient out of commentary something strange happens (even when I don't use the variable as you can see in the code(I get the same result when I do use the variable though)).
The finally block is not executed.
It is to say, when I go and debug the app, the code goes through the finally and checks if the list is empty and puts isFetchingData to false. But I don't see that happening on the screen. If the list is empty a label should occur but now that label doesn't go away when list is not empty. The INotifyPropertyChanged does work good because without the httpClient it runs smoothly.
I'm very new to asynchronous programming so maybe I forgot to implement something that has to make sure the GetStringAsync ends properly? Maybe it keeps fetching the data and that is why I never see the finally block executed (even though it does behind the screen). I've read some articles about asynchronous programming but couldn't find something that could help me out.
I must also say that this method is called from the constructor, which makes it a little bit harder to run async. I tried calling it without async await and I tried calling it this way:
Task.Run(async ()=> { await GetAllPatients(); });
I tried with and without ConfigureAwait(false) but that doesn't make a difference either.
Finding a way to not put the method in the constructor (as suggested by CrowCoder and Albert) seemed the only possibility. In this case I managed to do so, but for other people it may not be always possible.
Because I work with MVVM without a framework and I'm very new to Xamarin and asynchronous programming (I'm a student), it was too difficult for me to find an alternative to the constructor.
I will put this as an answer, but if someone can give a code example where it would work to put the method in the constructor, or a workaround, it is still very welcome.

Multithreading using AsyncCallback and GUI controls

Multithread programming is a new concept for me. I’ve done a bunch of reading and even with many examples, I just can’t seem to figure it out. I'm new to C# and programming.
I have a winform project with lots of custom controls I’ve imported and will utilize many tcpclients. I’m trying to get each control to be hosted on it’s own separate thread. Right now, I’m trying to get 1 control to behave appropriately with it’s own thread.
I'll show you what I have and then follow up with some questions regarding guidance.
string asyncServerHolder; // gets the server name from a text_changed event
int asyncPortHolder; // gets the port # from a text_changed event
TcpClient wifiClient = new TcpClient();
private void btnStart_Click(object sender, EventArgs e)
{
... // variable initialization, etc.
... // XML setup, http POST setup.
send(postString + XMLString); // Content to send.
}
private void send(string msg)
{
AsyncCallback callBack = new AsyncCallback(ContentDownload);
wifiClient.BeginConnect(asyncServerHolder, asyncPortHolder, callBack, wifiClient);
wifiClient.Client.Send(System.Text.Encoding.ASCII.GetBytes(msg));
}
private void ContentDownload(IAsyncResult result)
{
if (wifiClient.Connected)
{
string response4 = "Connected!!"; //debug msg
byte[] buff = new byte[1024];
int i = wifiClient.Client.Receive(buff);
do
{
response1 = System.Text.Encoding.UTF8.GetString(buff, 0, i);
} while (response1.Length == 0);
response2 = response1.Substring(9, 3); // pick out status code to be displayed after
wifiClient.Client.Dispose();
wifiClient.Close();
}
}
If you're knowledgeable about this, I bet you see lots of problems above. As it stands right now, I always get an exception one my first iteration of running this sequence:
"A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied"
Why is this? I have confirmed that my asyncServerHolder and my asyncPortHolder are correct. My second iteration of attempting allowed me to see response4 = "Connected!!" but I get a null response on response1.
Eventually I'd like to substitute in my user controls which I have in a List. I'd just like to gracefully connect, send my msg, receive my response and then allow my form to notify me from that particular control which plays host to that tcp client. My next step would be link up many controls.
Some questions:
1) Do I need more TCP clients? Should they be in a list and be the # of controls I have enabled at that time of btnStart_Click?
2) My controls are on my GUI, does that mean I need to invoke if I'm interacting with them?
3) I see many examples using static methods with this context. Why is this?
Thanks in advance. All criticism is welcome, feel free to be harsh!
BeginConnect returns immediately. Probably, no connection has been established yet when Send runs. Make sure that you use the connection only after having connected.
if (wifiClient.Connected) and what if !Connected? You just do nothing. That's not a valid error recovery strategy. Remove this if entirely.
In your read loop you destroy the previously read contents on each iteration. In fact, you can't split up an UTF8 encoded string at all and decode the parts separately. Read all bytes into some buffer and only when you have received everything, decode the bytes to a string.
wifiClient.Client.Dispose();
wifiClient.Close();
Superstitious dispose pattern. wifiClient.Dispose(); is the canonical way to release everything.
I didn't quite understand what "controls" you are talking about. A socket is not a control. UI controls are single-threaded. Only access them on the UI thread.
Do I need more TCP clients?
You need one for each connection.
Probably, you should use await for all blocking operations. There are wrapper libraries that make the socket APIs usable with await.

C# Strange Behaviour of Delegate Callbacks

I wrote a class, that should provide basic interaction with NodeJS server. This class also includes TcpClient instance and works asynchronously (methods like BeginRead, BeginWrite, ...) so many functions takes callbacks (anonymous function using lambda expr.) as an argument. Problem starts in this scenario (I try to illustrate on a peace of code similar to original).
this._nodeJS.Send("DATA_TO_SEND", (Response) => {
Console.WriteLine(Response);
// Section1
this._nodeJS.Send("ANOTHER_DATA", (Response1) => {
Console.WriteLine(Response1);
});
});
Problem occurs in Section1. When it's commented out, program behaves as expected. Response is received a written to Console. When it's not commented out, it starts to behave very strange. Write to Console in Section1 doesn't work (in many cases) and, what is important, code below Console.WriteLine in this section is not executed, the "thread" just stops right before command. I tried to debug it, step by step, variables in Section1 are correctly set, and when I get to the next command, debugging just stops. Is there anything wrong with this approach? Is there some things I need to be aware of?
For better imagination here is my example. I connect to the NodeJS server, when it's done, I send a request and wait for response containing data, that are processed and again sent to the NodeJS server in next request (Section1). NodeJS give me final response and program works ... Thanks for any advice!
Finally, I figured out, what's goin' on. I know, I din't show my original code and instead used some kind of pseudo-code, but if someone is interested to know, problem, probably, was causing wrong conversion of received data. I have buffer of size 1024 and StringBuilder variable where the data was appended. So when I received the data, converted it this way: Encoding.UTF8.GetString(state.Buffer) - this is wrong, instead, I had to use Encoding.UTF8.GetString(state.Buffer, 0, bytesRead). I don't know how, but this part of code was causing troubles and stopping callback to execute.
Without knowing your implementation details, I would suspect that the second _nodeJS.Send(... call is being blocked by the response from the first Send call.
At a guess, your code does something like this (made up pseudocode!):
void Send(String data, Action<Response> callback)
{
_socket.BeginSend(Magic(data), r => {
callback.Invoke(r.ResponseData);
_socket.EndSend(r.Result); //you cannot call _socket.Send() again until you have done this!
});
}
Due to order of operations, it should be doing this:
void Send(String data, Action<Response> callback)
{
_socket.BeginSend(Magic(data), r => {
_socket.EndSend(r.Result);
callback.Invoke(r.ResponseData);
});
}

Transactional receive with timeout

I have a method that reads a list of messages from a message queue. The signature is:
IList<TMsg> Read<TMsg>(MessageQueue queue, int timeout, MessageQueueTransaction tx);
The basic functionality is that it will reads as many messages as it can from the queue, within the timeout, using the given transaction. The problem I'm having is deciding on how best to enforce the timeout. I have two working versions at the moment. These are:
Using BeginPeek with a timeout. If it succeeds, the message is removed with a transactional Receive call. The timeout for BeginPeek is recalculated after each call, based on the time the Read began, and the current time.
Using Receive with the timeout value, and catching the exception when the timeout expires.
The problem with the first approach is that it requires the queue to be read in DenySharedReceive mode, otherwise you can't guarantee the message will still be there between the Peek and Receive. The problem with the second method is that an exception needs to be thrown and handled (albeit, internally and transparently) which is probably not a great design since each call will always end in an exception which goes against the idea of throwing exceptions only in exceptional circumstances.
Does anyone have any other suggestions how I might achieve this, or comments on these two techniques and my concerns?
You could use the reactive excensions to create a producer of messages, use Observable.Buffer to manage the timeout and later subscribe to this producer
public IEnumerable<Message> GetMessage()
{
//do the peek and receive a single message
yield return message;
}
//and then something like
var producer = GetMessage().ToObservable();
// this is where your timeout goes
var bufferedMessages = producer.Buffer(TimeSpan.FromSeconds(3));
var disp = bufferedMessages.Subscribe(messages =>
{
Console.WriteLine("You've got {0} new messages", messages.Count());
foreach (var message in messages)
Console.WriteLine("> {0}", message); // process messages here
});
disp.Dispose(); // when you no longer want to subscribe to the messages
For more reactive examples look here
After a bit of investigation, hatchet's comment is the closest to the 'answer', at least as far as .NET is concerned. The wrapped native methods provide a return value (rather than error value) for 'TIMEOUT', but this is considered an exception by .NET and re-wrapping the native code is just not worth it. I tried. :p

Proper way to asynchronously send an email in ASP.NET... (am i doing it right?)

When a user registers on my website, I don't see why I need to make him "wait" for the smtp to go through so that he gets an activation email.
I decided I want to launch this code asynchronously, and it's been an adventure.
Lets imagine I have a method, such as:
private void SendTheMail() { // Stuff }
My first though.. was threading. I did this:
Emailer mailer = new Emailer();
Thread emailThread = new Thread(() => mailer.SendTheMail());
emailThread.Start();
This works... until I decided to test it for error-handling capability. I purposely broke the SMTP server address in my web.config and tried it. The scary result was that IIS basically BARFED with an unhandled exception error on w3wp.exe (it was a windows error! how extreme...) ELMAH (my error logger) did NOT catch it AND IIS was restarted so anyone on the website had their session erased. Completely unacceptable result!
My next thought, was to do some research on Asynchronous delegates. This seems to work better because exceptions are being handled within the asynch delegate (unlike the thread example above). However, i'm concerned if i'm doing it wrong or maybe I'm causing memory leaks.
Here's what i'm doing:
Emailer mailer = new Emailer();
AsyncMethodCaller caller = new AsyncMethodCaller(mailer.SendMailInSeperateThread);
caller.BeginInvoke(message, email.EmailId, null, null);
// Never EndInvoke...
Am I doing this right?
There was a lot of good advice that I upvoted here... such as making sure to remember to use IDisposable (i totally didn't know). I also realized how important it is to manually catch errors when in another thread since there is no context -- I have been working on a theory that I should just let ELMAH handle everything. Also, further exploration made me realize I was forgetting to use IDisposable on mailmessage, too.
In response to Richard, although I see that the threading solution can work (as suggested in my first example) as long as i'm catching the errors... there's still something scary about the fact that IIS completely explodes if that error isn't caught. That tells me that ASP.NET/IIS never meant for you to do that... which is why i'm leaning towards continuing to use .BeginInvoke/delegates instead since that doesn't mess up IIS when something goes wrong and seems to be more popular in ASP.NET.
In response to ASawyer, I was totally surprised that there was a .SendAsync built into the SMTP client. I played with that solution for a while, but it doesn't seem to do the trick for me. Although I can skip through the client of code that does SendAsync, the page still "waits" until the SendCompleted event is done. My goal was to have the user and the page move forward while the email is getting sent in the background. I have a feeling that I might still be doing something wrong... so if someone comes by this they might want to try it themselves.
Here's my full solution for how I sent emails 100% asynchronously in addition with ELMAH.MVC error logging. I decided to go with an expanded version of example 2:
public void SendThat(MailMessage message)
{
AsyncMethodCaller caller = new AsyncMethodCaller(SendMailInSeperateThread);
AsyncCallback callbackHandler = new AsyncCallback(AsyncCallback);
caller.BeginInvoke(message, callbackHandler, null);
}
private delegate void AsyncMethodCaller(MailMessage message);
private void SendMailInSeperateThread(MailMessage message)
{
try
{
SmtpClient client = new SmtpClient();
client.Timeout = 20000; // 20 second timeout... why more?
client.Send(message);
client.Dispose();
message.Dispose();
// If you have a flag checking to see if an email was sent, set it here
// Pass more parameters in the delegate if you need to...
}
catch (Exception e)
{
// This is very necessary to catch errors since we are in
// a different context & thread
Elmah.ErrorLog.GetDefault(null).Log(new Error(e));
}
}
private void AsyncCallback(IAsyncResult ar)
{
try
{
AsyncResult result = (AsyncResult)ar;
AsyncMethodCaller caller = (AsyncMethodCaller)result.AsyncDelegate;
caller.EndInvoke(ar);
}
catch (Exception e)
{
Elmah.ErrorLog.GetDefault(null).Log(new Error(e));
Elmah.ErrorLog.GetDefault(null).Log(new Error(new Exception("Emailer - This hacky asynccallback thing is puking, serves you right.")));
}
}
As of .NET 4.5 SmtpClient implements async awaitable method
SendMailAsync.
As a result, to send email asynchronously is as the following:
public async Task SendEmail(string toEmailAddress, string emailSubject, string emailMessage)
{
var message = new MailMessage();
message.To.Add(toEmailAddress);
message.Subject = emailSubject;
message.Body = emailMessage;
using (var smtpClient = new SmtpClient())
{
await smtpClient.SendMailAsync(message);
}
}
If you are using .Net's SmtpClient and MailMessage classes, you should take note of a couple things. First, expect errors on the send, so trap and handle them. Second, in .Net 4 there were some changes to these classes, and both now implement IDisposable (MailMessage since 3.5, SmtpClient new in 4.0). Because of this, your creation of the SmtpClient and the MailMessage should be wrapped in using blocks or explicitly disposed. This is a breaking change some people are unaware of.
See this SO question for more info on disposing when using async sends:
What are best practices for using SmtpClient, SendAsync and Dispose under .NET 4.0
Are you using the .Net SmtpClient to send email? It can send asynch messages already.
Edit - If Emailer mailer = new Emailer(); is not a wrapper over SmtpClient, this won't be so useful I imagine.
Threading isn't the wrong option here, but if you don't handle an exception yourself, it will bubble up and crash your process. It doesn't matter which thread you do that on.
So instead of mailer.SendTheMail() try this:
new Thread(() => {
try
{
mailer.SendTheMail();
}
catch(Exception ex)
{
// Do something with the exception
}
});
Better yet, use the asynchronous capabilities of the SmtpClient if you can. You'll still need to handle exceptions though.
I would even suggest you have a look at .Net 4's new Parallet Task library. That has extra functionality which lets you handle exceptional cases and works well with ASP.Net's thread pool.
So, why not have a separate poller/service which deals exclusively with sending emails? Thus, allowing your registration post-back to execute in only the time it takes to write to the database/message queue and delaying the sending of the email til the next polling interval.
I'm pondering the same issue just now and I'm thinking that I really don't want to even initiate the email sending within the server post back request. The process behind serving the web pages should be interested in getting a response back to the user ASAP, the more work you try to do the slower it will be.
Have a look at the Command Query Segregation Principal (http://martinfowler.com/bliki/CQRS.html). Martin Fowler explains that different models can be used in the command part of an operation than are used in the query part. In this scenario the command would be "register user", the query would be the activation email, using the loose analogy. The pertinent quote would probably be:
By separate models we most commonly mean different object models, probably running in different logical processes
Also worth a read is the Wikipedia article on CQRS (http://en.wikipedia.org/wiki/Command%E2%80%93query_separation). An important point which this highlights is:
it is clearly intended as a programming guideline rather than a rule for good coding
Meaning, use it where your code, program execution and programmer understanding would benefit. This being a good example scenario.
This approach has the added benefit of negating all the mufti-threading concerns and the headaches all that can bring.
I worked same issue for my project:
First tried Thread as you do:
- I loose context
- Exception handling problem
- Commonly said, Thread are bad idea on IIS ThreadPool
So I switch and try with asynchronously:
- 'asynchronously' is fake in a asp.net web application. It just put queue calls and swicth the context
So I make windows service and retrive the values through sql table: happy end
So for quick solution: from ajax side make async call tell the user fake yes, but continue your sending job in your mvc controller
Use this way-
private void email(object parameters)
{
Array arrayParameters = new object[2];
arrayParameters = (Array)parameters;
string Email = (string)arrayParameters.GetValue(0);
string subjectEmail = (string)arrayParameters.GetValue(1);
if (Email != "Email#email.com")
{
OnlineSearch OnlineResult = new OnlineSearch();
try
{
StringBuilder str = new StringBuilder();
MailMessage mailMessage = new MailMessage();
//here we set the address
mailMessage.From = fromAddress;
mailMessage.To.Add(Email);//here you can add multiple emailid
mailMessage.Subject = "";
//here we set add bcc address
//mailMessage.Bcc.Add(new MailAddress("bcc#site.com"));
str.Append("<html>");
str.Append("<body>");
str.Append("<table width=720 border=0 align=left cellpadding=0 cellspacing=5>");
str.Append("</table>");
str.Append("</body>");
str.Append("</html>");
//To determine email body is html or not
mailMessage.IsBodyHtml = true;
mailMessage.Body = str.ToString();
//file attachment for this e-mail message.
Attachment attach = new Attachment();
mailMessage.Attachments.Add(attach);
mailClient.Send(mailMessage);
}
}
protected void btnEmail_Click(object sender, ImageClickEventArgs e)
{
try
{
string To = txtEmailTo.Text.Trim();
string[] parameters = new string[2];
parameters[0] = To;
parameters[1] = PropCase(ViewState["StockStatusSub"].ToString());
Thread SendingThreads = new Thread(email);
SendingThreads.Start(parameters);
lblEmail.Visible = true;
lblEmail.Text = "Email Send Successfully ";
}
If you want to detect leaks, then you need to use a profiler like this one:
http://memprofiler.com/
I don't see anything wrong with your solution, but can almost guarantee you that this question will be closed as subjective.
One other option is to use jQuery to make an ajax call to the server and spark the e-mail flow. That way, the UI is not locked up.
Good luck!
Matt

Categories