I'm using C# for Visual studio, and i wanted to send an Email through my app, but i always get an error
here's my code
Button button = FindViewById<Button>(Resource.Id.myButton);
button.Click += delegate
{
var email = new Intent(Android.Content.Intent.ActionSend);
email.PutExtra(Android.Content.Intent.ExtraEmail, new string[] { "person1#gmail.com", "person2#gmail.com" });
email.PutExtra(Android.Content.Intent.ExtraCc, new string[] { "person3#gmail.com" });
email.PutExtra(Android.Content.Intent.ExtraSubject, "Hello Email");
email.PutExtra(Android.Content.Intent.ExtraText, "Hello user");
email.SetType("message/rfc822");
StartActivity(email);
};
and i always get this error
Android.Content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.SEND typ=message/rfc822 flg=0x1 (has clip) (has extras) }
can someone help me?
I means that it can't find an activity to handle the action SEND.
Are you running this on code in a simulator? Try it on a physical device (make sure it has a mail client installed).
Also, I would surround your code in a try/catch block, to avoid crashing if there's no activity available to handle your intent.
** Update **
Here's an example. Put the try/catch block inside your delegate.
try
{
var email = new Intent(Android.Content.Intent.ActionSend);
email.PutExtra(Android.Content.Intent.ExtraEmail, new string[] { "person1#gmail.com", "person2#gmail.com" });
email.PutExtra(Android.Content.Intent.ExtraCc, new string[] { "person3#gmail.com" });
email.PutExtra(Android.Content.Intent.ExtraSubject, "Hello Email");
email.PutExtra(Android.Content.Intent.ExtraText, "Hello user");
email.SetType("message/rfc822");
StartActivity(email);
}
catch (Exception ex)
{
// Either ignore or log the error.
}
Related
I've encountered a few dificulties trying to handle some errors in the best way possible. One of my cases for example is NullReferenceException.
To be more clear let me explain it in a few words. When I make a call to a server to receive some pieces of information, in some cases the server might have some problems and it will return of course null.
What I've done is I display an alert to let the user know that he can try later again. After this I try to send him in the previous page for example. And after all this my app still crushes.
What I'd like to do is to simply display the alert and then let the user stay in the same page without the application crushing.
These are a few pieces of my code:
tasks.cs
public async Task<List<Idea>> GetIdeaAsync(string accesToken)
{
List<Idea> ideas = null;
try
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accesToken);
var json = await client.GetStringAsync("http://www.getdata.de/api/ideas/");
var ideas = JsonConvert.DeserializeObject<List<Idea>>(json);
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Server Error", "There has been an server error. Please try later.", "OK");
if (ideas == null)
{
await Application.Current.MainPage.Navigation.PopAsync(); //actually I would like to stay in the same page
}
}
return ideas;
}
view.xaml.cs
private async void Button_Clicked(object sender, EventArgs e)
{
Tasks ts = new Tasks();
var ideas = await ts.GetIdeasAsync();
if (ideas == null)
{
Debug.WriteLine("hello");
//do nothing since the display alert is already shown
}
else
{
//code here
}
I would really appreciate if anyone can guide me to a "best-practice" approach. Thanks :)
You are declaring ideas in the try block, and then trying to access it in the catch block, where it is out of scope. (Visual Studio should give an Intellisense error)
Also, whenever manipulating the UI, you should always do it on the main thread. so move your DisplayAlert() code into
Device.BeginInvokeOnMainThread(async () =>
{
// await DisplayAlert(); move it into here
});
In addition, any PopAsync or PushAsync calls should also be done on the main UI thread. But calling PopAsync after an asynchronous call to an API not be a good idea, as the user may have already pressed the back button by the time the call returns.
As for the NullReferenceException, check to see if json is null before passing it to the DeserializeObject() function.
The problem it was pretty obvious actually since I after catch-ing the exception I would later continue with the code. So what I did was :
public async Task<List<Idea>> GetIdeaAsync(string accesToken)
{
List<Idea> ideas = null;
try
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accesToken);
var json = await client.GetStringAsync("http://www.getdata.de/api/ideas/");
var ideas = JsonConvert.DeserializeObject<List<Idea>>(json);
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Server Error", "There has been an server error. Please try later.", "OK");
if (ideas == null)
{
//actually I would like to stay in the same page
return null; //-- added this line
}
}
return ideas;
}
Maybe it's not the best idea but it's working for me. Any other approach would be highly appreciated. :)
I am having a issue accesing a text box in a view controller .cs file
async partial void loginUser(UIButton sender)
{
// Show the progressBar as the MainActivity is being loade
Console.WriteLine("Entered email : " + txtEmail.Text);
// Create user object from entered email
mCurrentUser = mJsonHandler.DeserialiseUser(txtEmail.Text);
try
{
Console.WriteLine("Starting network check");
// Calls email check to see if a registered email address has been entered
if (EmailCheck(txtEmail.Text) == true)
{
await CheckPassword();
}
else
{
UIAlertView alert = new UIAlertView()
{
Title = "Login Alert",
Message = "Incorrect email or password entered"
};
alert.AddButton("OK");
alert.Show();
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("An error has occured: '{0}'", ex);
}
It is within this funciton that it complains it cannot access a text box which is on a aynsc method
public Task CheckPassword()
{
return Task.Run(() =>
{
// Creates instance of password hash to compare plain text and encrypted passwords.
PasswordHash hash = new PasswordHash();
// Checks password with registered user password to confirm access to account.
if (hash.ValidatePassword(txtPassword.Text ,mCurrentUser.password)==true)
{
Console.WriteLine("Password correct");
UIAlertView alert = new UIAlertView()
{
Title = "Login Alert",
Message = "Password Correct Loggin In"
};
alert.AddButton("OK");
alert.Show();
//insert intent call to successful login here.
}
else
{
UIAlertView alert = new UIAlertView()
{
Title = "Login Alert",
Message = "Incorrect email or password entered"
};
alert.AddButton("OK");
alert.Show();
}
Console.WriteLine("Finished check password");
});
}
Its this line the error occurs:
txtPassword.Text
The error is as follows:
UIKit.UIKitThreadAccessException: UIKit Consistency error: you are
calling a UIKit method that can only be invoked from the UI thread.
Also my Password Correct does not show even though if it is a correct password.
Do i have to run the UI Alerts on a seperate thread?
Any UIKit methods must be called from the UI thread (or Main thread, Main queue, etc.). This ensures consistency in the UI. Xamarin adds a check to all UIKit methods in debug mode and throws that exception if you try to use a background thread to change the UI.
The solution is simple: only modify the UI from the UI thread. That essentially means if you're using a class with "UI" in front it, you should probably do it from the UI thread. (That's a rule of thumb and there are other times to be on the UI thread).
How do I get my code on this mythical UI thread? I'm glad you asked. In iOS, you have a few options:
When in a subclass of NSObject, InvokeOnMainThread will do the trick.
From anywhere, CoreFoundation.DispatchQueue.MainQueue.DispatchAsync will always work.
Both of those methods just accept an Action, which can be a lambda or a method.
So in your code, if we add an InvokeOnMainThread (because I think this is in your UIViewController subclass)...
public Task CheckPassword()
{
return Task.Run(() =>
{
// Creates instance of password hash to compare plain text and encrypted passwords.
PasswordHash hash = new PasswordHash();
// Checks password with registered user password to confirm access to account.
InvokeOnMainThread(() => {
if (hash.ValidatePassword(txtPassword.Text ,mCurrentUser.password)==true)
{
Console.WriteLine("Password correct");
UIAlertView alert = new UIAlertView()
{
Title = "Login Alert",
Message = "Password Correct Loggin In"
};
alert.AddButton("OK");
alert.Show();
//insert intent call to successful login here.
}
else
{
UIAlertView alert = new UIAlertView()
{
Title = "Login Alert",
Message = "Incorrect email or password entered"
};
alert.AddButton("OK");
alert.Show();
}
});
Console.WriteLine("Finished check password");
});
}
Maybe this helps someone. So I will add what solve my issue, that was the same of rogue.
Follow the code that avoid this error of consistency in xamarin forms when used in iOS
await Task.Run(async () =>
{
await Device.InvokeOnMainThreadAsync(async () =>
{
await MaterialDialog.Instance.SnackbarAsync(message: "Bla bla bla",
msDuration: MaterialSnackbar.DurationShort).ConfigureAwait(false);
}).ConfigureAwait(false);
}).ConfigureAwait(false);
My Xamarin Android app utilizes a Web service, which it connects to using HttpClient. On no connection (for exmaple when the user has no cell nor WiFi connection), an excpetion is thrown. I'm using async/await to get the data from the server. Here is an excerpt from my code:
public async Task<String> doLogin(string username, string password)
{
String url = Constants.loginEndpoint + username + "/" + password + "/";
var uri = new Uri(string.Format(url, string.Empty));
return_string = "";
try
{
var response = await GetAsync(uri);
if (response.IsSuccessStatusCode)
{
return_string = "success";
// Process the positive response here
else
{ }
}
catch (Exception ex)
{
throw new ConnectionException();
}
return return_string;
}
I defined a custon ConnectionException and want to show an AlertDialog to the user to inform them, that the request failed due to no connection. After the user clicks OK I want to close the app. I tried to show the alert dialog in the following way, but it's not working:
public class ConnectionException : Exception
{
public ConnectionException()
{
AlertDialog.Builder alert = new AlertDialog.Builder(myApp.Context);
alert.SetTitle("Failure");
alert.SetMessage("Request failed. No connection.");
alert.SetPositiveButton("OK", (senderAlert, args) =>
{
});
Dialog dialog = alert.Create();
dialog.Show();
}
public ConnectionException(string message)
: base(message)
{ }
public ConnectionException(string message, Exception innerException)
: base(message, innerException)
{ }
}
Is this the right approach? Probably not, as it's not working. I would appreciate any help on how to achieve this. Also, I've not given it too much thought, but is this a preferred way to handle such exceptions?
Assuming that your myApp.Context is an Activity and it has no back stack, you can just call Finish()
var context = myApp.Context; // this needs to be an Activity-based context...
context.RunOnUiThread(() =>
{
var alertDialog = new AlertDialog.Builder(context)
.SetTitle("Failure")
.SetMessage("Request failed. No connection.")
.SetPositiveButton("OK", (senderAlert, args) =>
{
context.Finish();
})
.Create();
alertDialog.Show();
});
Are you reusing this exception in several places, or is this a one off?
If your only using this exception once, there is no real reason to build your own.
You may as well just capture the exception and post your alert from inside your catch.
I know that's not as pretty of a way to write the catch, but if it works why not use it.
Side note:
DisplayAlert may be easier for you as well. It'll be a one liner.
Example:
await DisplayAlert("Failure","Request failed. No connection.", "Ok");
The way you are handling possible errors contains multiple issues and is not the right approach for several reasons.
First: Your code doesn't follow C-Sharp conventions and contains several code-smells. I show you a better and more accepted style.
1) Methods in C# normally starts with an uppercase letter. doLogin becomes Login
2) To create a new Uri instance you do not need to format your url-string. The string.Empty won't be used. So the code can be simplified into await GetAsync(new Uri(...));
3) The return_string seems not to be used in any way outside the method. It is string.Empty or "success". Why not switch it to bool? That way you can easily check if the login was successful. The return-type becomes bool instead of string.
The method looks now like this:
public async Task<bool> Login(string username, string password)
{
//TODO: Do parameter check for username and password
try
{
var response = await GetAsync(new Uri(Constants.loginEndpoint + username + "/" + password + "/"));
if (response.IsSuccessStatusCode)
{
// Process the positive response here
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
throw new ConnectionException();
}
return false;
}
Second, as mentioned by #Jason, an exception should not contain any UI or business logic. Consider the following, which will break your current implementation.
public async Task<bool> Login(string username, string password)
{
var connectionEx = new ConnectionException();
try
{
...
}
catch (Exception ex)
{
throw connectionEx;
}
...
}
Now your user will see the exception even so there wasn't any.
The last thing is that I recommend not to catch the exception just to throw your custom exception. The reason is, that there might be other things that raise an exception too. For example something is null in the positive response handling.
Depending on how the Login method is used, for example directly in an Android Activity, I would do something like that:
public async Task Login(string username, string password)
{
//TODO: Do parameter check for username and password
try
{
var response = await GetAsync(new Uri(Constants.loginEndpoint + username + "/" + password + "/"));
if (response.IsSuccessStatusCode)
{
// Process the positive response here
}
else
{
var alertDialog = new AlertDialog.Builder(context)
.SetTitle("Failure")
.SetMessage("Request failed.")
.SetPositiveButton("OK", (senderAlert, args) =>
{
Finish();
})
.Create();
alertDialog.Show();
}
}
catch (Exception ex)
{
var alertDialog = new AlertDialog.Builder(context)
.SetTitle("Failure")
.SetMessage("Something went wrong (" + ex.Message +")")
.SetPositiveButton("OK", (senderAlert, args) =>
{
Finish();
})
.Create();
alertDialog.Show();
}
}
I am having an issue using the SendMailAsync When I change it out for a normal Send it works fine. When I use SendMailAsync I get a connection has timed out and no mail is sent. Am I setting it up the wrong way?
edit:
1. I changed the variable name!!!
2.The exact error happens here await smtpClient.SendMailAsync(mailMessage); It just hangs until the connection times out, and I get an error description of "Connection has timed out" The status code returned is General Error
I'm calling the sendEmail from form the onClick event of a button for now. await unitOfWork.Instance.SendEmail(...) It's a single line of code in the onclick event
public async Task SendEmail(List<string> notificationList, string emailSubject, string emailMessage)
{
var message = new MailMessage()
{
IsBodyHtml = true,
BodyEncoding = System.Text.Encoding.UTF8,
Subject = emailSubject,
From = new MailAddress(FromEmailAddress),
Body = emailMessage
};
try
{
foreach (var emailAddress in notificationList)
{
message.To.Add(emailAddress);
}
var people = string.Join(Environment.NewLine, message.To);
MessageBox.Show(#"from: " + unitOfWork.CurrentSystemUser.Person.Email + "To: " + people);
await SendMessage(message);
}
catch (Exception E)
{
...
}
finally
{
...
}
}
private async Task SendMessage(MailMessage mailMessage)
{
if (!CanSendSmtpEmail) return;
await SendSmtpMail(mailMessage);
}
public async Task SendSmtpMail(MailMessage mailMessage)
{
SmtpClient smtpClient = new SmtpClient(SmtpClientHost, int.Parse(SmtpClientPort));
smtpClient.SendCompleted += (s, e) => {
smtpClient.Dispose();
mailMessage.Dispose();
};
await smtpClient.SendMailAsync(mailMessage);
//smtpClient.Send(mailMessage) works fine
}
Increasing SmtpClient.Timeout won't work because it only applies to the synchronous Send method (see here).
Your code is working fine for me when I test it using GMail (like explained here) Can you give it a try with GMail or a different SMTP server? I think maybe your SMTP server is "acting funny". Also maybe you can show us how are you calling SendEmail method ?
Side notes:
Your question is really interesting (at least to me) but because of the way you wrote your code (property has the same name as method) people have down-voted it (you should fix that).
Also, can I see the full exception you get? (btw: catch (Exception E) - not good, use lowercase "e" for the exception argument name).
Make sure you understand exactly how asynchronous it really is.
I have encountered a problem with pusherClient.wp8 package I installed from Nuget. Every time the app is sent to the background, I disconnect from pusher and unsubscribe from the channel. when I resume the app, the code hang when connection is re-established with pusher.
I have tried to reset the pusher object, reset the channel, create a new instance of pusher, and still nothing works, it seems there is a problem with the package, or rather the websocket disconnect method is failing to disconnect from pusher, however, when I close the app, everything get reseted. but this does not help me in instances when a user open a photopicker from my app.
Does anyone has a suggestion or know of another pusherclient I can use for windows phone 8. I have been struggling with this problem for weeks now.
Here is the github link of the package I used: https://github.com/bszypelow/PusherClient.WP8/blob/master/PusherClient.WP8
Thank you
public ConnectionState Connect()
{
var task = Task.Run(async () => await pusher.ConnectAsync()); ;
try
{
task.Wait();
}
catch (Exception ex)
{
Debug.WriteLine("Exception " + ex.Message + " at " + ex.Source + "Inner exception " + ex.InnerException + " additional data " + ex.Data);
}
return task.Result;
}
From looking at the source code I have a guess:
All the async methods never use .ConfigureAwait(false) which could be a reason for the dead lock.
Especially if you call it from the UI thread using the .Wait() or .Result. From event for example.
I suggest you to update the code (it's MIT license, you can do that):
public Task<Channel> Subscribe(string channelName)
{
if (_connection.State != ConnectionState.Connected)
throw new PusherException("You must wait for Pusher to connect before you can subscribe to a channel", ErrorCodes.NotConnected);
if (Channels.ContainsKey(channelName))
{
return Task.FromResult(Channels[channelName]);
}
// If private or presence channel, check that auth endpoint has been set
var chanType = ChannelTypes.Public;
if (channelName.ToLower().StartsWith("private-"))
chanType = ChannelTypes.Private;
else if (channelName.ToLower().StartsWith("presence-"))
chanType = ChannelTypes.Presence;
return SubscribeToChannel(chanType, channelName); //await is not needed here
}
private async Task<Channel> SubscribeToChannel(ChannelTypes type, string channelName)
{
switch (type)
{
case ChannelTypes.Public:
Channels.Add(channelName, new Channel(channelName, this));
break;
case ChannelTypes.Private:
AuthEndpointCheck();
Channels.Add(channelName, new PrivateChannel(channelName, this));
break;
case ChannelTypes.Presence:
AuthEndpointCheck();
Channels.Add(channelName, new PresenceChannel(channelName, this));
break;
}
if (type == ChannelTypes.Presence || type == ChannelTypes.Private)
{
string jsonAuth = await _options.Authorizer.Authorize(channelName, _connection.SocketID)
.ConfigureAwait(false); //do not capture the context!!
var template = new { auth = String.Empty, channel_data = String.Empty };
var message = JsonConvert.DeserializeAnonymousType(jsonAuth, template);
_connection.Send(JsonConvert.SerializeObject(new { #event = Constants.CHANNEL_SUBSCRIBE, data = new { channel = channelName, auth = message.auth, channel_data = message.channel_data } }));
}
else
{
// No need for auth details. Just send subscribe event
_connection.Send(JsonConvert.SerializeObject(new { #event = Constants.CHANNEL_SUBSCRIBE, data = new { channel = channelName } }));
}
return Channels[channelName];
}
You can checkout the source code, than if you don't use it now you can install trial version of ReSharper and this plug-in. They will help you to find all the lines where .ConfigureAwait is missing.