加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – 在ASP.NET MVC中未调用WebClient异步回调

发布时间:2020-12-16 07:03:23 所属栏目:asp.Net 来源:网络整理
导读:在GET请求我运行(类似): public ActionResult Index(void) { webClient.DownloadStringComplete += onComplete; webClient.DownloadStringAsync(...); return null;} 我发现直到Index()完成执行后才会调用onComplete. 我可以看到onComplete是在一个不同的线
在GET请求我运行(类似):

public ActionResult Index(void) {
    webClient.DownloadStringComplete += onComplete;
    webClient.DownloadStringAsync(...);
    return null;
}

我发现直到Index()完成执行后才会调用onComplete.
我可以看到onComplete是在一个不同的线程上调用的,而是执行了一个索引.

问题:为什么会发生这种情况?为什么webClient的异步线程显然被阻塞,直到请求处理线程完成?

有没有办法解决这个问题,而无需从ThreadPool启动新线程(我试过这个,并且使用线程池确实按预期工作.如果从ThreadPool的线程调用DownloadStringAsync,webClient的回调确实按预期发生).

ASP.NET MVC 3.0,.NET 4.0,MS Cassini开发Web服务器(VS 2010)

编辑:这是一个完整的代码:

public class HomeController : Controller {
    private static ManualResetEvent done;

    public ActionResult Index() {
        return Content(DownloadString() ? "success" : "failure");
    }

    private static bool DownloadString() {
        try {
            done = new ManualResetEvent(false);
            var wc = new WebClient();
            wc.DownloadStringCompleted += (sender,args) => { 
                // this breakpoint is not hit until after Index() returns.
                // It is weird though,because response isn't returned to the client (browser) until this callback finishes.
                // Note: This thread is different from one Index() was running on.
                done.Set(); 
            };

            var uri = new Uri(@"http://us.battle.net/wow/en/character/blackrock/hunt/simple");

            wc.DownloadStringAsync(uri);

            var timedout = !done.WaitOne(3000);
            if (timedout) {
                wc.CancelAsync();
                // if this would be .WaitOne() instead then deadlock occurs.
                var timedout2 = !done.WaitOne(3000); 
                Console.WriteLine(timedout2);
                return !timedout2;
            }
            return true;
        }
        catch (Exception ex) {
            Console.WriteLine(ex.Message);
        }
        return false;
    }
}

解决方法

我很好奇,所以我询问了Microsoft内部的ASP.NET讨论别名,并得到了Levi Broderick的回复:

ASP.NET internally uses the
SynchronizationContext for
synchronization,and only one thread
at a time is ever allowed to have
control of that lock. In your
particular example,the thread running
HomeController::DownloadString holds
the lock,but it’s waiting for the
ManualResetEvent to be fired. The
ManualResetEvent won’t be fired until
the DownloadStringCompleted method
runs,but that method runs on a
different thread that can’t ever take
the synchronization lock because the
first thread still holds it. You’re
now deadlocked.

I’m surprised that this ever worked in MVC 2,but if it did it was only by happy accident. This was never supported.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读