【问题标题】:How do I call a Silverlight RIA InvokeOperation in a Domain Service using Reactive Extensions?如何使用响应式扩展在域​​服务中调用 Silverlight RIA InvokeOperation?
【发布时间】:2011-11-25 18:25:50
【问题描述】:

有谁知道我将如何使用响应式扩展调用 RIA InvokeOperation?一旦调用全部完成,我需要处理来自 Silverlight 中多个异步调用的一些数据。在我的测试中,我将几个字符串与查询结果组合在一起,现在需要添加对 RIA 域服务调用方法的调用结果,结果卡住了。

我在 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 期望作为参数的 Begin/End 调用

引用自here

“Silverlight 的重要说明!

Silverlight 的网络服务 生成的客户端代码有点烦人——它隐藏起来 BeginXXXX/EndXXXX 调用,大概是为了进行 Intellisense 清洁器。但是,它们并没有消失,您可以将它们取回的方法是 通过将 MyCoolServiceClient 对象转换为其底层接口 (即 LanguageServiceClient 对象有一个生成的 它实现的ILanguageServiceClient接口)"

有什么建议吗?

【问题讨论】:

    标签: silverlight system.reactive invoke


    【解决方案1】:

    实际上,Silverlight 并没有隐藏任何东西。 RIA 服务工具生成的DomainContext 派生代理上不存在这些方法。

    但这里有一个扩展方法,它将Invoke 操作包装成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
    

    您必须编写额外的方法来支持具有不同数量参数的调用操作。

    【讨论】:

    • 成功了,非常感谢。经过一番努力,我也让它与输入参数一起工作。
    • @user1066012 如果它仍然很有趣,我已经改进了实现。现在它非常接近 RX 的 Observable.FromAsyncPattern 实现,支持单个参数并且没有同步问题。如果订阅在 RIA 操作完成后立即被释放,之前的代码可能会抛出断言。
    • 如果对上一条评论有任何疑问:我的答案的当前修订版 (2) 已经包含我在该评论中提到的代码。欢迎提出更多建议/问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多