tags:

views:

11

answers:

2

When making simple method calls on a service (no parameters or return value expected), everything works just great. However, If I call another method on the callback, I get a big nasty error. Here are the contract interfaces:

        Namespace Net.Wcf.Contracts
    #Region "Message Responder Wcf Contracts"
        ''' <summary>
        ''' Interface defining the methods that the Responder Inbox must implement.
        ''' </summary>
        <ServiceContract(CallbackContract:=GetType(IRccUserInterfaceCallback), SessionMode:=SessionMode.Required)> _
        Public Interface IRccUserInterface
            <OperationContract()> Function IsReady() As Boolean
            <OperationContract()> Function Login(ByVal UserInfo As Collections.UserInterface.RccUserInfo) As Boolean
            <OperationContract(IsOneWay:=True)> Sub LogOut(ByVal UserInfo As Collections.UserInterface.RccUserInfo)
            <OperationContract()> Sub AudioConnecting(ByVal Key As Integer, ByVal MaxTime As Integer, ByVal Priority As MessagePriority, ByVal User As String)
            <OperationContract()> Sub AudioDisconnecting(ByVal Key As Integer, ByVal UserName As String)
            <OperationContract()> Sub ProcessTaitSimpleMessage(ByVal Msg As Messages.Tait.TaitSimpleMessage)
            <OperationContract()> Sub ProcessGeneralMessage(ByVal Msg As Messages.General.Message)
            <OperationContract()> Sub KeepAlive(ByVal RccAddress As Address)
            <OperationContract()> Sub SetCurrentAudioState(ByVal UserName As String, ByVal state As RccAudioState)
            <OperationContract()> Sub UpdateQueueItemStatus(ByVal args As RccQueueStateChangeArgs)
            <OperationContract()> Sub RadioDiverted(ByVal UserName As String, ByVal AddressDivertedTo As Address)
            <OperationContract()> Sub RadioDivertCancelled(ByVal UserName As String)
        End Interface
    ''' <summary>
    ''' Methods available to the Cad Server to inform an Rcc Station that it is Online or Offline.
    ''' </summary>
    ''' <remarks></remarks>
    Public Interface IRccUserInterfaceCallback
        <OperationContract(IsOneWay:=True)> Sub CadServerOffline()
        <OperationContract(IsOneWay:=True)> Sub CadServerOnline()
        <OperationContract()> Sub ReceiveGeneralMessage(ByVal Msg As Messages.General.Message)
        <OperationContract()> Sub ReceiveSendFailedReport(ByVal args As Gui.Controls.SendResultsEventArgs)
        <OperationContract()> Sub VehicleStateUpdate(ByVal args As Collections.MdcStateChangeEventArgs)
        <OperationContract()> Sub UpdateQueueItemStatusCallback(ByVal args As RccQueueStateChangeArgs)
    End Interface
#End Region
End Namespace

To start up the service, I call the following:

Public Sub StartServiceHost()
            'Publish the Wcf Service endpoint.
            Try
                shRccUserInterface = New ServiceHost(Me._RccInboxService)
                AddHandler shRccUserInterface.Faulted, AddressOf OnChannelFaulted
                AddHandler shRccUserInterface.Closed, AddressOf OnChannelClosed
                AddHandler shRccUserInterface.Opened, AddressOf OnChannelOpened
                AddHandler shRccUserInterface.Opening, AddressOf OnChannelOpening
                AddHandler shRccUserInterface.UnknownMessageReceived, AddressOf OnUnknownMessageReceived

                Me.bndRccUserInterface = New NetTcpBinding("ReliableDuplexBinding")
                Dim bndMex As ServiceModel.Channels.Binding = Description.MetadataExchangeBindings.CreateMexHttpBinding()
                Dim ep As Description.ServiceEndpoint
                With shRccUserInterface
                    ep = .AddServiceEndpoint(GetType(Cad.Net.Wcf.Contracts.IRccUserInterface), bndRccUserInterface, "net.tcp://localhost:55555/RccInterface")
                    .AddServiceEndpoint(GetType(Description.IMetadataExchange), bndMex, String.Empty)
                    RaiseEvent ShowUserMessageEvent(Me, "Opening Endpoint: " & ep.Address.ToString, UtaCommon.Interfaces.StatusListEntryType.Information)
                    .Open()
                End With
                Me.blnServiceHostOpen = True
                RaiseEvent ServiceHostOpenEvent(Me)
            Catch exWcf As Exception
                log.Write_Error("RccGuiComm", "StartServiceHost()", exWcf)
                RaiseEvent SendUtaEmailEvent("Wcf Problem", exWcf.ToString, System.Net.Mail.MailPriority.High)
            End Try
        End Sub

I can then create a service reference, and everything works well as long as I'm only calling the "KeepAlive" method. When I attempt to send a message object out via "ProcessGeneralMessage" the behavior should be that if a target address isn't reached, then the user will be informed of the error via the callback method "ReceiveSendFailedReport(ByVal args As Gui.Controls.SendResultsEventArgs)" The odd thing that happens is that the User is informed, but the call from the service locks and will eventually throw an exception:

    This request operation sent to http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/Anonymous did not receive a reply within the configured timeout (00:00:14.7815986).  
The time allotted to this operation may have been a portion of a longer timeout.  
This may be because the service is still processing the operation or because the service was unable to send a reply message.  
Please consider increasing the operation timeout (by casting the channel/proxy to IContextChannel and setting the OperationTimeout property) and ensure that the service is able to connect to the client.

Further, all channels are faulted and no attempts to bring them back will work unless you restart the program. Any ideas what would cause this bizarre behavior?

A: 

It's just a hunch right now, but the object returned has an System.Exception type variable, and that may not be so easily serialized...

Jasonthemasonkcch
A: 

I also don't understand why do you use duplex communication and not basic request response.

When you have duplex communication with two way messaging you have to be careful when you call two way callback operation from service operation. This causes deadlock by default. You can mark your service implementation with ServiceBehavior attribute and set ConcurrencyMode to Reentrant. This can be also set in CallbackBehavior but it should not be needed.

Ladislav Mrnka
It is currently set to Reentrant. Are you suggesting to set the callback attribute "IsOneWay:=True"?
Jasonthemasonkcch