Синхронные вызовы служб данных ADO.NET в Silverlight
-
20-08-2019 - |
Вопрос
Я использую службы данных 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?Возможно, есть обходной путь для этого?
Решение 2
с тех пор я нашел эта почта на форуме MSDN, где говорится, что любой управляемый->Неуправляемый->Управляемый маршалинг происходит в потоке пользовательского интерфейса, что объясняет, почему вызов метода WaitOne зависает...
Другие советы
Мне удалось победить (: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 yourthing разместите код, который использует захваченные ссылки r1 и r2, которые будут содержать данные или ноль, если этот результат не удался.
Silverlight, вероятно, не понравится ничего синхронного, потому что он предназначен для запуска в браузере и может иметь только один поток для работы - и он должен делиться им.И единственный поток, доступный хосту, — это поток, предоставляемый браузером.
Все вызовы служб в 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