Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > Общие вопросы .NET
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 25.09.2010, 22:47   #1
Casper-SC
Форумчанин
 
Регистрация: 04.07.2007
Сообщений: 549
По умолчанию "Убить" BackgroundWorker. Не дать продолжать операцию.

У меня программа выгружает файл в интернет на сервер. Работает всё это дело через BackgroundWorker. Я сделал так, чтобы. Жму "Выгрузить", файл начинает отгружаться, жму "Отмена":
Код:
            if (bgrWorkerUploader == null)
            {
                BackgroundWorker bgrWorker = new BackgroundWorker(); 
                bgrWorker.WorkerSupportsCancellation = true;
                bgrWorker.WorkerReportsProgress = true;
                bgrWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgrWorkerUploader_RunWorkerCompleted);
                bgrWorker.DoWork += new DoWorkEventHandler(bgrWorkerUploader_DoWork);
                bgrWorkerUploader = bgrWorker;
            }
 
            if (!bgrWorkerUploader.IsBusy)
            {
                this.btnStartUpload.Content = "Отмена";
                this.uploadTimer.Start();
                ArgumentsUploader args = new ArgumentsUploader();
                args.fullFilePath = this.textBoxFilePath.Text;
                args.contentType = "image/png";
                bgrWorkerUploader.RunWorkerAsync(args);
            }
            else
            {
                bgrWorkerUploader.Dispose();
                bgrWorkerUploader = null;
                //bgrWorkerUploader.CancelAsync();
                this.btnStartUpload.Content = "Выгрузить";
                this.uploadTimer.Stop();
                this.SetCancelOperationText();
            }
Я так намудрил, потому, что если делать так:
Код:
bgrWorkerUploader.CancelAsync();
то по моему операция продолжает работать до конца, пока не выгрузит файл. А мне надо, чтобы при нажатии отмены сразу же прекращалась операция.

Я знаю, что в обработчике DoWork можно вставить такой код:
Код:
                    ............
                    if (bgrWorkerUploader.CancellationPending) //если операция не была отменена
                    {
                        e.Cancel = true;
                    }
                    else
                    {
                        response = imgUploader.Upload(argsUploader.fullFilePath, argsUploader.contentType);
                    }
                    ............
Но файл то продолжает выгружаться. Кто знает такой способ убивает работу BackgroundWorker'a?
Код:
                bgrWorkerUploader.Dispose();
                bgrWorkerUploader = null;
Просто я не пойму файл продолжает выгружаться или нет. На хостинг изображений идёт отгрузка, так что я узнать не могу продолжается ли операция или прерывается.
Что можно сделать, чтобы операция сразу бы прекращала выполняться при нажатии "Отмена"?

Последний раз редактировалось Casper-SC; 25.09.2010 в 22:55.
Casper-SC вне форума Ответить с цитированием
Старый 25.09.2010, 22:57   #2
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Вы понимаете, что код нельзя просто взять и оборвать в любой момент, и указать процессору выполнять другие инструкции, тогда попросту все рухнет, вся система, и ждите перезагрузки. Теперь по сути, обычно долгая работа это цикл, если нет, то сделайте цикл, т.е. к примеру если это чтение файла, то читайте маленькими частями в цикле. В цикле добавляете условие, проверку отмени действия. Вот и все.
BOBAH13 вне форума Ответить с цитированием
Старый 26.09.2010, 18:06   #3
Casper-SC
Форумчанин
 
Регистрация: 04.07.2007
Сообщений: 549
По умолчанию

Хорошо. Например вот есть у меня метод передачи:
Код:
        public String Upload(string filename, string contenttype)
        {
            //...................................
            //Тут составляем запрос и т.д.
            //...................................

            // Читаем файл
            using (FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
            {
                buffer = new byte[fileStream.Length];
                fileStream.Read(buffer, 0, buffer.Length);
            }
            long length = postHeaderBytes.Length + buffer.Length + boundaryBytes.Length;
            webrequest.ContentLength = length;

            // Пишем заголовок запроса
            Stream requestStream = webrequest.GetRequestStream();
            requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

            //ВОТ ЭТО ПЕРЕДАЧА САМОГО ФАЙЛА
            // Пишем файл 
            requestStream.Write(buffer, 0, buffer.Length);

            // Пишем boundary
            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);

            // Получаем ответ
            WebResponse responce = webrequest.GetResponse();
            Stream s = responce.GetResponseStream();

            // Читаем
            StreamReader sr = new StreamReader(s, Encoding.GetEncoding("UTF-8"));
            string result = sr.ReadToEnd();
            sr.Close();

            return result;
        }

Вот я хочу выгружать файл маленькими частями с проверкой отменили ли работу BackgroundWorker'у (пока проверку не делаю, надо бы вообще понять как передавать частями файл). Делаю так:

