Синхронные вызовы служб данных ADO.NET в Silverlight

Я использую службы данных ADO.NET в приложении Silverlight, и, поскольку библиотеки Silverlight не поддерживают вызов ToList() для IQueryable, я подумал, что можно создать метод расширения вокруг этого, называемый SilverlightToList(). Итак, в этом методе я вызываю метод BeginExecute в своем контексте, как показано ниже:

            var result = context.BeginExecute<T>(currentRequestUri,null,context);
            result.AsyncWaitHandle.WaitOne();
            return context.EndExecute<T>(result).ToList();

Проблема в том, что когда я вызываю метод WaitOne(), это приводит к взаимоблокировке. Является ли это ограничением служб данных ADO.NET в Silverlight? Возможно, есть обходной путь для этого?


person James_2195    schedule 09.12.2008    source источник
comment
Хороший вопрос, распространенная проблема в Silverlight   -  person Andrei Rînea    schedule 08.10.2009


Ответы (4)


Мне удалось победить ( :P ) асинхронного монстра в Silverlight следующим образом:

var ctx = new ModelEntities(new Uri("http://localhost:2115/Data.svc"));

ManualResetEvent m1 = new ManualResetEvent(false);
ManualResetEvent m2 = new ManualResetEvent(false);

var q1 = (DataServiceQuery<Department>)(from e in ctx.Department select e);
var q2 = (DataServiceQuery<Person>)(from e in ctx.Person select e);

Department[] r1 = null;
Person[] r2 = null;

q1.BeginExecute(r =>
{
    try { r1 = q1.EndExecute(r).ToArray(); }
    finally { m1.Set(); }
}, null);
q2.BeginExecute(r =>
{
    try { r2 = q2.EndExecute(r).ToArray(); }
    finally { m2.Set(); }
}, null);

ThreadPool.QueueUserWorkItem((o) =>
{
    WaitHandle.WaitAll(new WaitHandle[] { m1, m2 });
    // do your thing..
});

Основная идея состоит в том, чтобы создать поток ожидания (последний блок), который будет иметь ссылки на объекты ожидания. НЕ помещайте вызов WaitAll в метод/поток вызывающей стороны, потому что это приведет к взаимоблокировке, как упоминалось ранее на этом сайте или других сайтах.

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

Однако не в моем случае выше, потому что WaitAll находится в ДРУГОМ потоке.

PS: Вместо строки // do your thing поместите код, который использует захваченные ссылки r1 и r2, которые будут содержать данные или null, если этот результат не удался.

person Andrei Rînea    schedule 08.10.2009

С тех пор я нашел этот пост на форуме MSDN, который говорит, что любая управляемая-> неуправляемая-> управляемая сортировка происходит в потоке пользовательского интерфейса, что объясняет, почему вызов метода WaitOne зависает...

person James_2195    schedule 09.12.2008

Silverlight, вероятно, не понравится что-либо синхронное, потому что он предназначен для работы в браузере, и у него может быть только один поток для работы — и он должен его совместно использовать. И единственный поток, доступный хосту, — это поток, предоставляемый браузером.

person dkretz    schedule 09.12.2008
comment
Разве наличие только одного потока не повышает вероятность синхронного вызова элементов? - person ChrisHDog; 09.12.2008
comment
Нет, это означает, что это не нужно, потому что это заморозит все остальное, что происходит в браузере, на всех вкладках. - person dkretz; 09.12.2008

Все вызовы служб в Silverlight должны быть асинхронными. Итак, вам нужно определить обратный вызов, чтобы получить результат, например:

context.BeginExecute<T>(currentRequestUri, resultCallback, context);

private void resultCallback(IAsyncResult asyncResult)
{
    DataServiceContext context = asyncResult.AsyncState as DataServiceContext;
    var result = context.EndExecute<T>(asyncResult);
    // Do whatever you need with the result here
}

Вот хороший справочник в MSDN: http://msdn.microsoft.com/en-us/library/cc838191(VS.95).aspx

person Boyan    schedule 09.12.2008
comment
Привет, спасибо за ответ. Попробовал по-вашему, как вы говорите, работает. Единственным недостатком этого метода является то, что я хотел бы передать результат обратно вызывающему потоку. Я видел в документации MS, что они обычно устанавливают DataContext элемента управления для результата. - person James_2195; 09.12.2008
comment
Попробуйте использовать объект Dispatcher элемента управления, чтобы установить его DataContext из метода обратного вызова результата. - person Boyan; 09.12.2008