I'm calling Class Library method within WPF app, using CancellationToken. Method exports data to Excel from Oracle, and sometimes operation takes too long or doesn't complete, so I tried with implementing cancellation.
WPF app - button click for export and export method:
public async void Export_Execute(object parameter)
{
SaveFileDialog dialog = new SaveFileDialog
{
InitialDirectory = Environment.GetFolderPath(
Environment.SpecialFolder.Desktop).ToString(),
Filter = "Excel |*.xlsx",
Title = "Save as"
};
if (dialog.ShowDialog() == true)
{
if (await Task.Run(() => GetData(dialog.FileName, DateTime.Now)))
{
var m = MessageBox.Show("Export complete, wish to open Excel file?",
"Export", MessageBoxButton.YesNo);
if (m == MessageBoxResult.Yes)
{
Process.Start(dialog.FileName);
}
}
}
}
GetData method:
public bool GetData(string _filename, DateTime? _date)
{
try
{
using (OracleConnection con = new OracleConnection(conn_string))
{
con.Open();
MyTokenSource = new CancellationTokenSource();
OracleCommand cmd = new OracleCommand("MySchema.Employees", con)
{
CommandType = CommandType.StoredProcedure
};
cmd.Parameters.Add("date_in", OracleDbType.Date).Value = _date;
cmd.Parameters.Add("result", OracleDbType.RefCursor,
ParameterDirection.Output);
var export = new MyExports();
export.Export_DataReader(cmd, MyTokenSource.Token);
return true;
}
}
catch (OperationCanceledException)
{
MessageBox.Show("Operation cancelled by user.", "Export data")
return false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
}
If something goes wrong in this WPF method, I want an actual error displayed. But If user cancels GetData method manually, I want to display a predefined message.
C# Class library code:
private static System.Timers.Timer CancelExport { get; set; }
public void Export_DataReader(OracleCommand _cmd, CancellationToken? _cancel)
{
//Doing long operations here for exporting to Excel...
// Timer gets enabled here too - in more or less beginning of the code...
Monitor(_cmd, _cancel);
}
private void Monitor(OracleCommand _cmd, CancellationToken? _cancel)
{
if (_cancel != null)
{
CancelExport = new System.Timers.Timer();
CancelExport.Elapsed += (sender, e) => MonitorEvent(sender, e, _cmd, _cancel);
CancelExport.Interval = 2000;
CancelExport.Enabled = true;
}
}
private static void MonitorEvent(object s, ElapsedEventArgs e, OracleCommand _cmd,
CancellationToken? _cancel)
{
if (_cancel.Value.IsCancellationRequested)
{
CancelExport.Enabled = false;
// When uncommented, this successfully returns Oracle exception
// Leaving like this, code just goes through,
// It ignores ThrowIfCancellationRequested()
// _cmd.Cancel();
//This doesn't return OperationCancelledException to WPF App so
//code keeps running like no error happened, even though error
//is visible in Output window
_cancel.Value.ThrowIfCancellationRequested();
}
}
So, when I hit MyTokenSource.Cancel() in WPF app, I get Oracle.DataAccess.dll error exception If I want, but not OperationCancelledException from CancellationToken.
What should I do to get OperationCanceledException back to my WPF app method?
MyTokenSource = new CancellationTokenSource(timeout);? E.g.MyTokenSource = new CancellationTokenSource(1000);to wait 1 second before cancellationGetDatamethod? I assume it's an event handler of a UI control.GetDatacalled? And where doesexport.Export_DataReaderthrow? Your code sample is a mess. Please read this and update your question accordingly.