Подтвердить что ты не робот

Разрешить копирование/аутентификацию для дочерних потоков...?

Здесь что-то очень странное, что я заметил.

Я пишу 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;
        });
    }

Кажется почти очевидным, что у меня отсутствуют некоторые основы того, как потоки используют разрешения. Так как использование отдельного потока предпочтительнее в моем случае, есть ли способ "скопировать" разрешения/аутентификацию? Возможно, какая-то олицетворение?

EDIT: если кто-то еще борется с этим, возможно использование других потоков (или Task, если это возможно), если в потоке пользовательского интерфейса выполняется query.BeginExecute(null, null);. Вам нужен способ вернуть возвращенный IAsyncResult обратно в вызывающий поток, но вы можете сделать это с помощью ManualResetEvent.

Но я все равно хотел бы знать, почему чернильные разрешения/аутентификация не разделяются между потоками...

4b9b3361

Ответ 1

Я не совсем уверен, это поможет. Но я нашел описание Джеффри Рихтера стр. 770

"Подобно консольным приложениям, приложения ASP.NET Web Form и XML Web Service позволяют любой поток, чтобы делать все, что он хочет. Когда поток пула потоков начинает обрабатывать клиенты запрос, он может предполагать культуру клиентов (System.Globalization.CultureInfo), позволяя веб-сервер, чтобы возвращать специфическое для культуры форматирование чисел, дат и времени .5 В Кроме того, веб-сервер может принимать идентификаторы клиентов (System.Security.Principal. IPrincipal), чтобы сервер мог получить доступ только к ресурсам, доступным для клиента доступ. Когда поток потока потока генерирует асинхронную операцию, он будет завершен другим потоком пула потоков, который будет обрабатывать результат асинхронной операции. Хотя эта работа выполняется от имени первоначального запроса клиента, культура и идентификационная информация по умолчанию не поступает к потоку пула потоков, поэтому любые дополнительная работа, выполненная от имени клиента, теперь не использует культуру и личность клиентов Информация. В идеале мы хотим, чтобы информация о культуре и идентичности перетекала в другую нить пул потоков, которые все еще выполняют работу от имени одного и того же клиента ".

И вот его пример, я надеюсь, что это поможет.

private static AsyncCallback SyncContextCallback(AsyncCallback callback) 
{
  SynchronizationContext sc = SynchronizationContext.Current;
  // If there is no SC, just return what was passed in
  if (sc == null) return callback;
  // Return a delegate that, when invoked, posts to the captured SC a method that
  // calls the original AsyncCallback passing it the IAsyncResult argument
  return asyncResult => sc.Post(result => callback((IAsyncResult)result), asyncResult);
}

protected override void OnMouseClick(MouseEventArgs e) {
  // The GUI thread initiates the asynchronous Web request
  Text = "Web request initiated";
  var webRequest = WebRequest.Create("http://Wintellect.com/");
  webRequest.BeginGetResponse(SyncContextCallback(ProcessWebResponse), webRequest);
  base.OnMouseClick(e);
}

private void ProcessWebResponse(IAsyncResult result) {
  // If we get here, this must be the GUI thread, it OK to update the UI
  var webRequest = (WebRequest)result.AsyncState;
  using (var webResponse = webRequest.EndGetResponse(result)) {
      Text = "Content length: " + webResponse.ContentLength;
  }
}

И вот что я использую в своем приложении

 public override void UpdateCanvas(object parameter)
 {
      Action<GraphPane> startToUpdate = StartToUpdate;
       GraphPane selectedPane = Canvas.HostingPane.PaneList.Find(p =>  p.Title.Text.Equals(defaultPanTitle));
       startToUpdate.BeginInvoke(selectedPane, FormSyncContext.SyncContextCallback(RefreshCanvas), selectedPane);
 }

 public static AsyncCallback SyncContextCallback(AsyncCallback callback)
 {
       // Capture the calling thread SynchronizationContext-derived object
       SynchronizationContext sc = SynchronizationContext.Current;

       // If there is no SC, just return what was passed in
       if (sc == null) return callback;

       // Return a delegate that, when invoked, posts to the captured SC a method that
       // calls the original AsyncCallback passing it the IAsyncResult argument
       return asyncResult => sc.Post(result => callback((IAsyncResult)result), asyncResult);
 }