如何使用反应式扩展在域服务中调用Silverlight RIA InvokeOperation?
有人知道我如何使用反应式扩展调用RIA调用操作吗?一旦调用完成,我需要在Silverlight中处理来自多个异步调用的一些数据。在我的测试中,我将两个字符串与查询结果组合在一起,现在需要添加调用RIA域服务调用方法的结果,我被卡住了 我在RIA域服务端的简单测试功能(完成非RX样式)如下所示:如何使用反应式扩展在域服务中调用Silverlight RIA InvokeOperation?,silverlight,system.reactive,invoke,Silverlight,System.reactive,Invoke,有人知道我如何使用反应式扩展调用RIA调用操作吗?一旦调用完成,我需要在Silverlight中处理来自多个异步调用的一些数据。在我的测试中,我将两个字符串与查询结果组合在一起,现在需要添加调用RIA域服务调用方法的结果,我被卡住了 我在RIA域服务端的简单测试功能(完成非RX样式)如下所示: [Invoke] public string DomainServiceFunction() { return "hello"; }
[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");
}
);
}
我怀疑fromsyncPattern
是关键,但显然Silverlight隐藏了fromsyncPattern
期望作为参数的Begin/End调用
引自:
“Silverlight的重要提示
Silverlight的web服务
生成的客户端代码有点烦人——它隐藏起来了
BeginXXXX/EndXXXX调用,可能是为了实现智能感知
更干净。但是,它们没有消失,你能找回它们的方法是
通过将MyColServiceClient对象强制转换到其底层接口
(即LanguageServiceClient对象具有生成的
ILanguageServiceClient接口(它实现的)
有什么建议吗?事实上,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;
});
}
};
}
}
公共静态类DomainContextensions
{
//该方法接受调用操作代理方法委托
//并返回一个可观察的序列工厂
来自InvokeOperation的公共静态函数
(Func operationDelegate)
{
Contract.Requires(operationDelegate!=null,“operationDelegate”);
Contract.sure(Contract.Result()!=null);
返回x1=>
{
//主题是结果的存储。
var subject=new AsyncSubject();
尝试
{
var invokeOperation=operationDelegate(x1,操作=>
{
//处理操作结果
如果(操作被取消)
{
返回;
}
if(operation.HasError)
{
subject.OnError(操作错误);
操作。MarkErrorAsHandled();
返回;
}
合同。承担(操作。完成);
subject.OnNext(operation.Value);
subject.OnCompleted();
},空);
//创建操作取消对象
var invokeOperationCancellation=Disposable.Create(()=>
{
//在释放订阅之前,需要检查操作是否已完成
如果(!invokeOperation.IsComplete&&invokeOperation.CanCancel)
invokeOperation.Cancel();//这可能会中止web调用以节省带宽
});
//构造一个新的可观察对象,在dispose时添加调用操作取消
返回Observable.Create(obs=>newcompositedisposable(invokeOperationCancellation,subject.Subscribe(obs));
}
捕获(例外情况除外)
{
返回可观察的。创建(obs=>
{
obs.OnError(ex);
返回一次性。空;
});
}
};
}
}
虽然我还没有测试过,但它应该可以工作
用法:
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
var context=…//获取您的域上下文
变量参数=…//操作参数
//这将创建可观察的:
var o=DomainContextExtensions.FromInvokeOperation(context.YourOperationMethod)(param);
o、 订阅(…);//按需订阅或生成查询
您必须编写其他方法来支持具有不同数量参数的调用操作。非常感谢,这很有效。经过一番努力,我还让它与输入参数一起工作。@user1066012如果它仍然有趣,我已经改进了实现。现在它非常接近RX的
可观察。FromAsyncPattern
实现,支持单个参数,并且没有同步问题。如果订阅是在RIA操作刚刚完成之后处理的,那么以前的代码可能会抛出断言。如果对以前的注释有任何疑问:我的答案的当前版本(2)已经有了我在该注释中提到的代码。欢迎提出进一步建议/问题。