【问题标题】:Calling a webservice synchronously from a Silverlight 3 application?从 Silverlight 3 应用程序同步调用 Web 服务?
【发布时间】:2011-02-25 01:37:41
【问题描述】:

我正在尝试重用一些对数据访问层类型服务执行某些调用的 .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;
}

基本上,这两种食谱都是这样做的:

  • 设置 ManualResetEvent
  • 挂钩已完成的事件
  • 事件处理程序从服务调用中获取结果,并向事件发出信号
  • 主线程现在异步启动 Web 服务调用
  • 然后等待事件发出信号

但是,在上述方法返回之前,不会调用事件处理程序,因此我的代码会检查 evt != null 等,以避免在方法超时后 TargetInvocationException 杀死我的程序。

有谁知道:

  • ...如果在 Silverlight 3 中可能的话
  • ...我在上面做错了什么?

【问题讨论】:

    标签: silverlight asynchronous


    【解决方案1】:

    我怀疑 MinGatServices 的东西试图通过确保在主 UI 线程上调度 ExecuteRequestCompleted 来提供帮助。

    我还怀疑您的代码已经在您阻止的主 UI 线程上执行。切勿在 Silverlight 中阻止 UI 线程,如果您需要阻止 UI,请使用 BusyIndicator 控件之类的东西。

    下意识的答案是“异步编码”,但这不能满足您的问题要求。

    一种可能不太麻烦的解决方案是从任何用户操作在不同线程上调用它开始整个代码块,例如使用BackgroundWorker

    当然,MinGatServices 可能会确保回调发生在执行 ExecuteRequestAsync 的同一线程上,在这种情况下,您需要让它在不同的线程上运行(跳回 UI 线程是可以接受的):-

     Deployment.Current.Dispatcher.BeginInvoke(() => client.ExecuteRequestAsync(securityToken, input));
    

    【讨论】:

    • 我会试试这个,MinGatServices 名称只是一个命名空间,并且该类基本上只包含问题中的方法,所以我为自己设置的任何陷阱都在问题中可见,但是是的,我确实在 UI 线程上执行了调用它的主代码,所以我将尝试在此处拆分执行路径。但是我是否应该理解您的回答,即“service.MethodNameAsync”通过 Dispatcher 类在 UI 线程上运行呢?因此,由于我从 UI 线程调用它,我现在让 UI 线程等待 UI 线程?
    • @Lasse:好吧,如果异步方法试图提供帮助,那么它将使用线程的调度程序来排队要在线程上执行的代码。所以是的,你最终会陷入这种僵局。
    猜你喜欢
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    相关资源
    最近更新 更多