LBu*_*kin 15 c# wcf asynchronous yield silverlight-3.0
我正在编写重构Silverlight程序,以从WCF服务中消耗其现有业务逻辑的一部分.在这样做时,我遇到了Silverlight 3中的限制,它只允许对WCF服务的异步调用,以避免长时间运行或无响应的服务调用阻塞UI线程(SL有一个有趣的排队模型来调用WCF服务)在UI线程上).
因此,编写曾经很简单的东西变得越来越复杂(请参阅我的问题末尾的代码示例).
理想情况下,我会使用协同程序来简化实现,但遗憾的是,C#目前不支持协同程序作为本机语言工具.但是,C#确实具有使用yield return语法的生成器(迭代器)的概念.我的想法是重新使用yield关键字,以允许我为相同的逻辑构建一个简单的协同模型.
但是,我不愿意这样做,因为我担心可能存在一些我没有预料到的隐藏(技术)陷阱(考虑到我对Silverlight和WCF的相对缺乏经验).我也担心未来的开发人员可能不清楚实现机制,并且可能会阻碍而不是简化他们将来维护或扩展代码的努力.我已经在SO上看到了关于重构迭代器以构建状态机的问题:使用"yield"关键字实现状态机,虽然它与我正在做的事情不完全相同,但它确实让我停下来.
但是,我需要做一些事情来隐藏服务调用的复杂性,并管理此类更改中的缺陷的工作量和潜在风险.我对可以用来解决这个问题的其他想法或方法持开放态度.
原始的非WCF版本的代码看起来像这样:
void Button_Clicked( object sender, EventArgs e ) {
using( var bizLogic = new BusinessLogicLayer() ) {
try {
var resultFoo = bizLogic.Foo();
// ... do something with resultFoo and the UI
var resultBar = bizLogic.Bar(resultFoo);
// ... do something with resultBar and the UI
var resultBaz = bizLogic.Baz(resultBar);
// ... do something with resultFoo, resultBar, resultBaz
}
}
}
Run Code Online (Sandbox Code Playgroud)
重新考虑的WCF版本变得更加复杂(即使没有异常处理和前/后条件测试):
// fields needed to manage distributed/async state
private FooResponse m_ResultFoo;
private BarResponse m_ResultBar;
private BazResponse m_ResultBaz;
private SomeServiceClient m_Service;
void Button_Clicked( object sender, EventArgs e ) {
this.IsEnabled = false; // disable the UI while processing async WECF call chain
m_Service = new SomeServiceClient();
m_Service.FooCompleted += OnFooCompleted;
m_Service.BeginFoo();
}
// called asynchronously by SL when service responds
void OnFooCompleted( FooResponse fr ) {
m_ResultFoo = fr.Response;
// do some UI processing with resultFoo
m_Service.BarCompleted += OnBarCompleted;
m_Service.BeginBar();
}
void OnBarCompleted( BarResponse br ) {
m_ResultBar = br.Response;
// do some processing with resultBar
m_Service.BazCompleted += OnBazCompleted;
m_Service.BeginBaz();
}
void OnBazCompleted( BazResponse bz ) {
m_ResultBaz = bz.Response;
// ... do some processing with Foo/Bar/Baz results
m_Service.Dispose();
}
Run Code Online (Sandbox Code Playgroud)
上面的代码显然是一种简化,因为它省略了异常处理,无效检查以及生产代码中必需的其他实践.尽管如此,我认为它证明了Silverlight中异步WCF编程模型开始出现的复杂性的快速增长.重新分解原始实现(不使用服务层,而是将其逻辑嵌入SL客户端)正在迅速成为一项艰巨的任务.而且很可能容易出错.
代码的共同例程版本看起来像这样(我还没有测试过):
void Button_Clicked( object sender, EventArgs e ) {
PerformSteps( ButtonClickCoRoutine );
}
private IEnumerable<Action> ButtonClickCoRoutine() {
using( var service = new SomeServiceClient() ) {
FooResponse resultFoo;
BarResponse resultBar;
BazResponse resultBaz;
yield return () => {
service.FooCompleted = r => NextStep( r, out resultFoo );
service.BeginFoo();
};
yield return () => {
// do some UI stuff with resultFoo
service.BarCompleted = r => NextStep( r, out resultBar );
service.BeginBar();
};
yield return () => {
// do some UI stuff with resultBar
service.BazCompleted = r => NextStep( r, out resultBaz );
service.BeginBaz();
};
yield return () => {
// do some processing with resultFoo, resultBar, resultBaz
}
}
}
private void NextStep<T>( T result, out T store ) {
store = result;
PerformSteps(); // continues iterating steps
}
private IEnumerable<Action> m_StepsToPerform;
private void PerformSteps( IEnumerable<Action> steps ) {
m_StepsToPerform = steps;
PerformSteps();
}
private void PerformSteps() {
if( m_StepsToPerform == null )
return; // nothing to do
m_StepsToPerform.MoveNext();
var nextStep = m_StepsToPerform.Current;
if( nextStep == null ) {
m_StepsToPerform.Dispose();
m_StepsToPerform = null;
return; // end of steps
}
nextStep();
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中有各种各样的事情需要改进.但基本前提是分解连续模式(为异常处理和各种检查创建拦截点),同时允许WCF的基于事件的异步模型在执行每个步骤时驱动 - 基本上是在最后一次异步WCF调用完成时.虽然从表面上看,这看起来更像代码,但值得一提的是PerformSteps()并且NextStep()可以重复使用,只有实现ButtonClickCoRoutine()才会随着每个不同的实现站点而改变.
我不完全确定我喜欢这个模型,如果有更简单的方法来实现它,我也不会感到惊讶.但我无法在"interwebs"或MSDN或其他任何地方找到一个.在此先感谢您的帮助.
Jon*_*eet 11
你应该看看并发和协调运行时.它使用迭代器来实现此目的.
另一方面,您还应该看看Parallel Extensions及其延续方法.Parallel Extensions是.NET 4.0的一部分,而CCR需要单独的许可.我会建议你选择一个由吃饭,呼吸和睡觉的人写的框架.你自己弄错了细节太容易了.
| 归档时间: |
|
| 查看次数: |
6606 次 |
| 最近记录: |