0

我有一项WCF需要在现有应用程序中组合的服务。
服务界面:

[ServiceContract(CallbackContract = typeof(IClientCallback))]
    public interface IExecutionService
    {
        [OperationContract]
        ExecutionStatus Execute(string path);

        [OperationContract]
        ExecutionStatus Abort();
    }

和回调:

[ServiceContract]
    public interface IClientCallback
    {
        [OperationContract(IsOneWay = false)]
        string GetUserInput(string message, string information, bool isPause);

        [OperationContract(IsOneWay = true)]
        void OutputAvailable(OutputAvailableEventArgs args);

        [OperationContract(IsOneWay = true)]
        void ResultAvailable(ResultAvailableEventArgs args);

        [OperationContract(IsOneWay = true)]
        void ExecutionStarted(ExecutionStartedEventArgs args);

        [OperationContract(IsOneWay = true)]
        void ExecutionEnded(ExecutionEndedEventArgs args);
    }

该服务正在执行一些工作并在有需要报告的情况下进行报告。Args 类被标记为DataContract带有命名空间。它们包含 .Net 原生类型 ( int, string, DateTime)。

我创建了一个测试应用程序,一切都很好(从要求服务执行到ExecutionStarted调用约 1 秒的时间)。

在我现有的应用程序中创建客户端时,有两个问题:

  1. Execute()缓慢 - 从到大约 1 分钟ExecutionStarted()
  2. 最后一个电话 - ExecutionEnded- 只是没有发生。会发生什么?最后一次OutputAvailable调用发生了。在调试期间,我看到服务调用了该ExecutionEnded方法,但是在客户端调用的是OutputAvailable(应该被调用,只是更早而不是代替完成方法)。

我在我的测试客户端和我的真实应用程序中使用相同的测试。

我希望一些可能有帮助的代码:

服务

类声明:

  [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
        public class ExecutionService : IExecutionService

public ExecutionStatus Execute(string path)
        {
            lock (locker)
            {
                var tempClient = OperationContext.Current.GetCallbackChannel<IClientCallback>();
                if (client == null)
                    client = tempClient;
                else if (client != null && client != tempClient)
                {
                    throw new FaultException(new FaultReason("Execution Service is busy processing a request."));
                }
                else if (tempClient == null)
                    throw new FaultException(new FaultReason("No client found, execution is aborted."));
                Log.InfoFormat("client: "+ DateTime.Now);
                Log.InfoFormat(client == null ? "null" : client.ToString());
            }
            ((IContextChannel)client).OperationTimeout = new TimeSpan(0,3,0);
            Task<ExecutionStatus> executionTask = Task.Factory.StartNew(() => HandleExecution(path));
            return executionTask.Result;
}

(确保我一次只有一个客户端。我需要可重入模式,以便可以在服务方法期间使用回调。)

客户端: 创建与服务的连接:

 var myBinding = new WSDualHttpBinding();
 var myEndpoint = new EndpointAddress("http://localhost:3050/ExecutionService");
 var myChannelFactory = new DuplexChannelFactory<IExecutionService>(this, myBinding, myEndpoint);
 service = myChannelFactory.CreateChannel();
 var executionStatus = service.Execute(@"C:\Users\nosh\Desktop\launcher.py"); 

如有必要,我将发布更多代码。
另一个问题是,在我的真实应用程序中,我得到:

A first chance exception of type 'System.TimeoutException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.TimeoutException' occurred in mscorlib.dll

就在“执行”方法返回之前,后来我得到:

A first chance exception of type 'System.Runtime.Serialization.SerializationException' occurred in System.Runtime.Serialization.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll
A first chance exception of type 'System.ServiceModel.Dispatcher.NetDispatcherFaultException' occurred in System.ServiceModel.dll

这在我的测试应用程序中不会发生。
知道这里有什么问题吗?

编辑
我想我知道出了什么问题,只是不知道如何解决它。问题是我真正的应用程序是WPF,并且在使用WCF. 我尝试切换到NetTcpBinding但没有帮助。我会很感激其他建议。

编辑 2
对于这个WPF问题,您应该在回调实现中添加以下内容:

[CallbackBehavior(UseSynchronizationContext = false)]

(感谢Ian Ringrose在这里提供答案。)
现在我仍然面对一个无响应WPF的客户端,但与服务的连接没有挂起。我会很感激更多的建议。

编辑 3
现在它只是一个没有在客户端上调用的方法。连接是活动的(我在它之后还有其他调用),该方法没有做任何特别的事情。

4

2 回答 2

0

我想每个人都会不时地偶然发现那些 WTF。
我无法解释解决方案背后的逻辑,但解决方案本身很简单:

  1. 在服务解决方案中,重命名有问题的方法(在ICallback界面中)。
  2. 重新编译并更新和重新编译有问题的应用程序。
  3. 运行应用程序,突然调用方法。
  4. 再次将该方法重命名为原始名称。
  5. 赢!
于 2013-04-02T13:58:49.837 回答
0

我不知道您是如何设置服务的,但是您是否使用异步方法来调用服务?否则我建议你实现它。您的服务是静态的,因此这也可能是问题所在,当您在其他设备上运行它时,链接将无法正常工作。至于序列化错误我无能为力。

于 2013-03-27T13:56:14.227 回答