2011-11-25 65 views
0

有誰知道我會如何使用Reactive Extensions調用RIA InvokeOperation?一旦呼叫全部完成,我需要在Silverlight中處理來自多個異步呼叫的一些數據。在我的測試中,我將幾個字符串與一個查詢的結果組合在一起,現在需要將調用的結果添加到RIA域服務調用方法中,並且被卡住了。如何使用Reactive Extensions在域服務中調用Silverlight RIA InvokeOperation?

在RIA領域服務端(完成非RX風格)我簡單的測試功能如下:

[Invoke] 
    public string DomainServiceFunction() 
    { 
     return "hello"; 
    } 

在客戶端的代碼,這個老派位調用該方法,而且是我想與RX實現部分:

private void CallDomainServiceFunction(object sender, RoutedEventArgs e) 
    { 
     DomainService1 DomainContext = new DomainService1(); 
     InvokeOperation invokeOp = DomainContext.DomainServiceFunction(OnInvokeCompleted, null); 
    } 

    private void OnInvokeCompleted(InvokeOperation invOp) 
    { 
     Debug.WriteLine(invOp.Value);//This prints "hello". 
    } 

我寫了從多個來源的數據組合(這是我想補充的RIA調用的invokeOperation爲好)一些測試代碼。它使一個元組了幾個字符串,並通過查詢返回的實體:

private void PrintProperty1() 
    { 
     GISDomainContext DomainContext = new GISDomainContext(); 
     //Query the database to get information for a property using the folio number. 
     var loadProperty = from loadOperation in DomainContextExtensions 
       .LoadAsync(DomainContext, DomainContext.GetPropertyNoOwnersByFolioQuery("19401006.000")) 
          select loadOperation; 
     //Zip up the property entity with a string for testing purposes. 
     var Data = Observable.Return("a bit of text ") 
      .Zip((Observable.Return("some more text") 
      .Zip(loadProperty, (a, b) => Tuple.Create(a, b))), (a,b) => Tuple.Create(a,b)); 
     //Add a bit more stuff just to show it can be done. 

     //THIS IS WHERE I WOULD ALSO ZIP WITH THE VALUE RETURNED FROM AN InvokeOperation. 

     Data.Subscribe 
     (
      //When all the required data are prepared then proceed... 
      r => //On Next 
      { 
       Debug.WriteLine("OnNext: " + r.Item1 + ", " + r.Item2.Item1 + ", " + r.Item2.Item2.Entities.First().folio.ToString()); 
       //results: "OnNext: a bit of text , some more text, 19401006.000" 
       //At this point the data are all now available for further processing. 
      }, 
      r => //On Error 
      { 
       Debug.WriteLine("Error in PrintProperty1: " + r.ToString()); 
      }, 
      () =>//On Completed 
      { 
       Debug.WriteLine("Completed PrintProperty1"); 
      } 
     ); 
    } 

我懷疑FromAsyncPattern是關鍵,但顯然Silverlight中隱藏的開始/結束調用FromAsyncPattern預計作爲參數

here報價:

「Silverlight的一個重要的注意

Silverlight的Web服務!生成的客戶端代碼有點煩人 - 它隱藏了 BeginXXXX/EndXXXX調用,大概是爲了使Intellisense 更清潔。然而,他們不走了,你可以讓他們回來的路上是 通過鑄造MyCoolServiceClient對象到它的底層接口 (即LanguageServiceClient對象有它實現了一個產生 ILanguageServiceClient界面)」

任何建議?

回答

1

其實,Silverlight是沒有隱瞞任何東西。這些方法只是不通過的RIA Services工具生成的DomainContext來源的代理存在。

但這裏有一個包裝的擴展方法操作成IObservable

public static class DomainContextExtensions 
{ 
    // The method takes in an invoke operation proxy method delegate 
    // and returns an observable sequence factory 
    public static Func<T1, IObservable<TResult>> FromInvokeOperation<T1, TResult> 
    (Func<T1, Action<InvokeOperation<TResult>>, object, InvokeOperation<TResult>> operationDelegate) 
    { 
    Contract.Requires<ArgumentNullException>(operationDelegate != null, "operationDelegate"); 
    Contract.Ensures(Contract.Result<Func<T1, IObservable<TResult>>>() != null); 

    return x1 => 
     { 
     // the subject is a storage for the result. 
     var subject = new AsyncSubject<TResult>(); 

     try 
     { 
      var invokeOperation = operationDelegate(x1, operation => 
      { 
       // handle operation results 

       if (operation.IsCanceled) 
       { 
       return; 
       } 

       if (operation.HasError) 
       { 
       subject.OnError(operation.Error); 
       operation.MarkErrorAsHandled(); 
       return; 
       } 

       Contract.Assume(operation.IsComplete); 
       subject.OnNext(operation.Value); 
       subject.OnCompleted(); 
      }, null); 

      // create the operation cancellation object 
      var invokeOperationCancellation = Disposable.Create(() => 
      { 
      // need to check if the operation has completed before the subscription is disposed 
      if (!invokeOperation.IsComplete && invokeOperation.CanCancel) 
      invokeOperation.Cancel(); // this might abort the web call to save bandwidth 
      }); 

      // construct a new observable that adds invoke operation cancellation upon dispose 
      return Observable.Create<TResult>(obs => new CompositeDisposable(invokeOperationCancellation, subject.Subscribe(obs))); 
     } 
     catch (Exception ex) 
     { 
      return Observable.Create<TResult>(obs => 
      { 
       obs.OnError(ex); 
       return Disposable.Empty; 
      }); 
     } 
     }; 
    } 
} 

這應該工作,雖然我沒有測試它。

用法:

var context = ... // get your DomainContext 
var param = ... // operation parameter 
// This will create the observable: 
var o = DomainContextExtensions.FromInvokeOperation</*Parameter type goes here*/, /*Result type goes here*/>(context.YourOperationMethod)(param); 
o.Subscribe(...); // subscribe as you wish or build a query 

你必須編寫其他的方法來支持調用操作使用不同數量的參數。

+0

工作,非常感謝。經過一番努力,我也得到了它與輸入參數一起工作。 – user1066012

+0

@ user1066012如果仍然很有趣,我已經改進了實現。現在它非常接近RX的'Observable.FromAsyncPattern'實現,支持單個參數並且沒有同步問題。如果在RIA操作完成後立即處理訂閱,則以前的代碼可能會觸發斷言。 –

+0

如果對以前的評論有任何疑問:我的答案的當前修訂(2)已經包含我在該評論中提到的代碼。歡迎進一步的建議/問題。 –

相關問題