Код:
        public String Upload(string filename, string contenttype)
        {
            //...................................
            //Тут составляем запрос и т.д.
            //...................................

            // Читаем файл
            using (FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
            {
                buffer = new byte[fileStream.Length];
                fileStream.Read(buffer, 0, buffer.Length);
            }
            long length = postHeaderBytes.Length + buffer.Length + boundaryBytes.Length;
            webrequest.ContentLength = length;

            // Пишем заголовок запроса
            Stream requestStream = webrequest.GetRequestStream();
            requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

            //====== Так я пытаюсь его передавать частями ======
            int part = 2048;
            for (int i = 0; i < buffer.Length; i += part)
            {
                while (i + part > buffer.Length)
                {
                    part--;
                }
                requestStream.Write(buffer, i, part);
 
            }
            //============================================

            // Пишем boundary
            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);

            // Получаем ответ
            WebResponse responce = webrequest.GetResponse();
            Stream s = responce.GetResponseStream();

            // Читаем
            StreamReader sr = new StreamReader(s, Encoding.GetEncoding("UTF-8"));
            string result = sr.ReadToEnd();
            sr.Close();

            return result;
        }
Вот так я его пытаюсь передать частями, но что-то не получается ничего. Помогите, как это сделать? Вообще теоретически это должно работать?



Хм... А вот теперь получилось, всё передаётся.

Ничего не понимаю, то передаётся, то нет

Последний раз редактировалось Casper-SC; 26.09.2010 в 18:39. Причина: Получилось передать файл
Casper-SC вне форума Ответить с цитированием
Старый 26.09.2010, 18:32   #4
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Код:
while (i + part > buffer.Length)
                {
                    part--;
                }
Вообще жесть.

Код:
int part = 2048;
int i = 0;
bool canceled = false;
while ((i < buffer.Length) && !canceled)
{
    if (buffer.Length - i < part)
    {
        part = buffer.Length - i;
    }
    requestStream.Write(buffer, i, part);
    i += part;
}
Как то так. И + надеюсь у вас там файлы не большие, а то вы весь файл читаете сразу в память, а это очень плохо. И кстати, лучше делайте буфер чтения и записи 1024. А еще можно к примеру, открыть файл для чтения и реквест стрим, и сразу читайте в буфер и шлите, после пересылки закрывайте файл. Так просто логичней, и можно слать какого угодно размера данные.
BOBAH13 вне форума Ответить с цитированием
Старый 26.09.2010, 22:23   #5
Casper-SC
Форумчанин
 
Регистрация: 04.07.2007
Сообщений: 549
По умолчанию

Цитата:
Сообщение от BOBAH13 Посмотреть сообщение
Код:
while (i + part > buffer.Length)
                {
                    part--;
                }
Вообще жесть.
Ах-ха-ха-ха, да вообще жесть, я так особо не думая, хотел вообще разобраться, просто запрос и отправку мне помогли сделать, я вообще впервые сам разбираюсь как куда-то передавать файлы. Кстати интересная вещь, открывает большие возможности

Вот как я всё перелопатил, вроде то что надо:

Код:
        public String Upload(string filename, string contenttype)
        {
            //...................................
            //Тут составляем запрос и т.д.
            //...................................
            int part = 1024;       //размер части передаваемого файла
            buffer = new byte[part];
            // Читаем файл
            FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);

            long length = postHeaderBytes.Length + fileStream.Length + boundaryBytes.Length;
            webrequest.ContentLength = length;

            // Пишем заголовок запроса
            Stream requestStream = webrequest.GetRequestStream();
            requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

            int i = 0;

            while (i < fileStream.Length)
            {
                if (fileStream.Length - i < part)
                {
                    part = (int)(fileStream.Length - i);
                }
                    fileStream.Read(buffer, 0, part);
                    requestStream.Write(buffer, 0, part);
                    i += part;
            }


            fileStream.Close(); //закрываем поток

            // Пишем boundary
            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);

            // Получаем ответ
            WebResponse responce = webrequest.GetResponse();
            Stream s = responce.GetResponseStream();

            // Читаем
            StreamReader sr = new StreamReader(s, Encoding.GetEncoding("UTF-8"));
            string result = sr.ReadToEnd();
            sr.Close();
            return result;
        }
Ну а позже всё это скопирую в свой проект (тестирую изменения отдельно, запуск программы в разы быстрее) и добавлю проверку на отмену в BackgrounWorker'a.

P.S. Если опять не так что-то сделал, мнение мне будет интересно чьё либо.

Последний раз редактировалось Casper-SC; 27.09.2010 в 02:33.
Casper-SC вне форума Ответить с цитированием
Старый 27.09.2010, 09:27   #6
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Код:
 fileStream.Close(); //закрываем поток
На счет этого не уверен, вообще в C# я до сих пор пытаюсь вникнуть об освобождении объектов. Я бы советовал сделать типа такого
Код:
fileStream.Dispose();
fileStream = null;
А подобные части
Код:
StreamReader sr = new StreamReader(s, Encoding.GetEncoding("UTF-8"));
            string result = sr.ReadToEnd();
            sr.Close();
