Mark
Mark

Reputation: 5132

How to handle ServiceMode il fault state

I have followed this example to create a communication between a ASP.NET Website and a C# project: https://dopeydev.com/wcf-interprocess-communication/

After some time of inactivity the service goes in fault state and I can't exchange data anymore:

Exception thrown: 'System.ServiceModel.CommunicationObjectFaultedException' in mscorlib.dll

This exception is raised when I try to send a message from the Website, like in the example:

service.SendMessage("Hi, I'm the client");

Is there a way to make the service permanently enabled? It will work on LAN and the webpage is a control interface that might send data every few hours.

UPDATE

Here the server configuration:

using System.ServiceModel;
using System;

namespace MyProject
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class IServer : Interfaces.IService
    {
        public void Connect()
        {
            Callback = OperationContext.Current.GetCallbackChannel<Interfaces.ICallbackService>();
        }

        public static Interfaces.ICallbackService Callback { get; set; }

        public void SendMessage(string message)
        {
            MessageReceivedEventArgs args = new MessageReceivedEventArgs();
            args.json = message;
            OnMessageReceived(this, args);
        }

        public event EventHandler<MessageReceivedEventArgs> MessageReceived;
        protected virtual void OnMessageReceived(object sender, MessageReceivedEventArgs e)
        {
            MessageReceived?.Invoke(this, e);
        }
    }

    public class MessageReceivedEventArgs : EventArgs
    {
        public string json;
    }
}

Upvotes: 0

Views: 462

Answers (2)

Igor Labutin
Igor Labutin

Reputation: 1446

As your service has single instance, then it might be OK to maintain permanent connection to it. Permanent connections are not good as they consume resources, but if you really want it, then you need to set receiveTimeout on both sides to TimeSpan.Max. In this way WCF will not close connection like it does now.

In your example code you need to replace new NetNamedPipeBinding() with new NetNamedPipeBinding() { ReceiveTimeout = TimeSpan.Max } in both client and server code.

According to the service code you do not suppose more than 1 client connected (because Callback is static field), but still be aware that if client disconnects, then Callback will look like it is valid, but if you try send something it will throw.

Upvotes: 1

Mark
Mark

Reputation: 5132

I ended up with this code. It seems to work, but I wonder how robust it is.

public bool CheckConnection()
{
    if (pipeFactory == null)
    {
        pipeFactory = new DuplexChannelFactory<IService>(new InstanceContext(_instance), new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/ipc"));
    }

    try
    {
        switch (pipeFactory.State)
        {
            case CommunicationState.Faulted:
                pipeFactory.Abort();
                pipeFactory = new DuplexChannelFactory<IService>(new InstanceContext(_instance), new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/ipc"));
                service = pipeFactory.CreateChannel();
                service.Connect();
                break;

            case CommunicationState.Closed:
                service = pipeFactory.CreateChannel();
                service.Connect();
                break;

            case CommunicationState.Created:
                service = pipeFactory.CreateChannel();
                service.Connect();
                break;
        }

    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex);
        throw;
    }

    return pipeFactory.State == CommunicationState.Opened;
}

UPDATE

This doesn't work. Even if the pipeFactory.State is Opened the following exception is raised after some time of inactivity:

Exception thrown: 'System.ServiceModel.CommunicationObjectFaultedException' in mscorlib.dll

System.ServiceModel.CommunicationObjectFaultedException: The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.

Server stack trace: at System.ServiceModel.Channels.CommunicationObject.ThrowIfDisposedOrNotOpen() at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at Interfaces.IService.SendMessage(String message) at _Default.Submit1(String name, String surname, String country, String email, Boolean disclaimer1, Boolean disclaimer2) in Default.aspx.cs:line 99

Upvotes: 0

Related Questions