DisplayPromptAsync Maui Cancel options - c#

as soon as I click on the cancel on the Display it generates an error, System.NullReferenceException: 'Object reference not set to an instance of an object.
private async void NameClicked(object sender, EventArgs e)
{
var ResultName = await DisplayPromptAsync("Insira seu Nome", "Favor inserir seu Nome","Ok", "Cancel");
LabelName.Text = ResultName.ToString();
await DisplayAlert("Nome Alterado","Seu Nome Foi altera com Sucesso","OK");
Apparently an exception needs to be created for " Cancel " but I still can't understand how I will create this exception if anyone can help me
It is finalizing the application as a whole
I was expecting the option to cancel finalize the displaypromptasync and not change anything.

You just need to check if result is null
var result = await DisplayPromptAsync(…);
if (result != null)
{
// do stuff
}

Related

MessageBox.Show sporadically don't show on catching exception

I am writing a Visual Studio extension in C# and I get a strange behavior on managing exception and displaying error messages. Basically, I just want to add some details to the exception message to help me investigate in case of a problem.
It all starts from a command on a context menu item and I suspect it may be related to threads management behind the async/await mechanism. But I am not sure I guess correctly and I am not able to find any solution. HELP!
It starts from my menu item callback:
internal sealed class My_RunAnalysis
{
//...
public static async Task InitializeAsync(AsyncPackage package)
{
// Switch to the main thread - the call to AddCommand in PS_RunAnalysis's constructor requires
// the UI thread.
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
OleMenuCommandService commandService = await package.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService;
Instance = new My_RunAnalysis(package, commandService);
}
//...
private async void ExecuteAsync(object sender, EventArgs e)
{
try
{
await My_ViewModel.RunAnalysisAsync();
}
catch (Exception exc)
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
//...
class My_ViewModel
{
async public static Task RunAnalysisAsync()
{
await My_Model.GetResultsListAsync();
}
}
//...
class My_Model
async public static Task GetResultsListAsync()
{
ResultsList = new My_ResultsList();
var rawResultsList = await QueryServerAsync<RawResultsListResponse>("GET", My_Request.GetResults());
//...
}
async public static Task<JsonResponse> QueryServerAsync<JsonResponse>(string method,
string request)
{
try
{
HttpResponseMessage response;
switch (method)
{
case "GET":
response = await _httpClient.GetAsync(request);
break;
case "POST":
default:
StringContent httpContent = new StringContent("", Encoding.UTF8, "application/json");
response = await _httpClient.PostAsync(request, httpContent);
break;
}
if (!response.IsSuccessStatusCode) //<<<<<<CASE #1
{
throw new My_Exception(
response.ReasonPhrase,
"Exception while querying server for " + request);
}
string serializedJson = await response.Content.ReadAsStringAsync();
// CASE #2>>>>>
var jsonResponse = serializer.Deserialize<JsonResponse>(serializedJson);
return jsonResponse;
}
catch (Exception e)
{
throw new My_Exception(
e.Message,
"Exception while querying server for " + request);
}
}
The strange thing is that:
When an error occurs in case #1 and I create a custom exception (my server responded but there was an internal error and I have a clean error code), the MessageBox in the catch of My_ViewModel::RunAnalysisAsync() will show correctly and immediately.
When a native exception occurs in case #2 (my server responded with malformed json and I get an exception from serializer.Deserialize), the MessageBox in the catch of My_ViewModel::RunAnalysisAsync() will not show, the IDE will hang for around 15s before restarting (and still not show the MessageBox).
Any idea what's wrong?
Thanks!
EDIT:
Seeing that the template for my custom command initializes also with SwitchToMainThreadAsync, I have tried to do the same with the Execute method. I updated the code above but it still does not work: an exception thrown by serializer.Deserialize will still freeze the UI for 10 to 15s and the MessageBox will not show!
Also note that the debugger can step immediately on "await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);" and go on next step to MessageBox. I would tend to suppose it means that the switch to the main thread is immediate but there is still something wrong...
Any idea what's wrong? I really need to capture exceptions a reliable way...
I could not find any explanation to the MessageBox working on a case and not on the other one. I ended up going to some log solution using FileStream.WriteAsync. Hence everything keeps async and I don't have to use MessageBox anymore.
use await JoinableTaskFactory.SwitchToMainThreadAsync(); to switch to the main thread JoinableTaskFactory is a member of AsyncPackage.
If it still doesn't work try
public static void ShowMessageBox(string title, string text)
{
Microsoft.VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();
IVsUIShell uiShell = Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider.GetService(typeof(SVsUIShell)) as IVsUIShell;
Guid clsid = Guid.Empty;
int result;
Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox(
0,
ref clsid,
title,
text,
string.Empty,
0,
OLEMSGBUTTON.OLEMSGBUTTON_OK,
OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
OLEMSGICON.OLEMSGICON_INFO,
0, // false
out result));
}

VS2017 doesn't give details for an exception, just crashed with null

I'm working on a UWP project and there's something funky going on with how errors are being presented to me. I don't know if it's VS2017 or how UWP is set up.
I have a piece of code that goes online and retrieves json content, sometimes the code works and sometimes it doesn't. It works when I use Expander control from UWP Community toolkit, and fails when I want to switch to GridView. When it doesn't work, it fails on GetStringAsync method of HttpClient. The strange behavior is that the exception isn't thrown in the method where the problem occurs, the code actually redirects me back without giving an error and as soon as it gets to the property that's supposed to have a value that isn't null, I get a null exception.
This is where the problem happens:
string httpContent = "";
using (HttpClient httpClient = new HttpClient())
{
try
{
httpContent = await httpClient.GetStringAsync(uri);
}
catch (Exception e)
{
// TODO: handle errors
var x = "";
}
}
This piece of code is called from within the view model. It starts with a constructor and RefreshServerKanesWrathDataAsync is the method where json is parsed.
public CncOnlinePageViewModel()
{
cnconline = new CncOnline();
cnconline.RefreshServerKanesWrathDataAsync();
}
The second I get to GetStringAsync, the code just goes back to the constructor like nothing happened, however the method never completes, it just exits back to the constructor, and therefore fails to update observable collections with data. I then get a null exception.
I wanted to test this with VS2015, but I updated some controls that are apparently only supported withing VS2017, so I can't run the code in other versions.
I also ran into an issue with the code prior to this problem, where I tried to access files in a directory without using a token. The behavior was exactly the same, the code wasn't telling me that I didn't have access to the directory I wanted to read, it was just throwing me out of the method back into the location that made the call to read the directory. Just like with the current problem, I would then run into a null exception, which wasn't where the main problem was.
I added Template10 and UWP community toolkit to the project, if that matters.
You shouldn't call an async method from a constructor unless you're willing to provide a callback.
public CncOnlinePageViewModel()
{
cnconline = new CncOnline();
var t = cnconline.RefreshServerKanesWrathDataAsync(); // assuming returns Task<string>
t.ContinueWith(OnCompleted);
}
private void OnCompleted(Task<string> task)
{
if (task.IsFaulted)
{
// Check error
var exception = task.Exception;
}
else if (task.IsCanceled)
{
// User hit cancel?
}
else
{
// All good!
var result = task.Result;
}
}
Here's a sample where RefreshServerKanesWrathDataAsync() returns just Task (not Task<result>)
public CncOnlinePageViewModel()
{
cnconline = new CncOnline();
var t = cnconline.RefreshServerKanesWrathDataAsync(); // assuming returns Task
t.ContinueWith(OnCompleted);
}
private void OnCompleted(Task task)
{
if (task.IsFaulted)
{
// Check error
var exception = task.Exception;
}
else if (task.IsCanceled)
{
// User hit cancel?
}
else
{
// All good!
}
}
On a side note, you may also need to have Visual Studio 2017 break when any exception is thrown. In VS2017, go to Debug->Windows->Exception Settings and make sure Common Language Runtime Exceptions has a check. If it has a filled box, click the box until it turns into a checkmark.
Also..., you can tap into an event raised when any task has an unobserved exception. You can do so in the constructor of App.xaml.cs
public App()
{
TaskScheduler.UnobservedTaskException += OnUnobservedException;
}
private static void OnUnobservedException(object sender, UnobservedTaskExceptionEventArgs e)
{
// Put break point here.
var ex = e.Exception;
// This will keep your app alive, but only do it if it's safe to continue.
e.SetObserved();
}

NullReferenceException when trying to send bytes via Bluetooth in C#

This is first time I am doing with Bluetooth connection in C#. I am trying to send byte (data type) from application written in C# over Bluetooth.
This is my code:
public class ConnectionManager
{
private StreamSocket socket;
private DataWriter dataWriter;
public void Initialize()
{
socket = new StreamSocket();
}
public void Terminate()
{
if (socket != null)
{
socket.Dispose();
}
}
public async void connect(HostName hostName)
{
if (socket != null)
{
await socket.ConnectAsync(hostName, "1");
dataWriter = new DataWriter(socket.OutputStream);
}
}
//sending data via Bluetooth
public void sendCommand(byte command)
{
dataWriter.WriteByte(command);
}
}
private ConnectionManager connectionManager;
// Constructor
public MainPage()
{
InitializeComponent();
connectionManager = new ConnectionManager();
}
private async void AppToDevice()
{
PeerFinder.AlternateIdentities["Bluetooth:Paired"] = "";
var pairedDevices = await PeerFinder.FindAllPeersAsync();
if (pairedDevices.Count == 0)
{
Debug.WriteLine("No devices found.");
}
else
{
foreach (var pairedDevice in pairedDevices)
{
if (pairedDevice.DisplayName == "HC-06")
{
connectionManager.connect(pairedDevice.HostName);
continue;
}
}
}
}
private void send_Click(object sender, RoutedEventArgs e)
{
byte command = Convert.ToByte(commandTextBox.Text);
connectionManager.sendCommand(command);
}
private void connect_Click(object sender, RoutedEventArgs e)
{
AppToDevice();
}
When I enter some value (for example 1 or 2) in commandTextBox and tap on Send button application crashes. This is the error message: An exception of type 'System.NullReferenceException' occurred in TestBluetooth.DLL but was not handled in user code
Can someone help me?
Sounds like a very basic error. Some object is null. It will happen when you try to access a method or a property on an object that is null.
Troubleshooting:
Check the stacktrace of the error. It says where it fails.
Turn on break on all exceptions when you debug so you can see where exactly it fails, and see which object is null.
If you can not debug it, add a try/catch around all the code in every method you have and use a MessageBox.Show(ex.ToString()) to display the full error with stacktrace when it fails.
If the error occurs in a third party dll, make sure to turn off Debugging->"Enable Just My Code" in Options in Visual Studio.
Download and install Red Gate's Reflector if it fails outside your code and you dont have the source for it. Reflector will "extract" out the code of the DLL and show you exactly the line it fails (or so I believe it does).
When you get an error saying "was not handled in user code" it means an Exception was thrown and not handled by a try/catch by you. I have a finger on the async method you have there.
If I ever play around with threads, i ALWAYS have a try/catch around all my code within the threaded code. I recommend adding a try/catch in the AppToDevice() method. Also add it for all your Form events. Show a message of error to the user or handle it and hide the error from the user.
Check these:
Best Practice for Exception Handling in a Windows Forms Application?
Exception handling in threads

WinRT C#: Cannot save UnhandledException to Storage

I'm working on WinRT. If an unhandled exception is thrown I want to write the message text to the storage.
I added an Event handler in 'App.xaml.cs', see the code.
The exception is caught but the last line, where the file is written, crashes again -> 'exception'!
Why? Any idea?
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
this.UnhandledException += App_UnhandledException;
}
async void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile file= await folder.CreateFileAsync("crash.log",CreationCollisionOption.OpenIfExists);
await FileIO.AppendTextAsync(file, e.Message); // <----- crash again -----
}
Thanks
Sunny
I've been wondering the same thing and stumbled across this quite early on in my search. I've figured out a way, hopefully this will prove useful to someone else too.
The problem is that await is returning control of the UI thread and the app's crashing. You need a deferral but there's no real way to get one.
My solution is to use the settings storage, instead. I'm assuming most people wanting to do this want to do something LittleWatson style, so here's some code modified from http://blogs.msdn.com/b/andypennell/archive/2010/11/01/error-reporting-on-windows-phone-7.aspx for your convenience:
namespace YourApp
{
using Windows.Storage;
using Windows.UI.Popups;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
public class LittleWatson
{
private const string settingname = "LittleWatsonDetails";
private const string email = "mailto:?to=you#example.com&subject=YourApp auto-generated problem report&body=";
private const string extra = "extra", message = "message", stacktrace = "stacktrace";
internal static void ReportException(Exception ex, string extraData)
{
ApplicationData.Current.LocalSettings.CreateContainer(settingname, Windows.Storage.ApplicationDataCreateDisposition.Always);
var exceptionValues = ApplicationData.Current.LocalSettings.Containers[settingname].Values;
exceptionValues[extra] = extraData;
exceptionValues[message] = ex.Message;
exceptionValues[stacktrace] = ex.StackTrace;
}
internal async static Task CheckForPreviousException()
{
var container = ApplicationData.Current.LocalSettings.Containers;
try
{
var exceptionValues = container[settingname].Values;
string extraData = exceptionValues[extra] as string;
string messageData = exceptionValues[message] as string;
string stacktraceData = exceptionValues[stacktrace] as string;
var sb = new StringBuilder();
sb.AppendLine(extraData);
sb.AppendLine(messageData);
sb.AppendLine(stacktraceData);
string contents = sb.ToString();
SafeDeleteLog();
if (stacktraceData != null && stacktraceData.Length > 0)
{
var dialog = new MessageDialog("A problem occured the last time you ran this application. Would you like to report it so that we can fix the error?", "Error Report")
{
CancelCommandIndex = 1,
DefaultCommandIndex = 0
};
dialog.Commands.Add(new UICommand("Send", async delegate
{
var mailToSend = email.ToString();
mailToSend += contents;
var mailto = new Uri(mailToSend);
await Windows.System.Launcher.LaunchUriAsync(mailto);
}));
dialog.Commands.Add(new UICommand("Cancel"));
await dialog.ShowAsync();
}
}
catch (KeyNotFoundException)
{
// KeyNotFoundException will fire if we've not ever had crash data. No worries!
}
}
private static void SafeDeleteLog()
{
ApplicationData.Current.LocalSettings.CreateContainer(settingname, Windows.Storage.ApplicationDataCreateDisposition.Always);
var exceptionValues = ApplicationData.Current.LocalSettings.Containers[settingname].Values;
exceptionValues[extra] = string.Empty;
exceptionValues[message] = string.Empty;
exceptionValues[stacktrace] = string.Empty;
}
}
}
To implement it, you need to do the same as the link above says, but to ensure the data's here in case the url ever goes down:
App.xaml.cs Constructor (BEFORE the call to this.InitializeComponent()):
this.UnhandledException += (s, e) => LittleWatson.ReportException(e.Exception, "extra message goes here");
Obviously if you already have an UnhandledException method you can throw the call to LittleWatson in there.
If you're on Windows 8.1, you can add a NavigationFailed call too. This needs to be in an actual page (typically MainPage.xaml.cs or whatever page is first opened):
xx.xaml.cs Constructor (any given page):
rootFrame.NavigationFailed += (s, e) => LittleWatson.ReportException(e.Exception, "extra message goes here");
Lastly, you need to ask the user if they want to send the e-mail when the app re-opens. In your app's default Page's constructor (default: the page App.xaml.cs initializes):
this.Loaded += async (s, e) => await LittleWatson.CheckForPreviousException();
Or add the call to your OnLoad method if you already use it.
In this situation, await could be loosely translated to "do this job on another thread, and continue what you were doing while you wait for it to finish". Given that what your app was doing was crashing, you probably don't want it to continue doing that until you're done logging the problem. I'd suggest running your file IO synchronously in this case.
This may come a bit too late for the original question but...
as #Hans Passant suggested, avoiding await (i.e., running the FileIO.AppendTextAsync() synchronously), also seconded by #Jon, I would opt for this rather than the relatively too heavy code for LittleWatson. As the app is in some error handing state anyway (this should be a rare occurrence) I wouldn't put any blocking arising from synchronous (due to removing await) as a major downside.
Leaving the synchronous option to one side, the following await implementation worked for me:
Change await FileIO.AppendTextAsync(file, e.Message); to:
Task task = LogErrorMessage(file, e.Message)
task.Wait(2000); // adjust the ms value as appropriate
...
private async Task LogErrorMessage(StorageFile file, string errorMessage)
{
await FileIO.AppendTextAsync(file, errorMessage); // this shouldn't crash in App_UnhandledException as it did before
}

