Im trying to read receiving email from gmail and I did it.
If emails receive one by one it works perfectly.But if emails receive three or four at the same time.I miss at least two of them.
I hope describe my issue properly.
Here is my code for reading;
private void StartReceiving()
{
Task.Run(() =>
{
using (ImapClient client = new ImapClient("imap.gmail.com", 993, txtEmail.Text, txtSifre.Text, AuthMethod.Login, true))
{
if (client.Supports("IDLE") == false)
{
MessageBox.Show("server crash");
return;
}
client.NewMessage += new EventHandler<IdleMessageEventArgs>(OnNewMessage);
while (true) ;
}
});
}
static void OnNewMessage(object sender,IdleMessageEventArgs e)
{
//MessageBox.Show("mesaj geldi");
MailMessage m = e.Client.GetMessage(e.MessageUID, FetchOptions.Normal);
f.Invoke((MethodInvoker)delegate
{
f.txtGelen.AppendText("Body: " + m.Body + "\n");
});
}
What should I do ? Im kinda newbie at this,i have to read at least 4 emails at same time.
I never worked with gmail, but I had a similar problem when I was reading a TCP/IP log file, and it kept sending messages while I was processing.
The way I resolved it was to use a LIST of strings, and then process it in a background worker. Changing a string in place could be an issue in a race situation.
This is cut and pasted out of my code, and modified without checking my syntax, but it goes something like this:
private System.ComponentModel.BackgroundWorker backgroundWorkerReadMail;
private List<string> messagesToBeRead = null;
/****************************************************************
* readPassedMessage(string str)
* Puts message in queue, and calls background worker
****************************************************************/
private void readPassedMessage(string str)
{
string stringToRead = str;
if (messagesToBeRead == null) messagesToBeRead = new List<string>();
messagesToBeRead.Add(stringToRead);
if (backgroundWorkerReadMail != null && backgroundWorkerReadMail.IsBusy == false)
{
backgroundWorkerReadMail.RunWorkerAsync();
}
else if (backgroundWorkerReadMail == null)
{
// need to create it
}
}
private void backgroundWorkerReadMail_DoWork(object passedObj, DoWorkEventArgs e)
{
if (messagesToBeRead == null || messagesToBeRead.Count == 0) return;
if (backgroundWorkerReadMail.CancellationPending)
{
messagesToBeRead.Clear();
e.Cancel = true;
}
else
{
bool messagesLeftToRead = true;
while (messagesLeftToRead)
{
string curString = messagesToBeRead[0];
// < ADD CODE HERE TO DO WHATEVER YOU WANT WITH YOUR MESSAGE > //
messagesToBeRead.RemoveAt(0);
if (messagesToBeRead.Count == 0 || backgroundWorkerVoiceAssist.CancellationPending)
break;
} // while (messagesLeftToRead) end brace
}
}
Related
I have an async function which still freezes / lags the UI thread for me when I execute it. This is my function calling it.
private void TcpListenerLogic(object sender, string e)
{
Application.Current.Dispatcher.BeginInvoke((Action)async delegate {
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
// Get properties for new anchor
string testInformation = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + results.test_id);
}
}
catch (Exception exception)
{
// Writing some Trace.WriteLine()'s
}
});
}
And this is the async function that freezes my UI Thread
public static async Task<string> getJsonFromURL(string url)
{
try
{
string returnString = null;
using (System.Net.WebClient client = new System.Net.WebClient())
{
returnString = await client.DownloadStringTaskAsync(url);
}
return returnString;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return null;
}
}
I already tried to make everything in TcpListenerLogic run in a new Thread:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
}).Start();
Which resulted in the whole UI completely freezing. And I tried to make TcpListenerLogic async and await the dispatcher, which also made everything freeze permanently. I also tried to make TcpListenerLogic async and leave the dispatcher. The dispatcher is only there because I normally have some UI code in there, which I left out for my tests.
I have ventured far through the internet, but no BackgroundWorker, ThreadPool or other methods helped me in my endeavour.
If anyone has help for this particular problem, or a resource that would improve my understanding of async functions in C#, I would much appreciate it.
Edit
As requested a deeper insight in how this event handler is called.
I have System.Net.Websocket, which is connected to the Backend API I am working with and triggers an event, everytime he receives new Data. To guarantee the socket listens as longs as it is open, there is a while loop which checks for the client state:
public event EventHandler<string> TcpReceived;
public async void StartListener(string ip, int port, string path)
{
try
{
using (client = new ClientWebSocket())
{
try
{ // Connect to backend
Uri serverUri = new Uri("ws://" + ip + ":" + port.ToString() + path );
await client.ConnectAsync(serverUri, CancellationToken.None);
}
catch (Exception ex)
{
BackendSettings.IsConnected = false;
Debug.WriteLine("Error connecting TCP Socket: " + ex.ToString());
}
state = client.State;
// Grab packages send in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
try
{
// **Just formatting the received data until here and writing it into the "message" variable**//
TcpReceived(this, message);
// Close connection on command
if (result.MessageType == WebSocketMessageType.Close)
{
Debug.WriteLine("Closing TCP Socket.");
shouldstayclosed = true;
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
break;
}
state = client.State;
}
catch
{
BackendSettings.IsConnected = false;
state = client.State;
}
}
state = client.State;
}
}
catch (Exception ex)
{
// Some error messages and settings handling
}
}
The Event has a handler attached:
TcpReceived += TcpListener_TcpReceived;
And this is the Handler, which calls the previously seen "TcpListenereLogic".
private void TcpListener_TcpReceived(object sender, string e)
{
TcpListenerLogic(sender, e);
//App.Current.Dispatcher.BeginInvoke(new Action(() => {
// TcpListenerLogic(sender, e);
//}));
//new Thread(() =>
//{
// Thread.CurrentThread.IsBackground = true;
// TcpListenerLogic(sender, e);
//}).Start();
}
I previously had the "TcpListenereLogic" as the handler, but I wanted to try different methods to call it. I also left in the commented out part, to show how the call of "TcpListenereLogic" looked already. All my attempts were with all mentioned setups and sadly lead to nothing.
Thank you very much #TheodorZoulias for helping me to find the solution to my problem.
It turns out it wasn't the async function itself, but rather how often it gets called. It got called roughly ~120 times every second.
My solution starts by calling the Listener method over a new Thread:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
MainWindow.tcpListener.StartListener(ip, portNumber, "/api/");
}).Start();
To limit the amount of calls that happen every second I added a dispatcher timer, that resets a bool after it has been used for a call, by my Event.
readonly System.Windows.Threading.DispatcherTimer packageIntervallTimer =
new System.Windows.Threading.DispatcherTimer();
bool readyForNewPackage = true;
private void ReadyForPackage(object sender, EventArgs e)
{
readyForNewPackage = true;
}
public async void StartListener(string ip, int port, string path)
{
packageIntervallTimer.Interval = TimeSpan.FromMilliseconds(50);
packageIntervallTimer.Tick += (s, e) => { Task.Run(() => ReadyForPackage(s, e)); };
packageIntervallTimer.Start();
Then I wrapped everything inside the while loop into an if condition based on the bool, the most important part was to have my "event EventHandler TcpReceived" in there:
// Grab packages sent in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
if (readyForNewPackage == true)
{
readyForNewPackage = false;
try
{
....
TcpReceived(this, message);
....
}
catch
{
...
}
}
}
I added my TcpListenerLogic to the Eventhandler:
TcpReceived += TcpListenerLogic;
And my TcpListenerLogic now looked like this (names have been changed):
private async void TcpListenerLogic(object sender, string e)
{
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
string testID = "";
if (results.test_id is JValue jValueTestId)
{
testID = jValueTestId.Value.ToString();
}
else if (results.test_id is string)
{
testID = results.test_id;
}
// Get properties for new object
string information = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + testID );
if (information != null)
{
await App.Current.Dispatcher.BeginInvoke(new Action(() =>
{
// Create object out of the json string
TestStatus testStatus = new TestStatus();
testStatus.Deserialize(information);
if (CommunicationCommands.isNameAlreadyInCollection(testStatus.name) == false)
{
// Add new object to the list
CommunicationCommands.allFoundTests.Add(testStatus);
}
}));
{
}
catch (Exception exception)
{
....
}
}
Adding a new Thread to execute any step results in problems, so keep in mind that all this uses the thread created at the beginning for "StartListener"
I have WPF desktop application, witch contains mail link. If you click on the link, the default mail client opens. But if the machine does not have a configured e-mail client, the program crashes with a critical exception
System.NullReferenceException: The object reference does not point to an instance of the object.
at Nvx.ReDoc.DesktopUi.View.Tray.Sections.About.AboutWindow.OnRequestNavigate(Object sender, RequestNavigateEventArgs e)
<Other:ReDocHyperlinkLite NavigateUri="mailto:mail#mail.com?subject=sampleText" RequestNavigate="OnRequestNavigate">
<Run Text="mail#mail.com"/></Other:ReDocHyperlinkLite>
OnRequestNavigate implementation is
private void OnRequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
How to check if there is an installed mail client on the computer, and catch an exception?
You can check whether an application is registered to handle the mailto URI scheme (and additionally check if the given application really exists):
private bool IsSchemeRegistered(string scheme)
{
using (var schemeKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(scheme))
{
if (schemeKey == null)
return false;
if (schemeKey.GetValue("") == null || !schemeKey.GetValue("").ToString().StartsWith("URL:"))
return false;
using (var shellKey = schemeKey.OpenSubKey("shell"))
{
if (shellKey == null)
return false;
using (var openKey = shellKey.OpenSubKey("open"))
{
if (openKey == null)
return false;
using (var commandKey = openKey.OpenSubKey("command"))
{
if (commandKey == null)
return false;
var command = commandKey.GetValue("") as string;
if (string.IsNullOrEmpty(command) || !File.Exists(command.Split(new[] { '"' }, StringSplitOptions.RemoveEmptyEntries).First()))
return false;
}
}
}
}
return true;
}
This method be called like this:
if ( !IsSchemeRegistered("mailto") )
{
MessageBox.Show("No mail client installed/configured");
}
else
{
//...
}
I tested this code with placing a breakpoint in Monodevelop, running on a Raspbian. This app needs to communicate with a Windows, with a C# console application.
Although the timer1_Tick method prints the incoming message everytime (and it clearly prints the new message, because there I clear the message variable everytime after an incoming message), it seems to be that the OnNewData doesn't run everytime, when there's an incoming message.
I ask new incoming message with sending the "mes" out in the timer1_Tick.
I don't process the other kind of incoming messages in that method, but for the response for "mes", this place would be the best for processing. The reason is the "mes" creates answer types ("", " type answers), what I can get anytime.
I don't know what is the problem. Any idea? How could this happen, if the textbox is being refreshed nicely after each new incoming message?
public partial class Form0 : Form
{
public static string ReadCharactersIntoString(){
char c='c';
string outputString=String.Empty;
do{
c=(char)streamReader.Read();
outputString=outputString+c;
}while(c!='>');
return outputString;
}
async void OnNewData(object sender, EventArgs e){
message = Form0.ReadCharactersIntoString ();
//work with message variable works unreliable...
//sometimes this method runs, when there's an incoming message, sometimes it's not...
//although tick method prints the message everytime...
//why? how to solve this?
reseter.Set ();
}
public void AcceptMessages(){
while (true) {
try{
if (streamReader!=null && streamReader.Peek () > 0) {
newIncomingDataEvent.Invoke(this,EventArgs.Empty);
reseter.WaitOne ();
}
}catch{
}
}
}
public static async Task Waiting(){
while (message == null || message[message.Length-1]!='>') {
}
}
public static async Task<string> CollectingAnswer(){
await Waiting();
return message;
//when the answer is completely collected, it gives me back
}
public void ConnectionEstablisher()
{
while (true)
{
if (!activeConnection)
{
try
{
socketForServer = new TcpClient(ip, port);
networkStream = socketForServer.GetStream();
streamReader = new System.IO.StreamReader(networkStream);
streamWriter = new System.IO.StreamWriter(networkStream);
streamReader.BaseStream.ReadTimeout = 5000;
streamWriter.BaseStream.ReadTimeout = 5000;
activeConnection = true;
newIncomingDataEvent+=OnNewData;
reseter = new ManualResetEvent (true);
}
catch(Exception e)
{
activeConnection = false;
}
}
}
}
private async void timer1_Tick(object sender, EventArgs e)
{
if (this.Visible && activeConnection)
{
try
{
streamWriter.Write("mes");
streamWriter.Flush();
textBoxSending.AppendText("mes" + Environment.NewLine);
collectAnswer=CollectingAnswer();
outputString=await collectAnswer;
message=null;
textBoxAccepting.AppendText(outputString + Environment.NewLine);
//this always prints the incoming response message...
i have an application that sends email by receiving a text message. I realized at the point of this code smt.Send(mailMsg); my UI freezes until sending process is done, this sometimes takes 2-5 min and i don't want the user to think the application has crashed or is malfunctioning. therefore i would like to know how to run that method in a backgroundworker to avoid freezing my UI. below is relevant code thank you.
Report generating/exporting method
private void Q4report()
{
Control.CheckForIllegalCrossThreadCalls = false;
Output("Processing request...");
ReportDocument cryRpt1 = new ReportDocument();
cryRpt1.Load("cryQ2.rpt");
crystalReportViewer2.ReportSource = cryRpt1;
crystalReportViewer2.Refresh();
cryRpt1.ExportToDisk(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat, "QueryReport.pdf");
Output("Generating report...");
Output("Report Process Completed");
if (i != 1)
{
sendMail("QueryReport.pdf", "4POS StockItem/per price list Query Report");
}
else if( i == 1)
{
Unsent_Request_sendMail("QueryReport.pdf", "4POS StockItem/per price list Query Report");
}
}
Email sending method
public bool sendMail(string pdf, string subject)
{
bool flag = false;
MailMessage mailMsg = new MailMessage();
try
{
// To
mailMsg.From = new MailAddress(radtxtEmail.Text);
if (sub3 != null)
{
string strSubject = subject;
string strBody = "Kindly find attached your query report.";
mailMsg.To.Add(sub3);
mailMsg.Subject = strSubject;
mailMsg.Body = strBody;
Attachment attachment = new Attachment(pdf);
mailMsg.Attachments.Add(attachment);
mailMsg.IsBodyHtml = true;
using (SmtpClient smt = new SmtpClient("smtp.gmail.com"))
{
smt.Port = 587;
smt.Credentials = new System.Net.NetworkCredential(radtxtEmail.Text, radtxtboxPassword.Text);
smt.EnableSsl = true;
bool connection = NetworkInterface.GetIsNetworkAvailable();
bool IsOnline = ModemManager.netCheck.IsOnline();
if (connection == true)
{
if (IsOnline == true)
{
smt.Send(mailMsg);
sent_insert();
mailMsg.Dispose();
attachment.Dispose();
Output("Report Mail successfully sent!");
}
else
{
Output("Internet Access Unavailable.");
Output("Mail process terminated.");
Unsent_insert();
mailMsg.Dispose();
attachment.Dispose();
// btnSendMessage_Click();
return false;
}
}
else
{
Output("Network Connectivity Unavailable.");
Unsent_insert();
mailMsg.Dispose();
attachment.Dispose();
// btnSendMessage_Click();
return false;
}
}
flag = true;
}
}
catch (Exception ex)
{
Output(ex.Message);
}
return flag;
}
You can encapsulate the sendMail method in a Task.Run block, which will start the method on a separate thread:
if (i != 1)
{
Task.Run(() => sendMail("QueryReport.pdf", "4POS StockItem/per price list Query Report"));
}
Note that unless you save the created task, you'll have no way to monitor the status of the task for completion or cancel it if needed. If this is for a UI, I'd capture the created task as part of the parent classes state:
private Task sendMailTask;
Then attach the task created from Task.Run so you have a way to get back to the generated task if you need to:
if (i != 1)
{
this.sendMailTask = Task.Run(() => sendMail("QueryReport.pdf", "4POS StockItem/per price list Query Report"));
}
Alternatively, if this is being triggered as a result of a button click for example, you can await it in an async void method:
private async void button2_Click(object sender, EventArgs e)
{
// ...
if (i != 1)
{
await Task.Run(() => sendMail("QueryReport.pdf", "4POS StockItem/per price list Query Report"));
}
// ...
}
Which will still return control to the UI and run the work for sending mail in the background.
Use BackgroundWorker to prevent freeze
void device_DeviceArrived(ProximityDevice sender)
{
//Compatible Device enters area
if (stance == WriteStage.PREP)
{
System.Diagnostics.Debug.WriteLine("Writestages won");
//Perhaps here
updateStatusRectangle(Colors.Yellow);
stance = WriteStage.WRITING;
updateStatusText("Writing...");
writeToTag(msg);
}
else
{
updateReceivedText("Device connected!");
}
}
private void MessageReceivedHandler(ProximityDevice sender, ProximityMessage message)
{
System.Diagnostics.Debug.WriteLine("Handler ran");
var rawMsg = message.Data.ToArray();
var ndefMessage = NdefMessage.FromByteArray(rawMsg);
foreach (NdefRecord record in ndefMessage)
{
System.Diagnostics.Debug.WriteLine("Record type: " + Encoding.UTF8.GetString(record.Type, 0, record.Type.Length));
var specType = record.CheckSpecializedType(false);
if (specType == typeof(NdefTextRecord))
{
var textrec = new NdefTextRecord(record);
updateReceivedText(textrec.Text);
}
}
}
The above event and handler are executed when the phone comes into contact with an NFC device. For intents and purposes in this app, I need to ensure that before writing to a card, if it already has content, it will prompt the user to verify overwriting the data. I commented where I think it should go, but as far as checking for the Message, I'm not sure how to go about it. I can't call the handler without the ProximityMessage, and I don't know of another way to view the message.
The Question: Is it possible to call the MessageReceivedHandler (or check the message at all), from device_DeviceArrived?
(Note: Debug.Writelines are for test purposes, and this is just a quick NFC writer I'm throwing together).
UPDATE: In attempting to find a work around, I ran into a different problem.
public bool promptUserForOverwrite()
{
bool response = false;
Dispatcher.BeginInvoke(() =>
{
MessageBoxResult cc = MessageBox.Show("You are about to overwrite data. Proceed?", "Overwrite?", MessageBoxButton.OKCancel);
if (cc == MessageBoxResult.OK)
{
System.Diagnostics.Debug.WriteLine("MessageBox OK result");
response = true;
}
});
return response;
}
private void MessageReceivedHandler(ProximityDevice sender, ProximityMessage message)
{
System.Diagnostics.Debug.WriteLine("Handler ran");
var rawMsg = message.Data.ToArray();
var ndefMessage = NdefMessage.FromByteArray(rawMsg);
foreach (NdefRecord record in ndefMessage)
{
System.Diagnostics.Debug.WriteLine("Record type: " + Encoding.UTF8.GetString(record.Type, 0, record.Type.Length));
var specType = record.CheckSpecializedType(false);
if (specType == typeof(NdefTextRecord))
{
var textrec = new NdefTextRecord(record);
updateReceivedText(textrec.Text);
}
}
bool pow = promptUserForOverwrite();
if (!pow)
{
System.Diagnostics.Debug.WriteLine("Prompt returned");
//This always hits - pow is always false.
}
if (stance == WriteStage.WRITING && pow)
{
//writeToTag(msg);
}
}
This would work as a work around; the problem is the beginInvoke method. I need it for cross thread access, but used like this seems to make it run at a later time (when the thread is free?). The bool pow is always false, even after I click ok on the messagebox (debugged, and it does get the result, but after I can no longer use it). Is there an alternative that I can use for the Dispatcher?
Ugly, but I have this working. You need to get a TaskScheduler from the UI thread, so declare a
private TaskScheduler sched;
and then on the OnLoaded event for the page
sched = TaskScheduler.FromCurrentSynchronizationContext();
Then your methods
public async Task<bool> promptUserForOverwrite()
{
return false;
}
private async void MessageReceivedHandler(ProximityDevice sender, ProximityMessage message)
{
System.Diagnostics.Debug.WriteLine("Handler ran");
var rawMsg = message.Data.ToArray();
var ndefMessage = NdefMessage.FromByteArray(rawMsg);
foreach (NdefRecord record in ndefMessage)
{
System.Diagnostics.Debug.WriteLine("Record type: " + Encoding.UTF8.GetString(record.Type, 0, record.Type.Length));
var specType = record.CheckSpecializedType(false);
if (specType == typeof(NdefTextRecord))
{
var textrec = new NdefTextRecord(record);
updateReceivedText(textrec.Text);
}
}
var task = promptUserForOverwrite();
var pow = await task.ContinueWith(t =>
{
MessageBoxResult cc = MessageBox.Show("You are about to overwrite data. Proceed?", "Overwrite?", MessageBoxButton.OKCancel);
if (cc == MessageBoxResult.OK)
{
System.Diagnostics.Debug.WriteLine("MessageBox OK result");
return true;
}
else
{
return false;
}
}, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, sched);
if (!pow)
{
System.Diagnostics.Debug.WriteLine("Prompt returned");
//This always hits - pow is always false.
}
if (stance == WriteStage.WRITING && pow)
{
//writeToTag(msg);
}
}