Синхронные вызовы ADO.NET для устройств данных в Silverlight - PullRequest
2 голосов
/ 09 декабря 2008

Я использую устройства данных 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? Есть ли обходной путь для этого?

Ответы [ 4 ]

3 голосов
/ 08 октября 2009

Мне удалось победить (: P) асинхронного монстра в серебряном свете, вот так:

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 line line поместите код, который использует захваченные ссылки r1 и r2, которые будут содержать данные или ноль, если результат не удался.

1 голос
/ 09 декабря 2008

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

1 голос
/ 09 декабря 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

1 голос
/ 09 декабря 2008

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

...