【问题标题】:Background Agent notifyComplete() after HTTPRequestHTTPRequest 后的后台代理 notifyComplete()
【发布时间】:2013-10-16 21:40:14
【问题描述】:

我想在 windows phone 7 后台代理中的定期任务上创建一个 HTTPRequest。 为了简单起见,我只想在 backgroundAgent 和应用程序之间的共享类上调用一个方法。

共享方法是一个简单的 HTTPRequest。

在 SharedClass.cs 中 makeTheRequest()

public static void makeTheRequest(){
    var request = (HttpWebRequest)WebRequest.Create(new Uri("http://foo.bar"));
    request.BeginGetResponse(r =>
    {
         NotifyComplete();
    }, request);
}

我无法在此处调用 notifyComplete(),因为不在范围内。

BackgroundAgent.cs onInvoke()

protected override void OnInvoke(ScheduledTask task)
{
     if (task is PeriodicTask)
     {
          SharedClass.makeTheRequest();

          NotifyComplete(); 
     }
}

当我在这里调用它时,可能 makeTheRequest() 永远不会完成,因为该进程在完成之前就被杀死了

我读过一些关于 Taks Parallel library 的内容,但我不知道这是否是正确的做法,也不知道如何去做。

谢谢

【问题讨论】:

    标签: c# silverlight windows-phone-7 httprequest task-parallel-library


    【解决方案1】:

    我会更改您的 makeTheRequest() 方法,以便您可以将 Action 传递给它,以便在请求完成时触发。

    在来自代理的呼叫中,您可以包括对NotifyComplete() 的呼叫,但在应用程序中您不能这样做。

    另请注意,您应该在代理中包含超时处理,因为由于超时,代理内部的请求反复失败,可能会导致代理被禁用。

    更新

    一个例子:

    protected override void OnInvoke(ScheduledTask task)
    {
        if (task is PeriodicTask)
        {
            SharedClass.makeTheRequest(this.NotifyComplete);
        }
    }
    
    public class SharedClass
    {
        public static void makeTheRequest(Action callback)
        {
            var request = (HttpWebRequest)WebRequest.Create(new Uri("http://foo.bar"));
            request.BeginGetResponse(r => callback.Invoke(), request);
        }
    }
    

    【讨论】:

    • 这是一种比使用 TPL 更简单的解决方案。你的意思是像传递回调一样在请求完成时执行?谢谢!
    • @blackjid 是的。又好又简单
    • 我认为 TPL 是要走的路。可能对超时处理有帮助,但对于一个简单的问题来说似乎有点过头了。
    • 如果您想要一种“不错”的方式来添加超时支持(即不使用Timer),请使用异步 CTP 并创建一个调用TaskEx.Delay()的任务
    • CTP 具有上线许可证,因此不应阻止您使用它。但是,是的,作为 CTP,它可能会发生变化。是的,您将使用 awaitasync 关键字,但它们本身不会让您处理超时并确保您在执行时间限制内调用 NotifyComplete()
    【解决方案2】:
    1. 一旦主 bgAgent 线程退出,HttpWebRequest 将被终止。
    2. 我们应该在这里使用同步 HttpWebRequest,但我们不能,因为 MS 将它们从 gelded 框架中拿走了。
    3. 我们必须使用线程同步对象来模拟线程阻塞行为,例如 手动重置事件。
    受保护的覆盖无效 OnInvoke(ScheduledTask 任务) { var evnt = new ManualResetEvent(false);//初始化为无信号状态(false) var request = (HttpWebRequest)WebRequest.Create(new Uri("http://foo.bar")); request.BeginGetResponse(r => { //在这里工作 evnt.Set();//信号主线程继续 }, 要求); evnt.WaitOne();//阻塞主线程执行 通知完成(); 返回; }

    这样,在你完成工作之前,主线程都不会退出,NotifyComplete 也不会被调用。 你应该让 WaitOne 超时(大约 25 秒),以确保你的任务不会因为 30 秒的限制而被杀死和(更糟)取消调度。这将使事情变得更加复杂,因为您必须保护您的两个线程(主线程和 http)不会相互混淆。 此处也未显示 evnt.Close() 问题。主线程可能会在 http 完成之前关闭句柄并尝试 Set()。或者你可以依赖垃圾回收Do I need to call Close() on a ManualResetEvent?

    (顺便说一句,ManualResetEvent 与 C# 事件的概念无关。它是 Win32 意义上的事件,与 Mutex 和 Semaphore 来自同一帮派)。

    【讨论】:

    • 标记为有用,你解决了我这两天让我头疼的问题。
    • 感谢您发布此解决方案,它也是唯一对我有用的解决方案!
    【解决方案3】:

    您必须使用委托

    在 SharedClass.cs 中

     public delegate void MyDelegate();
     public MyDelegate MyUpdate;
    

    在 BackgroundAgent.cs 也许

    void UpdateLiveTile() { ..... NotifyComplete(); }
    

    在BackgroundAgent.cs onInvoke()

    var cs = new SharedClass();
    cs.MyUpdate= new SharedClass.MyDelegate(UpdateLiveTile);
    cs.makeTheRequest();
    

    在公共静态 void makeTheRequest()

    public static void makeTheRequest()
    {
       var request ....
       request.BeginGetResponse(r =>
       {
          .........
          MyUpdate();
       }, request
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多