Как рефакторинг кода, чтобы использовать потоки?


У меня есть класс WebPostRequest, который выглядит так:

public class WebPostRequest
{
    public const string Success = "OK";

    private WebRequest _webRequest;
    private List<string> _paramsList;

    public WebPostRequest(string url)
    {
        try
        {
            _webRequest = WebRequest.Create(url);
        }
        catch (Exception)
        {
            throw;
        }
        _webRequest.Method = "POST";
        _webRequest.ContentType = "application/x-www-form-urlencoded";
        _paramsList = new List<string>();
    }

    public void Add(string key, string value)
    {
        _paramsList.Add(String.Format("{0}={1}", key, HttpUtility.UrlEncode(value)));
    }

    public void UploadPdf(string postKey, string name, params UserControl[] userControls)
    {
        string fileName = FileHelper.GetTimestampedName(name, "pdf");
        string filePath = PdfHelper.Save(fileName, userControls);
        FtpHelper.UploadFile(filePath);
        this.Add(postKey, fileName);
    }

    public void UploadImage(string postKey, string name, Image image)
    {
        if (image != null)
        {
            string fileName = FileHelper.GetTimestampedName(name, "jpg");
            FtpHelper.UploadFile(fileName, image.ToByteArray());
            this.Add(postKey, fileName);
        }
    }

    public string GetResponse()
    {
        // Build a string containing all the parameters
        string parameters = String.Join("&", _paramsList.ToArray());
        _webRequest.ContentLength = parameters.Length;

        try
        {
            // Write the parameters into the request
            using (StreamWriter streamWriter = new StreamWriter(_webRequest.GetRequestStream()))
            {
                streamWriter.Write(parameters);
            }

            // Execute the query
            HttpWebResponse httpWebResponse = (HttpWebResponse)_webRequest.GetResponse();
            StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream());
            return streamReader.ReadToEnd();
        }
        catch (Exception)
        {
            throw;
        }
    }
}

В WebPostRequest класс использует объект WebRequest, чтобы разместить на веб-сервер и получить ответ.

Класс используется такой:

bool success = false;
try
{
    WebPostRequest webPostRequest = new WebPostRequest(url);

    webPostRequest.Add("key_1", "value_1");
    webPostRequest.Add("key_2", "value_2");

    webPostRequest.UploadPdf("key_3", "pdf_name_1", userControl1);
    webPostRequest.UploadPdf("key_4", "pdf_name_2", userControl2);

    webPostRequest.UploadImage("key_5", "picture_name_1", image1);
    webPostRequest.UploadImage("key_6", "picture_name_1", image2);

    string response = webPostRequest.GetResponse();
    if (response != WebPostRequest.Success)
    {
        throw new Exception(response);
    }
    success = true;
}
catch (Exception ex)
{
    //display error messaage
}
if (success)
{
    //display success message
}

Что я хочу сделать, это добавить окно для отображения сообщений о состоянии и прогресс (типа шатер). Окно должно быть отображается с WebPostRequest класс, потому что этот класс используется в нескольких местах в приложении. Задачи загрузки, который может занять много времени, нужно будет выполняться в другом потоке, так что поток пользовательского интерфейса не реагирует. Обратите внимание, что все файлы должны быть загружены перед постом, поэтому метод GetResponse должен ждать загрузки задач, чтобы закончить. Отметим также, что вспомогательные методы могут приводить к ошибкам, которые обрабатываются вне WebPostRequest класс.

Какие советы/рекомендации можете дать? Любая идея приветствуется.



456
2
задан 18 ноября 2011 в 01:11 Источник Поделиться
Комментарии
1 ответ

Я не хотел показать пользовательский интерфейс из WebPostRequest. Для быстрого решения вы можете просто обернуть загружать целые части и предоставить какой-то слушатель, чьи методы будут вызываться, чтобы сообщить о прогрессе.

Таким образом WebPostRequest не знаю ничего об уровне пользовательского интерфейса. Пользовательский интерфейс не будет заблокирован и иметь возможность отслеживать прогресс загрузки.

Вот в C#-как псевдокод, иллюстрирующий, что я имею в виду:

class ProgressListener
{
public void OnProgress(OperationContext)
{
//notiy UI in the thread-safe way -> use Control.Invoke for Windows Forms
}

public void OnFinish(OperationContext)
{
//show success message in UI
}

public void OnError(OperationContext)
{
//show detailed error message in UI
}
}

//on UI class
void PerformUpload()
{

ProgressListener listener = new ProgressListener(Form f);

Thread thread = new Thread(() =>
{
try
{
try
{
WebPostRequest webPostRequest = new WebPostRequest(url);
webPostRequest.Add("key_1", "value_1");
webPostRequest.Add("key_2", "value_2");

webPostRequest.UploadPdf("key_3", "pdf_name_1", userControl1);

listener.OnProgress( /*operaton context*/)

webPostRequest.UploadPdf("key_4", "pdf_name_2", userControl2);

listener.OnProgress( /*operaton context*/)
webPostRequest.UploadImage("key_5", "picture_name_1", image1);

listener.OnProgress( /*operaton context*/)
webPostRequest.UploadImage("key_6", "picture_name_1", image2);

listener.OnProgress( /*operaton context*/)

string response = webPostRequest.GetResponse();
if (response != WebPostRequest.Success)
{
listener.OnProgress( /*operaton context*/)

throw new Exception(response);
}
success = true;

listener.OnFinish( /*operaton context*/)
}
catch (Exception ex)
{
listener.OnError( /*operaton context*/)
//display error messaage
}
}
catch(Exception ex)
{
listener.OnError( /*operaton context*/)
//logging
}
});

thread.Name = "uploader";
thread.Start();
}

1
ответ дан 11 декабря 2011 в 10:12 Источник Поделиться