WCF服务回调未被调用

3

我正在使用WCF服务中的TCP绑定,但是客户端的回调函数没有被调用。这是我的代码:

服务端:

 public interface IMyContractCallback
{
   [OperationContract(IsOneWay = true)]  
    void OnCallback();
}

[ServiceContract(CallbackContract = typeof (IMyContractCallback),SessionMode =
 SessionMode.Required)]
public interface IService1
{

     [OperationContract(IsOneWay = true)]  
    void DoSomething();      


      [OperationContract]
    int GetCount();
}

 public class Service1 : IService1
{

    private int count=0;   
    public int GetCount()
    {
        return count;
    }

    public void DoSomething()
    {
        count++;
        Console.WriteLine("increased count");
       IMyContractCallback callback =  
                 OperationContext.Current.GetCallbackChannel<IMyContractCallback>();

            if ((callback as IChannel).State == CommunicationState.Opened)
            {
                callback.OnCallback();
            }

    }       
}

我的客户是

public class App1
{


    private MyServiceCallback callback;
    private InstanceContext context;
    private Service1Client proxy;       

    public App1()
    {
        callback=new MyServiceCallback();


        context = new InstanceContext(callback);
        var factory = new DuplexChannelFactory<IService1>(callback, "EndPointTCP");
        IService1 proxy = factory.CreateChannel();

        callback.proxy = proxy;

        proxy.DoSomething();


    }
}

public class MyServiceCallback : IService1Callback
{

    public IService1 proxy
    {
        get;
        set;
    }
    public void OnCallback()
    {

        Console.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine(proxy.GetCount());

    }
}

我面临两个问题:
1.使用上述代码,我无法从DoSomething接收回调。 2.如果我将DoSomething声明为双向绑定,则会收到回调,但会抛出异常“服务器未提供有意义的回复”。
我的客户端配置:
<?xml version="1.0" encoding="utf-8" ?>
  <configuration>
<system.serviceModel>
    <bindings>
        <netTcpBinding>
            <binding name="EndPointTCP" closeTimeout="00:10:00" openTimeout="00:10:00"
                receiveTimeout="00:10:00" sendTimeout="00:10:00"
                transactionFlow="false"
                transferMode="Buffered" transactionProtocol="OleTransactions"
                hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                maxReceivedMessageSize="65536">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" 
                 maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <reliableSession ordered="true" inactivityTimeout="00:20:00"
                    enabled="true" />
                <security mode="Transport">
                    <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                    <message clientCredentialType="Windows" />
                </security>
            </binding>
        </netTcpBinding>
        <wsDualHttpBinding>
            <binding name="EndPointHTTP" closeTimeout="00:01:00" openTimeout="00:01:00"
                receiveTimeout="00:10:00" sendTimeout="00:01:00" 
                bypassProxyOnLocal="false"
                transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" 
                   maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <reliableSession ordered="true" inactivityTimeout="00:10:00" />
                <security mode="Message">
                    <message clientCredentialType="Windows" 
                           negotiateServiceCredential="true"
                        algorithmSuite="Default" />
                </security>
            </binding>
        </wsDualHttpBinding>
    </bindings>
    <client>
        <endpoint address="masked"
            binding="wsDualHttpBinding" bindingConfiguration="EndPointHTTP"
            contract="ServiceReference1.IService1" name="EndPointHTTP">
            <identity>
                <servicePrincipalName value="masked" />
            </identity>
        </endpoint>
        <endpoint address="masked"
            binding="netTcpBinding" bindingConfiguration="EndPointTCP"
            contract="ServiceReference1.IService1" name="EndPointTCP">
            <identity>
                <servicePrincipalName value="masked" />
            </identity>
        </endpoint>
    </client>
</system.serviceModel>
  </configuration>

我的服务配置

<?xml version="1.0" encoding="UTF-8"?>
<configuration>


<system.web>
<compilation debug="true" targetFramework="4.0"/>
<httpRuntime maxRequestLength="102400" />

 </system.web>

<system.diagnostics>
 <sources>
  <source name="System.ServiceModel"
          switchValue="Information, ActivityTracing"
          propagateActivity="true">
    <listeners>
      <add name="traceListener"
          type="System.Diagnostics.XmlWriterTraceListener"
          initializeData= "d:\log\Traces.svclog" />
    </listeners>
  </source>
 </sources>
 </system.diagnostics>

 <system.serviceModel>
<bindings>
  <netTcpBinding>
    <binding name="TcpBinding" maxBufferPoolSize="2147483647"  
       maxBufferSize="2147483647"
      maxReceivedMessageSize="2147483647" portSharingEnabled="true" >
      <readerQuotas maxDepth="32" maxStringContentLength="2147483647" 
        maxArrayLength="2147483647"
        maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
      <security mode="Transport"/>
      <reliableSession enabled="true" />
    </binding>
  </netTcpBinding>
</bindings>
<services>
  <service behaviorConfiguration="WcfService2.MyServiceBehaviour" 
   name="WcfService2.Service1">
    <endpoint address="" binding="wsDualHttpBinding" bindingConfiguration=""
      name="EndPointHTTP" contract="WcfService2.IService1" />
    <endpoint address="" binding="netTcpBinding" bindingConfiguration="TcpBinding"
      name="EndPointTCP" contract="WcfService2.IService1" isSystemEndpoint="false" />
    <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
      name="mexpoint" contract="IMetadataExchange" />
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="WcfService2.MyServiceBehaviour">
      <serviceMetadata httpGetEnabled="false"  />
      <serviceThrottling maxConcurrentSessions="10000"/>
      <serviceDebug includeExceptionDetailInFaults="true" />
      <dataContractSerializer maxItemsInObjectGraph="2147483647" />
    </behavior>
  </serviceBehaviors>
   </behaviors>
 </system.serviceModel>
 <system.webServer>
  <modules runAllManagedModulesForAllRequests="true" />
  <directoryBrowse enabled="true" showFlags="Date, Time, Size, Extension, LongDate" />
  </system.webServer>

  </configuration>

