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; 
     }); 
    } 

내가 스레드 권한을 사용하는 방법에 대한 몇 가지 기본 사항을 누락하는 것이 거의 확실한 것 같다

여기에 빠른 예입니다. 필자의 경우 별도의 스레드를 사용하는 것이 바람직하므로 권한/인증을 "복사"할 수있는 방법이 있습니까? 아마 어떤 종류의 가장 (impersonation)일까요?

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 응용 프로그램과 마찬가지로 ASP.NET 웹 양식과 XML 웹 서비스 응용 프로그램을 사용하면 원하는 모든 작업을 수행 할 수 있습니다. 스레드 풀 스레드가 클라이언트의 처리를 시작하면 요청을 사용하면 클라이언트의 문화권 (System.Globalization.CultureInfo)을 가정 할 수 있으므로 웹 서버는 숫자, 날짜 및 시간에 대한 문화권 별 서식을 반환 할 수 있습니다 .5 또한 웹 서버는 클라이언트의 ID System.Security.Principal. IPrincipal) 서버가 클라이언트가 액세스를 허용하는 리소스에만 액세스 할 수 있도록합니다. 스레드 풀 스레드가 비동기 작업을 생성하면 012가 완료됩니다다른 스레드 풀 스레드가 비동기 작업의 결과를 처리합니다. 이 작업이 원래 클라이언트 요청을 대신하여 수행되는 동안 culture 및 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); 
} 
관련 문제