将权限/身份验证复制到子线程......?

Sha*_*aan 17 c# multithreading task-parallel-library silverlight-5.0 dynamics-crm-2011

这是我注意到的非常奇怪的事情.

我正在编写CRM 2011 Silverlight扩展,而且,在我的本地开发实例上一切正常.该应用程序使用OData进行通信,并使用System.Threading.Tasks.Task很多来在后台执行所有操作(FromAsync是一种祝福).

但是,我决定在CRM 2011 Online中测试我的应用程序,并且令我惊讶地发现它将不再起作用; 结束检索任务时,我会收到安全异常.

使用Fiddler,我发现CRM正试图将我重定向到Live登录页面,考虑到我已经登录,这个页面没有多大意义.

经过多次尝试后,我发现错误是因为我从与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;
        });
    }
Run Code Online (Sandbox Code Playgroud)

似乎很明显我缺少一些关于线程如何使用权限的基础知识.由于在我的情况下使用单独的线程是可取的,有没有办法"复制"权限/身份验证?也许是某种模仿?

编辑:如果其他人正在努力解决这个问题,Task只要query.BeginExecute(null, null);在UI线程上执行,就可以使用其他线程(或者视情况而定).您需要一种方法来检索返回IAsyncResult到调用线程,但您可以使用a来执行此操作ManualResetEvent.

但我仍然想知道为什么线程之间不共享darned权限/身份验证...

小智 2

我不太确定这是否有帮助。但我找到了 Jeffrey Richter 第 770 页的描述

\n\n

“与控制台应用程序一样,ASP.NET Web Form 和 XML Web Service 应用程序允许任何线程做任何它想做的事情。当线程池线程开始处理客户端\xe2\x80\x99s\n请求时,它可以假定客户端\ xe2\x80\x99s 区域性 (System.Globalization.CultureInfo),允许 Web 服务器返回数字、日期和时间的区域性特定格式。5 此外,Web 服务器可以采用客户端\xe2\x80\ x99s 标识 (System.Security.Principal.\nIPrincipal),以便服务器只能访问允许客户端\n访问的资源。当线程池线程生成异步操作时,\n它将由另一个线程池线程完成\n ,它将处理异步操作的结果。\n当代表原始客户端请求执行此工作时,区域性\n和身份信息默认情况下不会\xe2\x80\x99 流到新的线程池线程,因此代表客户端完成的任何\n其他工作现在不使用客户端\xe2\x80\x99s 文化和身份\n信息。理想情况下,我们希望文化和身份信息流向仍在代表同一客户端工作的其他线程\n池线程。”

\n\n

这是他的例子,我希望这会有所帮助。

\n\n
private static AsyncCallback SyncContextCallback(AsyncCallback callback) \n{\n  SynchronizationContext sc = SynchronizationContext.Current;\n  // If there is no SC, just return what was passed in\n  if (sc == null) return callback;\n  // Return a delegate that, when invoked, posts to the captured SC a method that\n  // calls the original AsyncCallback passing it the IAsyncResult argument\n  return asyncResult => sc.Post(result => callback((IAsyncResult)result), asyncResult);\n}\n\nprotected override void OnMouseClick(MouseEventArgs e) {\n  // The GUI thread initiates the asynchronous Web request\n  Text = "Web request initiated";\n  var webRequest = WebRequest.Create("http://Wintellect.com/");\n  webRequest.BeginGetResponse(SyncContextCallback(ProcessWebResponse), webRequest);\n  base.OnMouseClick(e);\n}\n\nprivate void ProcessWebResponse(IAsyncResult result) {\n  // If we get here, this must be the GUI thread, it\'s OK to update the UI\n  var webRequest = (WebRequest)result.AsyncState;\n  using (var webResponse = webRequest.EndGetResponse(result)) {\n      Text = "Content length: " + webResponse.ContentLength;\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是我在我的应用程序中使用的

\n\n
 public override void UpdateCanvas(object parameter)\n {\n      Action<GraphPane> startToUpdate = StartToUpdate;\n       GraphPane selectedPane = Canvas.HostingPane.PaneList.Find(p =>  p.Title.Text.Equals(defaultPanTitle));\n       startToUpdate.BeginInvoke(selectedPane, FormSyncContext.SyncContextCallback(RefreshCanvas), selectedPane);\n }\n\n public static AsyncCallback SyncContextCallback(AsyncCallback callback)\n {\n       // Capture the calling thread\'s SynchronizationContext-derived object\n       SynchronizationContext sc = SynchronizationContext.Current;\n\n       // If there is no SC, just return what was passed in\n       if (sc == null) return callback;\n\n       // Return a delegate that, when invoked, posts to the captured SC a method that\n       // calls the original AsyncCallback passing it the IAsyncResult argument\n       return asyncResult => sc.Post(result => callback((IAsyncResult)result), asyncResult);\n }\n
Run Code Online (Sandbox Code Playgroud)\n