Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Рекомендации по преобразованию вызовов WCF в асинхронные вызовы WCF

Автор вопроса: ScottGОтветов: 6

У меня возникают проблемы при попытке преобразовать все мои обычные вызовы WCF в асинхронные вызовы WCF. Я обнаружил, что у меня есть рефакторинг большого количества кода, и я не уверен, как именно это сделать. Я использовал метод, который нашел здесь, но столкнулся с проблемами, когда Мне нужно, чтобы все происходило по порядку.

private void btnSave_Click(object sender, RoutedEventArgs e)
{

  List<Item> itemList = GetList();
  foreach(Item i in itemList)
  {
    DoSomeWork(i);

    if(i.SomeID == 0)
    {
       DoSomeMoreWork(i);
    }

    UpdateRecord(i)  // this can't execute until the above code is complete

  }
}

private void DoSomeWork(Item i)
{
  // call async method
}

private void DoSomeMoreWork(i)
{
  // call async method
}

private void UpdateRecord(item i)
{
  // call async method
}

Каков наилучший способ рефакторинга кода, чтобы он работал асинхронно, или мне нужно полностью переосмыслить свою логику? Мне действительно нужно повсюду вставлять счетчики и переключатели, чтобы убедиться, что определенные действия выполняются до того, как будут выполняться другие?

РЕДАКТИРОВАТЬ: причина, по которой я это делаю, заключается в том, что в ближайшие пару месяцев мы преобразуем это приложение WPF в Silverlight, для которого требуются асинхронные вызовы. Итак, я пытаюсь преобразовать наши обычные вызовы WCF в асинхронные в процессе подготовки. Я считаю, что это требует другого образа мышления.

asynchronouswcf

Ответы

Ответ 1 · рейтинг 3 · kyoryu

Для того, что вы делаете, я бы сказал, что реальное место для обработки вещей - сделать один вызов службы для каждого элемента, а не 3.

Желательно, если список пунктов не велик, сделать один звонок в сервис со всем списком...

private void btnSave_Click(object sender, RoutedEventArgs e)
{
    List<Item> itemList = GetList();
    foreach(Item i in itemList)
    {
        DoAllTheWorkAndUpdate(i);
    }
}

or...

private void btnSave_Click(object sender, RoutedEventArgs e)
{
    List<Item> itemList = GetList();
    foreach(Item i in itemList)
    {
        if(i.Id == 0)
        {
            DoLotsOfWorkAndUpdate(i);
        }
        else
        {
            DoSomeWorkAndUpdate(i);
        }

    }
}

or...

private void btnSave_Click(object sender, RoutedEventArgs e)
{
    List<Item> itemList = GetList();
    DoTheWorkOnTheWholeList(itemList);
}

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

Ответ 2 · рейтинг 2 · Matt Davis

Взгляните на Джувала Лоуи (автор книги Программирование служб WCF) веб-сайт с примерами реализации асинхронного программирования в ВКФ. Загрузки бесплатны; вам просто нужно указать свой адрес электронной почты.

Ответ 3 · рейтинг 1 · Navaar

Я, возможно, немного озадачен тем, почему вам нужно использовать асинхронные операции WCF, когда вам нужно, чтобы вещи были синхронными внутри цикла.

Если вы просто используете асинхронные методы, чтобы предотвратить зависание пользовательского интерфейса, вы можете просто использовать BackgroundWorker, который поддерживает обновления хода выполнения, чтобы поддерживать пользовательский интерфейс в актуальном состоянии, а не использовать асинхронные вызовы WCF.

Вы также должны иметь возможность вызывать различные функции из событий Completed для асинхронных методов.

Просто подключите обработчики событий к завершенным событиям, а затем передайте объект Item в качестве параметра userState при запуске асинхронного вызова WCF. Таким образом, вы будете иметь его в качестве параметра, когда срабатывает каждое из событий Completed. Таким образом, вы будете выполнять следующий шаг обработки только после завершения предыдущего асинхронного вызова.

Я не знаю, действительно ли это отвечает на ваш вопрос.

Ответ 4 · рейтинг 1 · Andrei Sedoi

Попробуйте использовать это

http://ayende.com/Blog/archive/2008/03/29/WCF-Async-without-proxy.aspx

подход, который определенно работает.

Ответ 5 · Ken Smith

Если вы не используете Silverlight, вы можете заблокировать поток в одном методе до завершения других методов, например, с помощью события ManualResetEvent. Но это не будет работать в Silverlight, так как все вызовы WCF происходят в основном потоке пользовательского интерфейса, поэтому, если вы заблокируете этот поток, блокируется все. Лучший подход - сделать что-то подобное, используя обратные вызовы:

    public delegate void OperationCallback();

    private void btnSave_Click(object sender, RoutedEventArgs e)
    {

        List<Item> itemList = GetList();
        foreach (Item i in itemList)
        {
            DoSomeWork(i, () =>
            {
                if (i.SomeID == 0)
                {
                    DoSomeMoreWork(i, () =>
                    {
                        UpdateRecord(i);
                    });
                }
                else
                {
                    UpdateRecord(i);
                }
            });

        }
    }

    private void DoSomeWork(Item i, OperationCallback callback)
    {
        // call async method then callback when it completes.
        callback();
    }

    private void DoSomeMoreWork(Item i, OperationCallback callback)
    {
        // call async method, then callback when it completes.
        callback();
    }

    private void UpdateRecord(Item i)
    {
        // call async method
    }

Это, конечно, не так ясно, как в синхронной версии, но если вы как можно больше используете лямбда-выражения, все же можно сохранить достаточно читаемый поток управления.

Ответ 6 · рейтинг -1 · Chris Porter

Добавьте 2 свойства в Item с именами SomeWorkDone и SomeMoreWorkDone как логические значения. Создайте методы для обработки как DoSomeWorkCompleted, так и DoSomeMoreWorkCompleted. В этих методах задайте для соответствующих логических свойств значение true и вызовите UpdateRecord. В UpdateRecord убедитесь, что оба свойства Done имеют значение true, а затем завершите вызовы.

У вас будут некоторые возможные проблемы с конкуренцией, но это должно помочь вам.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы