Я начинаю работать с BackgroundWorker , чтобы попробовать его, и мне интересно, как я могу остановить запрос, который возвращает Объект Список и это может занять некоторое время.
Полагаю, что я не могу остановить запрос на сервере, но я специально ищу, чтобы остановить чтение SqlDataReader * 1010. * который содержит результат этого запроса.
Вот пример кода с моим BackgroudnWorker и пример запроса:
public partial class Form1 : Form
{
private BackgroundWorker worker;
public Form1 (Point location)
{
this.Location = location;
InitializeComponent();
worker = new BackgroundWorker
{
WorkerSupportsCancellation = true,
};
worker.DoWork += this.Worker_DoWork;
worker.RunWorkerCompleted += this.Worker_RunWorkerCompleted;
}
#region Form
private void ButtonBack_Click (object sender, EventArgs e)
{
if (worker.IsBusy && !worker.CancellationPending)
{
worker.CancelAsync();
}
this.Close();
}
private void TextBoxSearch_TextChanged (object sender, EventArgs e)
{
while (worker.IsBusy)
{
if (worker.IsBusy && !worker.CancellationPending)
{
worker.CancelAsync();
}
}
worker.RunWorkerAsync();
}
#endregion
#region Worker
private void Worker_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
if (worker.IsBusy && !worker.CancellationPending)
{
worker.CancelAsync();
}
Console.WriteLine(e.Error.Message);
}
}
private void Worker_DoWork (object sender, DoWorkEventArgs e)
{
if (!worker.CancellationPending)
{
// Where I'd like to cut the IEnumerable if worker.CancellationPending to shorten time of process
foreach (LigneHS ligne in GetLignesHS(worker.CancellationPending))
{
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
// Do work
}
}
else
{
e.Cancel = true;
return;
}
}
#endregion
// Sample query
internal static IEnumerable<LigneHS> GetLignesHS (bool cancellationPending)
{
string requete = "SELECT * FROM [MY_TABLE] ORDER BY [date] DESC";
SqlConnection conn = BDD.OpenBDD16();
SqlCommand command = new SqlCommand(requete, conn);
List<LigneHS> lignes = new List<LigneHS>();
LigneHS ligne = new LigneHS();
try
{
if (!cancellationPending)
{
SqlDataReader reader = command.ExecuteReader();
while (reader.Read() && !cancellationPending)
{
ligne = new LigneHS();
if (reader["id"] != DBNull.Value)
{
ligne.Id = Convert.ToInt32(reader["id"]);
// filtering null values for every column
lignes.add(ligne);
// tried to add the yield return here, but can't inside a try-catch
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("GetLignesHS : " + ex.Message);
}
finally
{
command.Dispose();
conn.Close();
}
return lignes;
}
}
Как и здесь, cancellationPending запроса не обновляется, еслирабочего просят остановиться.
Сначала я подумал об использовании yield return для прерывания foreach, если BackgroundWorker попросили остановить. Но я использую try-catch при обработке запроса, поэтому не могу.
Я знаю, что использование CancellationToken , как я делал, когда использовал прямой поток, будетработать, но мне интересно, если это лучший способ добиться того, чего я хочу здесь.