除非调用线程空闲(方法已完成),否则不会调用 WebRequest 的回调

发布于 2024-11-11 15:08:04 字数 1123 浏览 1 评论 0原文

这是我的代码(它是 Silverlight!):

public class ThreadTester
{
    public void Test()
    {
        Debug.WriteLine("Outer thread start");
        ThreadPool.QueueUserWorkItem(x => RunInner());
        Thread.Sleep(2000);
        Debug.WriteLine("Outer thread end");
    }

    private void RunInner()
    {
        Debug.WriteLine("Inner thread start");

        BL bl = new BL();
        bl.Run1(AssyncCallback);

        Debug.WriteLine("Inner thread end");
    }

    public void AssyncCallback(IAsyncResult ar)
    {
        Debug.WriteLine("Async Callback called!");
    }

}

public class BL
{
    public void Run1(AsyncCallback callback)
    {
        WebRequest req = WebRequest.Create(@"http://microsoft.com");
        req.BeginGetResponse(callback, null);
    }
}

这是我在输出窗口中得到的:

Outer thread start
Inner thread start
Outer thread end
Inner thread end
Async Callback called!

你知道为什么它会这样工作吗?不应该吗

Outer thread start
Inner thread start
Async Callback called!
Inner thread end
Outer thread end

主要重点是回调调用。

提前致谢

Here is my code (It's Silverlight!):

public class ThreadTester
{
    public void Test()
    {
        Debug.WriteLine("Outer thread start");
        ThreadPool.QueueUserWorkItem(x => RunInner());
        Thread.Sleep(2000);
        Debug.WriteLine("Outer thread end");
    }

    private void RunInner()
    {
        Debug.WriteLine("Inner thread start");

        BL bl = new BL();
        bl.Run1(AssyncCallback);

        Debug.WriteLine("Inner thread end");
    }

    public void AssyncCallback(IAsyncResult ar)
    {
        Debug.WriteLine("Async Callback called!");
    }

}

public class BL
{
    public void Run1(AsyncCallback callback)
    {
        WebRequest req = WebRequest.Create(@"http://microsoft.com");
        req.BeginGetResponse(callback, null);
    }
}

This is what I get in output window:

Outer thread start
Inner thread start
Outer thread end
Inner thread end
Async Callback called!

Any ideas why it works that way? Shouldnt it be

Outer thread start
Inner thread start
Async Callback called!
Inner thread end
Outer thread end

Main emphasis is on Callback call.

Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浮华 2024-11-18 15:08:04

回调的要点是,只有在请求完成并收到响应后才调用它。

这似乎花费了超过 2 秒的时间,因此线程结束消息发生在回调之前。

此外,一旦 2 秒结束,外部线程结束 就会被写入,而 RunInner() 内的所有内容都是同步发生的,因此 内部线程结束直到请求完成之后才会显示(但在回调执行之前,因为您使用的是异步BeginGetResponse)。

当我运行相同的代码时,我实际上得到了以下输出:

外螺纹开始
内螺纹起始
内螺纹端部
调用了异步回调!
外螺纹端部

这仅意味着该请求对我而言花费了不到 2 秒的时间。如果将 Thread.Sleep() 值增加几秒,您应该会得到相同的结果。不过,回调是异步调用的,因此内部线程结束消息通常会先于它,但对于异步处理,您不应该依赖它。

如果不清楚,请在评论中告诉我,我会尽力进一步说明。

编辑

现在我看到您正在使用 Silverlight,问题变得更加清晰。我认为,如果您将其实际调用 EndGetResponse(),您最终会得到 SecurityException,因为 Silverlight 希望通过以下方式阻止跨站点脚本攻击:默认。也就是说,如果没有建立允许访问的策略,您将无法访问与 Silverlight 应用程序所在域(例如 microsoft.com 或 google.com)不同的域中的 URL。

这里有安全策略的详细处理:http ://msdn.microsoft.com/en-us/library/cc645032(v=VS.95).aspx

The point of the callback is that it is something to invoke only after your request is complete and your response is received.

This appears to be taking more than 2 seconds, so the thread end messages happen before the callback.

Further, the Outer thread end gets written as soon as the 2 seconds is up, whereas everything within RunInner() happens synchronously, so Inner thread end doesn't show up until after the request is complete (but before the callback executes, because you are using the asynchronous BeginGetResponse).

When I run your same code, I actually get this output:

Outer thread start
Inner thread start
Inner thread end
Async Callback called!
Outer thread end

This just means that the request took less than 2 seconds for me. If you increase your Thread.Sleep() value by a few seconds, you should get the same result. Again, though, the callback is being invoked asynchronously, so the Inner thread end message will typically precede it, but with asynchronous processing you should not rely on that.

Let me know in the comments if this is not clear, and I will try to illustrate further.

edit

Now that I see that you are using Silverlight, the issues are becoming clearer. I think that if you take this through to actually calling EndGetResponse(), you'll end up with a SecurityException, because Silverlight wants to block cross-site scripting attacks, by default. That is, you can't access URLs in domains different than the one in which your Silverlight application lives (like microsoft.com or google.com) without establishing a policy that allows it.

There is a detailed treatment of security policies here: http://msdn.microsoft.com/en-us/library/cc645032(v=VS.95).aspx

兮子 2024-11-18 15:08:04
public partial class MainPage : UserControl
    {
        private WebRequest m_request;
        public MainPage()
        {
            InitializeComponent();
            MessageBox.Show("began!");
            ThreadPool.QueueUserWorkItem(o => Run1(AssyncCallback));

        }

        public void Run1(AsyncCallback callback)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("run called"));
            m_request = WebRequest.Create(@"http://localhost:9892/testGet.htm");
            m_request.BeginGetResponse(callback, null);
            Thread.Sleep(5000);
            Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("finish"));
        }

        public void AssyncCallback(IAsyncResult ar)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("inside"));
            try {
                m_request.EndGetResponse(ar);
                Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("ok"));

            }
            catch (Exception e) {
                Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show(e.Message));
                throw;
            }
        }
    }

