3

I want to create an HTTPRequest on a periodic task in a windows phone 7 background agent. To keep it simple I just want to call a method on a shared class between the backgroundAgent and the application.

The shared method is a simple HTTPRequest.

On the SharedClass.cs makeTheRequest()

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

I cannot call the notifyComplete() here because is not in the scope.

On the BackgroundAgent.cs onInvoke()

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

          NotifyComplete(); 
     }
}

When I call it here, probably makeTheRequest() never gets done because the process is killed before it gets completed

I have read something about Taks Parallel library, but I don't know if thas is the right way to do it nor how to do it.

thanks

blackjid
  • 1,571
  • 16
  • 23

3 Answers3

4

I'd change your makeTheRequest() method so that you can pass it an Action to fire upon request completion.

In the call from the agent you can include the call to NotifyComplete() but from the app you don't do this.

Note also that you should include timeout handling in the agent as repeated failing of the request from within the agent, due to timing out, can lead to the agent being disabled.

Update

An Example:

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);
    }
}
Matt Lacey
  • 65,560
  • 11
  • 91
  • 143
  • That's a way simpler solution than using TPL.. You mean like passing a callback the to be executed upon request completion? Thanks! – blackjid Dec 05 '11 at 13:42
  • @blackjid yep. nice and simple – Matt Lacey Dec 05 '11 at 13:44
  • I thought that TPL was the way to go. May be it helps with the timeout handling, but it's seems like overkill for a simple problem. – blackjid Dec 05 '11 at 13:48
  • If you want a "nice" way to add timeout support (i.e. without using a `Timer`) use the async CTP and create a task which calls `TaskEx.Delay()` – Matt Lacey Dec 05 '11 at 16:17
  • It is safe to use async CTP in a production code? since is not ready yet? – blackjid Dec 05 '11 at 17:43
  • Hey @matt, why not just to use the task and await and async keyword in the AsyncCTP? – blackjid Dec 05 '11 at 22:09
  • 1
    The CTP has a go live license so that shouldn't stop you using it. But yes, as a CTP it's subject to change. Yes, you'll use the `await` and `async` keywords but on their own they won't let you handle timeouts and ensure that you're calling `NotifyComplete()` within the execution time limit. – Matt Lacey Dec 07 '11 at 11:46
  • @PhilippeMaes added example – Matt Lacey Oct 16 '13 at 13:40
3
  1. Once the main bgAgent thread exits, the HttpWebRequest will be killed.
  2. We should be using synchronous HttpWebRequest here, but we can't because MS took them away from gelded framework.
  3. We have to mimic thread-blocking behaviour using thread synchronization objects, like ManualResetEvent.

    protected override void OnInvoke(ScheduledTask task)
    {
        var evnt = new ManualResetEvent(false);//initialize to unsignalled state (false)
        var request = (HttpWebRequest)WebRequest.Create(new Uri("http://foo.bar"));
        request.BeginGetResponse(r =>
        {
           //do work here
           evnt.Set();//signal main thread to continue 
        }, request);

        evnt.WaitOne();//block execution of main thread

        NotifyComplete();
        return;
    }

This way neither main thread will exit not NotifyComplete will be called before you finish your work. You should make that WaitOne with a timeout (around 25 seconds) to ensure your task won't get killed and (worse) unsheduled because of 30 secs limit. This will make things much more complicated, as you'll have to protect your both threads (main and http) from messing each other up. The evnt.Close() issue is also not shown here. Main thread may close the handle before http finishes and tries to Set(). Or you can rely on garbage collection Do I need to call Close() on a ManualResetEvent?

(btw, ManualResetEvent has nothing to do with concept of C# event. It's and event in Win32 sense, from same gang as Mutex and Semaphore).

Community
  • 1
  • 1
Agent_L
  • 4,960
  • 28
  • 30
1

You MUST use Delegate

In SharedClass.cs

 public delegate void MyDelegate();
 public MyDelegate MyUpdate;

In BackgroundAgent.cs Maybe

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

In BackgroundAgent.cs onInvoke()

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

In public static void makeTheRequest()

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