我认为你的问题标题有误导性。最后一段表明你确实得到了回调;真正的问题是为什么 GetCount() 失败了。你同意吗? - Jay
请分享一下您的服务和客户端配置文件中的serviceModel部分。 - Adarsh Kumar
@Jay,我上一段的意思是,只有在将DoSomething()声明为双向操作时,我才会收到回调,如果我将其声明为单向,则不会收到回调;如果我将其声明为双向,则会收到回调,但无论我是否在回调中调用Getcount,回调都会以异常“服务器未提供有意义的回复”完成。所以我的问题是,第一,为什么我的单向操作没有返回回调,第二,为什么我从双向操作的回调中得到异常。我尝试使用SessionMode.Allowed,问题仍然存在。 - TRS
@Adarsh 我添加了客户端和服务端的配置。 - TRS
大家好,我修改了代码和问题陈述,以更好地概括我的问题。 - TRS
显示剩余4条评论
2个回答

3
问题是你在回调函数中再次调用了服务。如果你把这个省略掉,就不会出现“没有有意义的答案”的错误信息。
设置ConcurrencyMode属性到你的服务和回调类中应该会有所帮助。
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1
...

并且

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyServiceCallback : IService1Callback
...

您需要在OperationContract中设置"IsOneWay = false"。

这不是解决方案,即使我从回调中不再调用服务,我仍然会收到“没有有意义的回复错误”,而且您能否详细说明“当然,您必须在OperationContract中设置“IsOneWay = false”。” 我相信我们也可以从单向操作中获得回调,但在我的情况下某种原因无法工作。 - TRS
问题在于,你正在从回调函数中再次调用该服务 - 这是一个很好的观点。 - rudolf_franek
好的,我可以重现你所描述的问题,直到我设置了ConcurrencyMode或删除了GetCount调用。但是,我没有你的原始项目。它可以在某个地方下载吗?回调函数不适用于“IsOneWay=true”。然而,当使用回调时,它可能被隐含地使用。 - JeffRSon
看到你的真实项目会很有趣,因为目前上面的代码缺少基地址。在我的测试中,我使用了一个WCFService库和一个控制台客户端。不过我需要添加基地址。 - JeffRSon

1

应该使用 IsOneWay = true 来使其正常工作。

这里是一个例子

----服务代码

[ServiceContract(CallbackContract = typeof(IServerFinishedProcessingCallback), SessionMode = SessionMode.Required)]
public interface IDualMathService
{
    [OperationContract(IsOneWay=true)]
    void ProcessAdd(double num1, double num2);

    [OperationContract(IsOneWay = true)]
    void ProcessSubtract(double num1, double num2);

    [OperationContract(IsOneWay=true)]
    void ProcessMultiply(double num1, double num2);

    [OperationContract(IsOneWay=true)]
    void ProcessDivide(double num1, double num2);
}            
public interface IServerFinishedProcessingCallback
{        
    [OperationContract(IsOneWay=true)]
    void ProcessingFinished(string operation, double result);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class DualMathServiceClass : IDualMathService
{
    readonly IServerFinishedProcessingCallback _clientCode = OperationContext.Current.GetCallbackChannel<IServerFinishedProcessingCallback>();
    //[PrincipalPermission()]
    public void ProcessAdd(double num1, double num2)
    {
        Console.WriteLine("Processing Request for client session ID " + OperationContext.Current.SessionId);
        Console.WriteLine(string.Format("Processing Add Request for parameters {0} and {1} ", num1, num2));
        _clientCode.ProcessingFinished("Add", (num1 + num2));
    }
    public void ProcessSubtract(double num1, double num2)
    {
        Console.WriteLine("Processing Request for client session ID " + OperationContext.Current.SessionId);
        Console.WriteLine(string.Format("Processing Subtract Request for parameters {0} and {1} ", num1, num2));
        _clientCode.ProcessingFinished("Subtract", (num1 - num2));
    }
    public void ProcessMultiply(double num1, double num2)
    {
        Console.WriteLine("Processing Request for client session ID " + OperationContext.Current.SessionId);
        Console.WriteLine(string.Format("Processing Multiply Request for parameters {0} and {1} ", num1, num2));
        _clientCode.ProcessingFinished("Multiply", (num1 * num2));
    }
    public void ProcessDivide(double num1, double num2)
    {
        Console.WriteLine("Processing Request for client session ID " + OperationContext.Current.SessionId);
        Console.WriteLine(string.Format("Processing Divide Request for parameters {0} and {1} ", num1, num2));
        if (num2 == 0)
            throw new FaultException<string>("Number 2 can not be zer");
        _clientCode.ProcessingFinished("Divide", (num1 / num2));
    }
}

客户端代码

[CallbackBehavior(IncludeExceptionDetailInFaults = true,
    UseSynchronizationContext = true,
    ValidateMustUnderstand =true,
    ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ClientCallbackClass : IDualMathServiceCallback
{
    public delegate void ProceFinishedEventDelegate(string operation, double result);
    public event ProceFinishedEventDelegate ProcessFinishedEvent = null;
    public void ProcessingFinished(string operation, double result)
    {            
        if (ProcessFinishedEvent != null)
        {
            ProcessFinishedEvent(operation, result);
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接