2014-02-20 30 views
1

我有兴趣在解决方案中找到处理Silverlight异步调用链接的空白。请让我知道,如果你发现解决方案中的差距/问题。或者,如果有其他方法/模式来解决问题,请指出我的正确方向。异步调用跟踪

代码没有编译或测试

问题

我们有一个要求,做一些动作异步调用的一堆完成后。

例如,一旦服务调用完成,就将默认值分配给UI控件。

void Fun() 
{ 
    Servicecall1(); 
    Servicecall2(); 

    //Make sure the following is executed only after the previous async calls are finished. 
    AssignDefaultValues(); 
} 

解决方案

的一种方式做,这是链接服务,通过调用回调。不过,我只是想知道它是如何通过像下面这样的特殊异步执行跟踪类的对象来实现它。

class SomeClass 
{ 
    AsyncMehodCallWatcher _methodcallwatcher = new AsyncMehodCallWatcher();    

     void fun() 
     { 
     _methodcallwatcher.AsyncMethodStartMultipleCall(() => 
      { 
      //this function will be called automatically after the following service calls 
      AssignDefaultValues(); 
      }, 2); 

     Servicecall1(); 
     Servicecall2(); 
     } 

     void Servicecall1() 
     { 
      serviceclient.DoSomething(DoSomethingcallback); 

     } 

     void DoSomethingcallback(object sender, GetCompletedEventArgs arg) 
     { 
      _methodcallwatcher.AsyncCallCompleted(); 
     } 

     void Servicecall2() 
     { 
      serviceclient.DoSomething(DoSomething2callback); 

     } 

     void DoSomething2callback(object sender, GetCompletedEventArgs arg) 
     { 
      _methodcallwatcher.AsyncCallCompleted(); 
     } 
} 

任何人谁需要调用Servicecall1(),或Servicecall2()应该调用AsyncMethodPreCall(空)。

这里是所提出的实现AsyncMehodCallWatcher

public class AsyncMehodCallWatcher 
    { 
     private int _counter = 0; 

     public AsyncMehodCallWatcher() 
     { 
     } 

     public void AsyncMethodPreCall() 
     { 
      AsyncMethodPreCall(null); 
     } 

     Action _callcompletedaction = null;  

     public void AsyncMethodStartMultipleCall(Action action, int numofcalls) 
     { 
      if (action != null) 
      { 
       if (_callcompletedaction != null) 
       { 
        throw new InvalidOperationException(LocalString.AsyncMehodCallWatcherErrorAsyncCalls); 
       } 

       _callcompletedaction = action;    
       _counter = numofcalls; 
      } 
     } 

     public void AsyncMethodPreCall(Action action) 
     { 
      if (action != null) 
      { 
       if (_callcompletedaction != null) 
       { 
        throw new InvalidOperationException(LocalString.AsyncMehodCallWatcherErrorAsyncCalls); 
       } 
       _callcompletedaction = action;    
      } 
      _counter++;   
     } 

     public void AsyncCallCompleted() 
     { 
      _counter--; 

      if (_counter < 0) 
      { 
       throw new InvalidOperationException(LocalString.AsyncMehodCallWatcherErrorAsyncCalls); 
      } 

      if (_counter == 0) 
      { 
       if (_callcompletedaction != null) 
       { 
        _callcompletedaction(); 
        _callcompletedaction = null;     
       } 
      }   
     } 

    } 
+0

问题是什么 – Sajeetharan

+0

对于所提到的问题,提出的解决方案是可接受的还是其他任何方式? – Jimmy

+0

您针对Silverlight Noseratio

回答

1

下面是我在评论这个问题的意思是:

Task<GetCompletedEventArgs> CallServiceAsync(
    Action<Action<object, GetCompletedEventArgs> callDoSomething) 
{ 
    var tcs = new TaskCompletionSource<GetCompletedEventArgs>(); 
    callDoSomething((sender, arg) => tcs.SetResult(arg)); 
    return tcs.Task; 
} 

async Task AsyncMethodStartMultipleCall(ServiceClient client) 
{ 
    var task1 = CallServiceAsync((callback) => client.DoSomething(callback)); 
    var task2 = CallServiceAsync((callback) => client.DoSomething(callback)); 
    var task3 = CallServiceAsync((callback) => client.DoSomething(callback)); 

    await Task.WhenAll(task1, task2, task3); 
} 

我强烈建议使用Microsoft.Bcl.Async的Silverlight 4和.NET 4.0。它会给你async/await,如果你使用VS2012 +。如果您因任何原因无法使用该文件,请使用ContinueWhenAll或查阅Stephen Toub的Then pattern,如果完成顺序很重要。例如:

Task AsyncMethodStartMultipleCall(ServiceClient client) 
{ 
    var task1 = CallServiceAsync((callback) => client.DoSomething(callback)); 
    var task2 = CallServiceAsync((callback) => client.DoSomething(callback)); 
    var task3 = CallServiceAsync((callback) => client.DoSomething(callback)); 

    return TaskFactory.ContinueWhenAll(new [] { task1, task2, task3 }, (tasks) => 
    { 
     Debug.Print("All completed!"); 
    }); 
} 

如果你不打算use async/await,确保你从UI线程保存TaskScheduler.FromCurrentSynchronizationContext(),并将它传递给ContinueWhenAllContinueWith,否则你的延续拉姆达可能会在池中的线​​程调用。

+0

@Noserito,请注意我们仍然在.net 4,仍然没有异步并等待 – Jimmy

+0

@Jimmy,我强烈建议使用['Microsoft.Bcl.Async'](http://www.nuget.org/packages/microsoft .bcl.async)用于Silverlight 4和.NET 4.0。如果你使用VS2012 +,它会给你'async/await'。如果您因任何原因无法使用该功能,请参阅Stephen Toub的['Then' pattern](http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx)。 – Noseratio

+0

@Noserito,不幸的是我们仍然在2010年。希望我们会尽快升级。现在,按照Stephen Toub的方法 – Jimmy

1

的如果使用任务并行库,你可以把你的基于回调方法为使用基于TaskCompletionSource任务的方法。这是一个例子。

public class SomeClass 
{ 
    public async Task Fun() 
    { 
     // execute both service requests at the same time 
     Task<Result> fooTask = ServiceCallAsync1(); 
     Task<Result> barTask = ServiceCallAsync2(); 

     // wait for both of them to be complete. 
     Result[] t = await Task.WhenAll(new[] { fooTask, barTask }); 
     AssignDefaultValues(); 
    } 

    public Task<Result> ServiceCallAsync1() 
    { 
     TaskCompletionSource<Result> completion = new TaskCompletionSource<Result>(); 
     serviceclient.DoSomething(() => 
     { 
      completion.SetResult(new FooResult()); 
     }); 
     return completion.Task; 
    } 

    public Task<Result> ServiceCallAsync2() 
    { 
     TaskCompletionSource<Result> completion = new TaskCompletionSource<Result>(); 
     serviceclient.DoSomething(() => 
     { 
      completion.SetResult(new BarResult()); 
     }); 
     return completion.Task; 
    } 

    private void AssignDefaultValues() 
    { 
    } 
} 
+0

请注意,我们仍然在.net 4,所以没有异步,并等待 – Jimmy

+1

哦,但你可以!您可以使用[Microsoft.Bcl.Async](https://www.nuget.org/packages/Microsoft.Bcl.Async)nuget包! –