17

Đây là điều gì đó rất lạ mà tôi đã nhận thấy.Sao chép quyền/xác thực vào chủ đề con ...?

Tôi đang viết một phần mở rộng Silverlight CRM 2011 và, tốt, tất cả đều tốt trên phiên bản phát triển cục bộ của tôi. Ứng dụng sử dụng OData để giao tiếp, và sử dụng System.Threading.Tasks.Task rất nhiều để thực hiện tất cả các hoạt động trong nền (FromAsync là một phước lành).

Tuy nhiên, tôi đã quyết định thử nghiệm đơn đăng ký của mình trong CRM 2011 Online và thấy rằng, với sự ngạc nhiên của tôi, điều đó sẽ không còn hoạt động nữa; Tôi sẽ nhận được một ngoại lệ bảo mật khi kết thúc nhiệm vụ truy xuất.

Sử dụng Fiddler, tôi thấy rằng CRM đang cố gắng chuyển hướng tôi đến trang đăng nhập trực tiếp, mà không có ý nghĩa nhiều, xem xét tôi đã được đăng nhập.

Sau một số nỗ lực nhiều hơn, tôi phát hiện ra rằng lỗi là vì tôi đã truy cập dịch vụ từ một chuỗi khác với chuỗi giao diện người dùng.

Dưới đây là một ví dụ nhanh:

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

Có vẻ như gần như rõ ràng rằng tôi đang thiếu một số nguyên tắc cơ bản về cách sử dụng bài quyền. Kể từ khi sử dụng một thread riêng biệt là thích hợp hơn trong trường hợp của tôi, có cách nào để "sao chép" các điều khoản/xác thực? Có lẽ một số loại mạo danh?

EDIT: Trong trường hợp bất kỳ ai đang đấu tranh với điều này, sử dụng các chủ đề khác (hoặc Task, tùy từng trường hợp) có thể miễn là query.BeginExecute(null, null); được thực hiện trên chuỗi giao diện người dùng. Bạn cần một cách để truy xuất trả lại IAsyncResult quay lại chuỗi cuộc gọi, nhưng bạn có thể thực hiện điều đó bằng cách sử dụng ManualResetEvent.

Nhưng tôi vẫn muốn biết lý do tại sao các điều khoản darned/chứng thực không được chia sẻ giữa các chủ đề ...

+1

Nó có thể liên quan đến [Context Execution hiện chủ đề của] sự (http://msdn.microsoft.com/en-us/library /system.threading.thread.executioncontext). – shambulator

+0

Rất có thể, tuy nhiên tôi muốn chỉ ra rằng khi kiểm tra mã của tôi trên máy chủ CRM tại chỗ, tại chỗ mọi thứ hoạt động tốt. Vì vậy, nó vẫn còn chưa rõ ràng như những gì chính xác đang xảy ra. – Shaamaan

Trả lời

2

Tôi không hoàn toàn chắc chắn, là điều này sẽ giúp. Nhưng tôi đã tìm thấy một mô tả từ trang của Jeffrey Richter 770

"Giống như các ứng dụng giao diện điều khiển, Ứng dụng Web ASP.NET và các ứng dụng Dịch vụ web XML cho phép bất kỳ chủ đề nào để làm bất cứ điều gì nó muốn. yêu cầu, nó có thể giả định văn hóa của khách hàng (System.Globalization.CultureInfo), cho phép máy chủ Web trả về định dạng văn hóa cụ thể cho số, ngày và thời gian.5. System.Security.Principal. IPrincipal) để máy chủ có thể truy cập chỉ các tài nguyên mà máy khách được phép truy cập . Khi một luồng thread thread sinh ra một hoạt động không đồng bộ, nó sẽ được hoàn thành bởi một chuỗi chủ đề khác, sẽ xử lý kết quả của một thao tác không đồng bộ. Trong khi tác vụ này đang được thực hiện thay mặt cho yêu cầu của khách hàng ban đầu, văn bản và thông tin nhận dạng không chuyển sang luồng hồ bơi chủ đề mới theo mặc định, vì vậy bất kỳ công việc bổ sung nào được thực hiện thay mặt cho khách hàng hiện không sử dụng máy khách văn hóa và bản sắc thông tin. Lý tưởng nhất, chúng tôi muốn văn hóa và thông tin nhận dạng được chuyển đến chủ đề khác của chủ đề hồ bơi vẫn đang hoạt động thay mặt cho cùng một khách hàng. "

Và đây là ví dụ của ông ấy, tôi hy vọng điều này sẽ hữu ích.

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

Và đây là những gì tôi đang sử dụng trong ứng dụng của tôi

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); 
} 
Các vấn đề liên quan