Return Boolean from a method

I am making a save option in my program that saves the changes to a file. I am using this code to save and get a MessageBox to show the result of the process I am getting an error on this line "Object reference not set to an instance of an object."
SaveFileCheck = StockHandler.SaveChangesToFile();
this is my code
private void Save_Click(object sender, EventArgs e)
{
bool SaveFileCheck = false;
var result = MessageBox.Show("Are you sure you want to Save the changes ?", "My Application",
MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk);
if (result == DialogResult.Yes)
{
SaveFileCheck = StockHandler.SaveChangesToFile();
if (SaveFileCheck)
{
MessageBox.Show("The process was a success");
}
else
{
MessageBox.Show("The process failed please make sure that the file is not been used and try again");
}
//Save the file back
}
}
}
}
public bool SaveChangesToFile()
{
try
{
if (FileName != null)
{
using (StreamWriter Write = new StreamWriter(FileName, false))
{
foreach (Stock s in FileStockList)
{
Write.Write(s.ToString() + "\r\n");
}
}
}
else {
return false;
}
}
catch(IOException ex)
{
return false;
throw new ArgumentException("something went wrong an error" + ex + "is been cought");
}
return true;
}
StockHandler is null.
If StockHandler is not a static class, you need to create an instance of it before you can call methods on it:
var handler = new StockHandler();
SaveFileCheck = handler.SaveChangesToFile();
Or, if StockHandler is a member variable:
StockHandler = new // something
You haven't shown what StockHandler is, or where you're getting it from - but it looks like it's null. You'll need it to be a reference to a valid object. There's not a lot more we can say just from the code you've given.
Note that this has nothing to do with a method returning a bool.
It could be that StockHandler is null, or something in the SaveChangesToFile method is null or invalid.
EDIT
See here:
private StockHelper StockHandler;
StockHandler.SaveChangesToFile(); // = bang :(
You need to initialize the StockHelper instance:
private StockHelper StockHandler = new StockHelper();
StockHandler.SaveChangesToFile(); // = okay :)
I'm assuming that this code doesn't compile, which probably means that StockHandler is null. Otherwise, the error would likely be pointing to the SaveChangesToFile method.
Secondly, you either need to swallow exceptions in the SaveChangesToFile() method (not advisable), or you need to remove the return statement and throw the exception. If you do decide to throw an exception, it should definitely not be an ArgumentException, as it has nothing to do with arguments supplied to the method (or lack thereof).
What is stockhandler -- your SaveChangesToFile method is an instance method -- so have you instantiated a variable 'StockHandler' to an instance of whatever class contains the method SaveChangesToFile();

Categories

Resources