Вот кое-что очень странное, что я заметил.
Я пишу расширение CRM 2011 Silverlight, и в моем локальном экземпляре разработки все в порядке. Приложение использует OData для связи и много использует System.Threading.Tasks.Task
для выполнения всех операций в фоновом режиме (FromAsync
— это благословение).
Однако я решил протестировать свое приложение в CRM 2011 Online и, к своему удивлению, обнаружил, что оно больше не работает; Я получил бы исключение безопасности при завершении задач извлечения.
Используя Fiddler, я обнаружил, что CRM пытается перенаправить меня на страницу входа в Live, что не имело особого смысла, учитывая, что я уже вошел в систему.
После еще нескольких попыток я обнаружил, что ошибки потому что я обращался к сервису из потока, отличного от потока пользовательского интерфейса.
Вот небольшой пример:
//this will work
private void button1_Click(object sender, RoutedEventArgs e)
{
var query = ctx.AccountSet;
query.BeginExecute((result) =>
{
textBox1.Text = query.EndExecute(result).First().Name;
}, null);
}
//this will fail
private void button2_Click(object sender, RoutedEventArgs e)
{
System.Threading.Tasks.Task.Factory.StartNew(RestAsync);
}
void RestAsync()
{
var query = ctx.AccountSet;
var async = query.BeginExecute(null, null);
var task = System.Threading.Tasks.Task.Factory.FromAsync<Account>(async, (result) =>
{
return query.EndExecute(result).First(); // <- Exception thrown here
});
textBox1.Dispatcher.BeginInvoke(() =>
{
textBox1.Text = task.Result.Name;
});
}
Кажется почти очевидным, что я упускаю некоторые основы того, как потоки используют разрешения. Поскольку в моем случае предпочтительнее использовать отдельный поток, есть ли способ «скопировать» разрешения/аутентификацию? Может быть, какое-то подражание?
РЕДАКТИРОВАТЬ: В случае, если кто-то еще борется с этим, использование других потоков (или Task
, в зависимости от обстоятельств) возможно до тех пор, пока query.BeginExecute(null, null);
выполняется в потоке пользовательского интерфейса. Вам нужен способ получить возвращенный IAsyncResult
обратно в вызывающий поток, но вы можете сделать это с помощью ManualResetEvent
.
Но я все же хотел бы знать, почему проклятые разрешения/аутентификация не распределяются между потоками...