17

ここに私が気づくだろう非常に奇妙なものがあります。子スレッドへのアクセス許可/認証をコピーしますか?

私はCRM 2011 Silverlight拡張機能を作成しています。ローカル開発インスタンスではすべて問題ありません。アプリケーションはODataを使用して通信し、背景ですべての操作を実行するために多くの場合System.Threading.Tasks.Taskを使用します(FromAsyncは祝福です)。

しかし、私はCRM 2011 Onlineで自分のアプリケーションをテストすることにしました。私の驚いたことに、もはや機能しなくなりました。私は検索タスクを終了するときにセキュリティ例外を受け取ります。私はCRMは私が既にログインして考えると、あまり意味がありませんでしたライブログインページ、に私をリダイレクトしようとしていることがわかったフィドラーを使用して

、。

は、いくつかのより多くの試行の後、私が発見しましたUIスレッドとは別のスレッドからサービスにアクセスしていたためにエラーが発生しました。

//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:他の誰かがこれに苦労している場合は、query.BeginExecute(null, null);がUIスレッド上で実行されている限り、他のスレッド(場合によってはTask)を使用することができます。返されたIAsyncResultを呼び出し元のスレッドに戻す方法が必要ですが、ManualResetEventを使用してこれを行うことができます。

しかし、私はまだ私はかなりわからない

+1

を使用していますそれはおそらく[現在のスレッドの実行コンテキスト]に関連する何である(http://msdn.microsoft.com/en-us/library /system.threading.thread.executioncontext)。 – shambulator

+0

かなり可能ですが、ローカルの社内CRMサーバーで自分のコードをテストすると、すべて正常に動作することを指摘したいと思います。だから、正確に何が起こっているのかはまだ不明です。 – Shaamaan

答えて

2

...とびきりの許可/認証はスレッド間で共有されていない理由を知りたいのですが、これは役立ちますです。しかし、私は、Jeffrey Richterの説明を見つけました。ページ770

"ASP.NET WebフォームとXML Webサービスアプリケーションでは、任意のスレッドが任意のスレッドを実行できるようになっています。 リクエストでは、クライアントのカルチャ(System.Globalization.CultureInfo)を引き継ぎ、 Webサーバーが番号、日付、および時刻のカルチャ固有の書式設定を返すことを許可します.5さらに、 では、WebサーバーはクライアントのID System.Security.Principal。 IPrincipal)クライアントが へのアクセスを許可されているリソースのみにアクセスできるようにします。スレッドプールスレッドが非同期操作を開始すると、完了します は、非同期操作の結果を処理する別のスレッドプールスレッドによって呼び出されます。 この作業は元のクライアント要求に代わって実行されますが、文化 とID情報はデフォルトで新しいスレッドプールスレッドには流れません。したがって、クライアントに代わって の追加作業が行われています。文化とアイデンティティ 理想的には、文化とアイデンティティ情報を他のスレッド プールスレッドに流して、同じクライアントの代わりにまだ動作しているプールスレッドにしたいと思っています。」と語っています。

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's 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's 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); 
} 
関連する問題