我正在尝试重用一些.NET代码来执行对数据访问层类型服务的一些调用。我已经设法将方法的输入和方法的输出打包,但不幸的是,从内部代码调用服务,我真的不想重写以便异步。
不幸的是,Silverlight中生成的Web服务代码只生成异步方法,所以我想知道是否有人有能够解决此问题的工作代码?
注意:我不需要在UI线程上执行主代码路径,但是有问题的代码会期望它对数据访问层的调用本质上是同步的,但整个工作可以主要在后台线程上执行。
我尝试了这里找到的食谱:The Easy Way To Synchronously Call WCF Services In Silverlight,但不幸的是它超时并且从未完成通话。
或者更确切地说,似乎发生的事情是调用已完成的事件处理程序,但仅在方法返回之后。我怀疑事件处理程序是从调度程序或类似程序调用的,因为我在这里阻塞主线程,所以它永远不会完成,直到代码实际上回到GUI循环。
或类似的东西。
这是我在找到上述配方之前编写的我自己的版本,但它遇到了同样的问题:
public static object ExecuteRequestOnServer(Type dalInterfaceType, string methodName, object[] arguments)
{
string securityToken = "DUMMYTOKEN";
string input = "DUMMYINPUT";
object result = null;
Exception resultException = null;
object evtLock = new object();
var evt = new System.Threading.ManualResetEvent(false);
try
{
var client = new MinGatServices.DataAccessLayerServiceSoapClient();
client.ExecuteRequestCompleted += (s, e) =>
{
resultException = e.Error;
result = e.Result;
lock (evtLock)
{
if (evt != null)
evt.Set();
}
};
client.ExecuteRequestAsync(securityToken, input);
try
{
var didComplete = evt.WaitOne(10000);
if (!didComplete)
throw new TimeoutException("A data access layer web service request timed out (" + dalInterfaceType.Name + "." + methodName + ")");
}
finally
{
client.CloseAsync();
}
}
finally
{
lock (evtLock)
{
evt.Close();
evt = null;
}
}
if (resultException != null)
throw resultException;
else
return result;
}
基本上,这两个食谱都是这样做的:
但是,在上面的方法返回之前不会调用事件处理程序,因此我的代码会检查evt != null
等等,以避免在方法超时后杀死我的程序的TargetInvocationException。
有谁知道:
答案 0 :(得分:1)
我怀疑通过确保在主UI线程上调度MinGatServices
,ExecuteRequestCompleted
内容正在尝试提供帮助。
我还怀疑您的代码已在您已阻止的主UI线程上执行。永远不要阻止Silverlight中的UI线程,如果您需要阻止UI使用类似BusyIndicator
控件的内容。
下意识的回答是“异步代码”,但这不符合您的问题要求。
一个可能不那么麻烦的可能解决方案是从任何用户操作在不同的线程上调用它来启动整个代码块,比如使用BackgroundWorker
。
当然MinGatServices
可能确保回调发生在执行ExecuteRequestAsync
的同一个线程上,在这种情况下你需要让它在另一个线程上运行(跳回到UI)线程是可以接受的): -
Deployment.Current.Dispatcher.BeginInvoke(() => client.ExecuteRequestAsync(securityToken, input));