2010-01-19 39 views
0

我创建一个Silverlight应用程序,我有一对夫妇与自动生成的代理问题(通过将在Visual Studio 2008中添加服务引用)是否有一个事件可以告诉WCF自动生成的代理何时执行异步操作?

在客户端上生成代理的异步方法生成和我可以打电话给他们,那很好。

但我真正想做的是在我的页面上有一个'忙'或'异步加载'动画。我过去通过使用一个静态类来存储目前正在进行的异步调用的数量,实现了这一点 - 这种方法的问题在于,我必须记住每当我调用异步方法时手动递增和递减计数代理(并在完成时递减) - 当然,我会忘记经常这样做。

我试过的其他方法稍微好一点就是将代理包装在我自己的包装类中,所以不是调用代理上的方法,而是调用包装器上的方法,包装器会增加/减少计数 - This有点好一些,但是当我的服务的操作合同/名称/参数不断变化时,它证明是有点痛苦的。当服务在早期发展。

我错过了什么吗?因为我真的认为它应该比我目前的方法简单一些。

+0

不是开箱即用的,但是当您调用BeginXXXX并将其设置回来时,设置一个小布尔标志会相当容易,那么输入EndXXX回调,不是吗? – 2010-01-19 22:14:17

回答

0

我同意,应该有一些比你目前的方法更容易。但是,除非我们可以使用T4模板来生成代理类,否则,除非你想推出自己的(不推荐IMO,YMMV),否则按照你已经尝试过的方式来看,你认为最好的方法就是拍摄。

我目前正在使用这两种方法的混合。我已经将所有WCF调用包装在一系列数据访问类中,这些类将MS提供的不太有用的事件驱动模型转换为更简单的回调方法。在这些数据访问类中,我还使用一个静态的PreProcessCall()方法来封装每个调用,该方法处理增加未完成的调用计数器并将调用编组到后台线程;我用静态的PostProcessCall()方法封装了每个返回调用,该方法递减未完成的调用计数器并将回调编组到UI线程中。

public static void PreProcessCall(Action action) 
    { 
     Logger.LogDebugMessage("Pre-processing call for {0}", (new StackTrace()).GetFrame(1).GetMethod().Name); 
     Interlocked.Increment(ref pendingCalls); 
     ThreadPool.QueueUserWorkItem(o => 
      { 
       try 
       { 
        action(); 
       } 
       catch (System.Exception ex) 
       { 
        DataPublisher.GetPublisher().RaiseDataProcessExceptionOccurred(ex, ex.Message); 
        UpdatePendingCalls(); 
       } 
      }); 
    } 

    private static void UpdatePendingCalls() 
    { 
     Interlocked.Decrement(ref pendingCalls); 
     Debug.Assert(pendingCalls >= 0, "The number of pending calls should never go below zero."); 
     if (pendingCalls <= 0) 
     { 
      lock (pendingCallNotifications) 
      { 
       while (pendingCallNotifications.Count > 0) 
       { 
        Action callback = pendingCallNotifications.Dequeue(); 
        Globals.Dispatcher.BeginInvoke(callback); 
       } 
      } 
     } 
    } 

    public static void PostProcessCall(Action action) 
    { 
     Logger.LogDebugMessage("Post-processing call for {0}", (new StackTrace()).GetFrame(1).GetMethod().Name); 
     UpdatePendingCalls(); 
     Globals.Dispatcher.BeginInvoke(() => 
      { 
       try 
       { 
        action(); 
       } 
       catch (System.Exception ex) 
       { 
        DataPublisher.GetPublisher().RaiseDataProcessExceptionOccurred(ex, ex.Message); 
       } 
      }); 
    } 

因此,一个典型的调用看起来是这样的:

public void SendMessage(string message, OperationCallback callback) 
    { 
     DataConnectionManager.PreProcessCall(() => 
      { 
       Logger.LogDebugMessage("SendChatMessage"); 
       notificationClient.SendChatMessageAsync(roomViewModel.SessionId, message, callback); 
      }); 
    } 

    void RoomService_SendChatMessageCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
    { 
     OperationCallback callback = (OperationCallback)e.UserState; 
     DataConnectionManager.PostProcessCall(() => 
      { 
       if (callback != null) 
       { 
        callback(e.Error); 
       } 
       Logger.LogDebugMessage("SendChatMessageCompleted."); 
      }); 
    } 

就像我说的,基本上你已经尝试过。

0

我创建了一个方法只是在最近,解决了这个问题 参见:Dynamic IL method causes "Operation could destabilize the runtime"

基本上,创建一个包装调用您的异步方法,并让这种包装采用动态方法和反思注册一个通用的事件。那么你永远不用担心在包装器中为每个异步调用维护包装器。

相关问题