можно делать так
Код:
var result = string.empty;
using (var sr = new StreamReader(s, Encoding.GetEncoding("UTF-8")))
{
            result = sr.ReadToEnd();
}
BOBAH13 вне форума Ответить с цитированием
Старый 27.09.2010, 18:10   #7
Casper-SC
Форумчанин
 
Регистрация: 04.07.2007
Сообщений: 549
По умолчанию

Цитата:
И кстати, лучше делайте буфер чтения и записи 1024.
А кстати почему лучше? Я сейчас добавил расчёт процентов, ну сколько выгрузилось, получается чем меньше часть передаваемого файла, тем больше раз выполняется расчёт.

Вообще сейчас пока это в таком виде (урезано, так как весь код и не влезет и нет смысла его выкладывать):


Код:
        //Выгрузить изображение на хостинг
        void bgrWorkerUploader_DoWork(object sender, DoWorkEventArgs e)
        {
            //Аргументы передаваемые в BackgroundWorker нужные для отправки изображения на хостинг
            ArgumentsUploader argsUploader = (ArgumentsUploader)e.Argument;

            Boolean connect = InternetConnection.CheckConnection(); //проверить соединение с интеренетом
            if (connect)
            {
                this.Dispatcher.Invoke(new Action(SetBtnUploadNameIn_Cancel)); //Установить на кнопке текст: "Отмена"
                int progress = 0; //прогресс выполнения

               //...................................
               //Тут составляем запрос и т.д. + часть кода, что в прошлых сообщениях и новый код
               //...................................

                int uploadedLength = 0;

                //Получаем размер одного процента из всего размера файла
                float percent1 = (float)(fileStream.Length / 100);
                float percent100 = (float)(fileStream.Length);

                while (uploadedLength < fileStream.Length)
                {
                    if (bgrWorkerUploader.CancellationPending) //если операция была отменена
                    {
                        e.Cancel = true;
                        fileStream.Close(); //закрываем поток
                        this.Dispatcher.Invoke(new Action(DisableButtonStartUpload));
                        this.Dispatcher.Invoke(new Action(SetApplyCancellingText));

                        try
                        {
                            requestStream.Close();
                        }
                        catch
                        {
                            return; //завершить выполнение метода
                        }
                        return; //завершить выполнение метода
                    }
                    else
                    {
                        if (fileStream.Length - uploadedLength < part)
                        {
                            part = (int)(fileStream.Length - uploadedLength);
                        }
                        fileStream.Read(buffer, 0, part);
                        requestStream.Write(buffer, 0, part);
                        uploadedLength += part;

                        progress = (int)(uploadedLength / percent1);

                        bgrWorkerUploader.ReportProgress(progress); //Сообщить о прогрессе выполнения !!!
                    }
                }
               //===========
               //Далее остальное
               //===========
        }

Последний раз редактировалось Casper-SC; 27.09.2010 в 19:00.
Casper-SC вне форума Ответить с цитированием
Старый 27.09.2010, 20:51   #8
userdab
Пользователь
 
Регистрация: 04.09.2010
Сообщений: 28
По умолчанию

для backgroundWorker вызвать CancelAsync, правда может быть проблема
userdab вне форума Ответить с цитированием
Старый 27.09.2010, 21:33   #9
Casper-SC
Форумчанин
 
Регистрация: 04.07.2007
Сообщений: 549
По умолчанию

Цитата:
Сообщение от userdab Посмотреть сообщение
для backgroundWorker вызвать CancelAsync, правда может быть проблема
Я так и делаю. Я там уже так всё замутил, что уже работает безотказно, отгружает, даёт все ссылки. При нажатии отмены прекращает работу. Даже в процессе выгрузки файла, что видно из кода в прошлом моём сообщении. При отсутствии соединения с интернетом показывает сообщение пользователю и не пытается ничего выгружать. При не настроенном интернете или вообще проблемах с интернетом тоже сообщает об этом пользователю. Показывается прогресс выгрузки на ProgressBar'e (главное вовремя остановится, а то я уже захотел сделать, чтобы показывалось в килобайтах сколько выгрузилось из общего кол-ва и ещё мелочей) Остался только один вопрос:

Почему лучше выгружать по 1024 байта (одному килобайту). Мне просто не понятно это.
Casper-SC вне форума Ответить с цитированием
Старый 29.09.2010, 21:02   #10
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Цитата:
Почему лучше выгружать по 1024 байта (одному килобайту). Мне просто не понятно это.
То было мое ИМХО привычка у меня видимо такая, ставить такое число.
BOBAH13 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как обойти "преобразование типа из "string" в "float" невозможно" lexluter1988 Помощь студентам 1 07.08.2010 12:23
при вводе на листе "магазин"- код товара появлялось "описание" товара из "склада" с "продажной ценой" aleksei78 Microsoft Office Excel 13 25.08.2009 12:04
"Убить" конкурента valerij Microsoft Office Excel 15 26.08.2008 15:08