WCF, Silverlight, асинхронные вызовы и Task Parallel Library

Уж сколько раз хоронили Silverlight, а в некоторых, особенно, внутрикорпоративных проектах он всё еще живет и здравствует, и даже активно развивается.

В один из подобных проектов и ступила недавно нога человека (моя, то есть :)).
Типичной задачей в Silverlight апплетах является, конечно, взаимодействие с сервером.

Использование технологии RIA Services (aka Domain Services), некоторое время активно пиарившейся Майкрософтом, лично у меня оставило весьма двойственные впечатления — в первую очередь из-за неочевидности происходящего «под капотом» и ощущения некоей магии происходящего. Поэтому старые добрые WCF-сервисы для взаимодействия с Сильверлайтом остаются для меня приоритетом.

С моего последнего появления в Сильверлайте прошло достаточно много времени, и я надеялся, что взаимодействие с WCF там значительно улучшилось. Оказалось же, что все в общем-то по-прежнему, и чтобы вызвать какой-нибудь метод сервиса вроде

    [ServiceContract]
    public interface ITestService
    {
        [OperationContract]
        int Operation(int value);
    }

Нужно написать что-то вроде:

            var client = new Service2Client();
            EventHandler<TestMethodReturningDataCompletedEventArgs> handler = null;
            handler = (s, args) =>
            {
                client.TestMethodReturningDataCompleted -= handler;
                Dispatcher.BeginInvoke(() =>
                {
                    //some UI method here
                    MessageBox.Show(args.Result.ToString());
                });
            };
            client.TestMethodReturningDataCompleted += handler;
            client.TestMethodReturningDataAsync();

Некоторая непоследовательность вызовов и общая непонятность кода налицо. И это при наличии Task Parallel Library, которая уже стала стандартом де-факто при работе с асинхронностью в .net! Отказавшись мириться с безобразием, происходящим в сильверлайт, я нашел замечательное решение: SyncWCF.

Выносим интерфейс сервиса в Portable Class Library, подключаем его к SL проекту и теперь вызов серсвиса становится куда более приятным!

            var channel = new AsyncChannelFactory<IService2>(new BasicHttpBinding() { }, null)
                .CreateChannel(new EndpointAddress("/Service2.svc"));

            var result = await channel.ExecuteAsync(ws => ws.TestMethodReturningData());
            MessageBox.Show(result.ToString());

К слову, для подобного использования пришлось чуть-чуть дописать библиотеку SyncWCF, потому что в оригинале она настроена на работу с callback’ами.

А если к этому добавить еще пару атрибутов, для нормальной передачи исключений в Silverlight (по умолчанию исключения Сильверлайт, конечно, перехватывает, только текст ошибок в них всех одинаков — «Not Found» :)), то получается совсем привычный «псевдо-синхронный» код.

            try
            {
                await channel.ExecuteAsync(ws => ws.TestMethodThrowingException());
            }
            catch (Exception ex)
            {
                //some error-handling logic is meant to be here 
                MessageBox.Show(ex.ToString());
            }

Рабочий пример с исходными кодами — по ссылке. Там же и слегка измененные исходники SyncWCF (до принятия диффа в основной репозиторий)

Вообще, я откровенно удивлен небольшой популярности проекта SyncWCF, неужели проблема настолько неактуальна? Поделитесь мнением в комменариях! :)

Опубликовать в Facebook
Опубликовать в Google Plus

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *