Silverlight - 在从方法返回之前等待异步调用完成

时间:2011-06-20 15:13:52

标签: multithreading silverlight wcf

我有一个使用WCF服务的Silverlight应用程序,并且还使用Wintellect Power Threading库来确保在应用程序继续之前完全执行逻辑。这是通过使用委托回调应用程序来实现的,这样它可以在服务调用完成后继续。

我希望在我的应用程序的另一部分中实现相同的功能,但不使用回调,例如call方法,它使用WCF服务来说明从数据库加载一个对象,等待它返回,然后从调用的原始方法返回该对象的Id。

我能看到这样做的唯一方法是在一个辅助库中执行对WCF服务的调用,该辅助库将对象加载到另一个线程上,原始方法将继续检查辅助库(使用静态变量)等待它完成然后返回。

这是实现此功能的最佳方式吗?如果是这样,我的实施细节无法正常工作。

public class MyHelper
{

    private static Thread _thread;
    private static User _loadedObject;        

    public static GetUser()
    {
        return _loadedObject;
    }

    public static void LoadObject(int userId)
    {
        _loadedObject = null;
        ParameterizedThreadStart ts = new ParameterizedThreadStart(DoWork);           
        _thread = new Thread(ts);
        _thread.Start(userId);

    }

    private static void DoWork(object parameter)
    {            
        var ae = new AsyncEnumerator();
        ae.BeginExecute(DoWorkWorker(ae, Convert.ToInt32(parameter)), ae.EndExecute);    
    }

    private static IEnumerator<Int32> DoWorkWorker(AsyncEnumerator ae, int userId)
    {
        // Create a service using a helper method
        var service = ServiceHelper.GetService<IUserServiceAsync>();
        service.BeginGetUserById(userId, ae.End(), null);
        yield return 1;

        _loadedObject = service.EndGetUserById(ae.DequeueAsyncResult());
        _thread.Abort();
    }
}

我的方法是:

public int GetUser(int userId)
{
    MyHelper.LoadObject(userId);
    User user = MyHelper.GetUser();
    while (user == null)
    {
        Thread.Sleep(1000);
        user = MyHelper.GetUser();
    }
    return user.Id;
 }

对获取用户的调用是在helper方法中的另一个线程上执行的,但从不返回。也许这是由于产量和调用方法的睡眠。我检查了调用以使用户处于不同的线程,因此我认为所有内容都应该分开,

3 个答案:

答案 0 :(得分:1)

我相信从Silverlight应用程序调用服务器会使用在UI线程上触发的事件;我认为这是浏览器中Silverlight主机环境的一部分,无法解决。因此,尝试从另一个线程回调服务器永远不会结束。如果您正在等待UI线程中的程序代码,那么您永远不会从WCF调用中获取调用结果事件。

可以模拟来自非UI线程的同步调用,并在UI线程上进行回调,但这可能不是您想要的。最好咬住子弹,让你的程序逻辑与Silverlight给你的异步调用一起工作。

答案 1 :(得分:1)

您使用的整个构造与Silverlight的当前最佳实践不匹配。在Silverlight中,您的数据访问方法(当然是通过WebServices)是异步执行的。你不应该围绕这个设计,而是相应地调整你的设计。

然而,顺序调用服务(与同步不同)在某些情况下可能有效。在this blog post中,我已经展示了如何通过订阅远程调用的Completed事件并在此期间阻止UI来实现这一点,工作流看起来就像普通的异步调用一样。

答案 2 :(得分:1)

如果您针对为服务参考创建的界面进行编码,则可以针对每个服务调用同步调用BeginEnd方法,然后传入{{1}在Action<T>方法完成后执行。请注意,您必须从调度员那里执行此操作。这与进行同步调用非常接近,因为在调用仍然写入调用之后运行的代码将在服务调用完成后执行。但它确实涉及创建包装器方法,但我们也通过隐藏包装器并自动生成它们来解决这个问题。看似很多工作但不是,并且最终比所有事件处理程序更优雅。如果您需要有关此模式的更多信息,请告诉我