在我的本地计算机上运行良好,其中 testGet.htm 是 SL 应用程序的本地计算机。
消息框显示开始,运行调用,内部,确定,然后 5 秒后完成

编辑:

如果我们像您建议的那样进行以下代码更改,您理论上的建议不可能起作用:

public MainPage()
        {
            InitializeComponent();
            MessageBox.Show("began!");
            ThreadPool.QueueUserWorkItem(o => Run1(AssyncCallback));
            Thread.Sleep(5000);
            MessageBox.Show("outer ended")
        }

        public void Run1(AsyncCallback callback)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("run called"));
            m_request = WebRequest.Create(@"http://localhost:9892/testGet.htm");
            m_request.BeginGetResponse(callback, null);
            Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("finish"));
        }

您不能期望显示“outer结束”之前显示的任何消息框,因为

ThreadPool.QueueUserWorkItem(o =>
                {
                    MessageBox.Show("one");
                    Thread.Sleep(5000);
                    MessageBox.Show("one ended");
                });
            ThreadPool.QueueUserWorkItem(o => MessageBox.Show("two"));
            ThreadPool.QueueUserWorkItem(o => MessageBox.Show("three"));

如果ThreadPool MaxThreads为1,它相当于调用。您不能期望“two”会在“one结束”之前显示,它不能在第一个执行的中间注入排队的代表。

public partial class MainPage : UserControl
    {
        private WebRequest m_request;
        public MainPage()
        {
            InitializeComponent();
            MessageBox.Show("began!");
            ThreadPool.QueueUserWorkItem(o => Run1(AssyncCallback));

        }

        public void Run1(AsyncCallback callback)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("run called"));
            m_request = WebRequest.Create(@"http://localhost:9892/testGet.htm");
            m_request.BeginGetResponse(callback, null);
            Thread.Sleep(5000);
            Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("finish"));
        }

        public void AssyncCallback(IAsyncResult ar)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("inside"));
            try {
                m_request.EndGetResponse(ar);
                Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("ok"));

            }
            catch (Exception e) {
                Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show(e.Message));
                throw;
            }
        }
    }

Works fine with my local machine where testGet.htm is local to SL application.
Message boxes are shown began ,run called, inside, ok and then 5 secs later finished

Edit:

What you are suggesting in theory cant possibly work, if we have following code change like u suggest:

public MainPage()
        {
            InitializeComponent();
            MessageBox.Show("began!");
            ThreadPool.QueueUserWorkItem(o => Run1(AssyncCallback));
            Thread.Sleep(5000);
            MessageBox.Show("outer ended")
        }

        public void Run1(AsyncCallback callback)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("run called"));
            m_request = WebRequest.Create(@"http://localhost:9892/testGet.htm");
            m_request.BeginGetResponse(callback, null);
            Deployment.Current.Dispatcher.BeginInvoke(() => MessageBox.Show("finish"));
        }

You cannot expect any message box to be shown before "outer ended" is shown because its equivalent to calling

ThreadPool.QueueUserWorkItem(o =>
                {
                    MessageBox.Show("one");
                    Thread.Sleep(5000);
                    MessageBox.Show("one ended");
                });
            ThreadPool.QueueUserWorkItem(o => MessageBox.Show("two"));
            ThreadPool.QueueUserWorkItem(o => MessageBox.Show("three"));

if ThreadPool MaxThreads was 1. You cannot expect that "two" will be shown before "one ended" , it cannot inject in the middle of execution of first queued delegate.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文