Reputation: 5132
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.
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
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
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;
}
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