C# WCF Channel Timeout on subsequent calls - c#

I have a C# app calling a Soap client using WCF. The first call to the service succeeds, but any calls thereafter fail.
The code to setup the client is:
public WebserviceHelper(string username, string password, string webserviceURL)
{
var binding = new BasicHttpBinding();
binding.MaxBufferPoolSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.MaxReceivedMessageSize = 2147483647;
binding.OpenTimeout = new TimeSpan(0, 1, 0);
binding.ReceiveTimeout = new TimeSpan(0, 1, 0);
binding.SendTimeout = new TimeSpan(0, 1, 0);
var endpoint = new EndpointAddress(webserviceURL);
var channelFactory = new ChannelFactory<EntityAPISoap>(binding, endpoint);
SoapClient = new EntityAPISoapClient(binding, endpoint);
SoapClient.Endpoint.Behaviors.Add(new CustomEndpointBehavior(username, password));
var isAlive = SoapClient.isAlive();
Console.WriteLine(SoapClient.State); //Opened
isAlive = SoapClient.isAlive(); //timeout exception
}
The first call to isAlive returns immediately, the second call times out with this exception:
The request channel timed out while waiting for a reply after
00:01:00. Increase the timeout value passed to the call to Request or
increase the SendTimeout value on the Binding. The time allotted to
this operation may have been a portion of a longer timeout.
I've increased the timeout, but then it just takes longer to respond and anyway the server responds within a second, so 1 minute is more than enough.

Related

ะก# WCF web service exception : a required header representing a Message Addressing Property is not present

I generated a Service Reference from url https://portal.shipsea.ru/services/ShipService?wsdl with Visual Studio 2022.
I tried to invoke some method of generated client.
Here is my code:
var binding = new BasicHttpsBinding();
binding.MaxReceivedMessageSize = 2147483647;
var endpointAddress = new EndpointAddress("https://portal.shipsea.ru:443/services/ShipService");
using var client = new ShipServiceClient(binding, endpointAddress);
client.ClientCredentials.Windows.ClientCredential.UserName = "******";
client.ClientCredentials.Windows.ClientCredential.Password = "******";
var responce = client
.getShipPositionsAsync(
new ShipPositionRequest
{
start = 0,
limit = 1000,
minLatitude = 0,
minLongitude = 0,
maxLatitude = 0,
maxLongitude = 0,
minReceiveDate = DateTime.Now,
maxReceiveDate = DateTime.Now.AddDays(-30)
})
When making the call, I get an exception:
System.ServiceModel.FaultException: A required header representing a Message Addressing Property is not present
Is there something wrong with the client generation? Or how to add the missing header when called?

Sending request to PKI Web service in .NET 6

I am trying to establish connection to external PKI SOAP web service, but not sure how to set BasicHttpBinding security in .NET 6. Constantly getting exception:
*System.ServiceModel.ProtocolException: 'The header 'Security' from the namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' was not understood by the recipient of this message, causing the message to not be processed. This error typically indicates that the sender of this message has enabled a communication protocol that the receiver cannot process. Please ensure that the configuration of the client's binding is consistent with the service's binding. '
*
I am using auto generated class from wsdl, but create my own binding.
BasicHttpBinding:
public BasicHttpBinding GetCustomBinding()
{
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport)
{
Security =
{
Message =
{
ClientCredentialType = BasicHttpMessageCredentialType.Certificate
},
Transport =
{
ClientCredentialType = HttpClientCredentialType.Certificate
},
Mode = BasicHttpSecurityMode.Transport
},
MaxReceivedMessageSize = MaxMessageSizeBytes
};
return binding;
}
Creating proxy client:
public autoGeneratedClient GetClient(string endpointUrl, string dnsIdentity, string clientCertificatePath, string clientCertificatePassword, string serviceCertificatePath, int timeout = 10)
{
DnsEndpointIdentity endpointIdentity = new DnsEndpointIdentity(dnsIdentity);
EndpointAddress endpointAddress = new EndpointAddress(new Uri(endpointUrl), endpointIdentity);
//CustomBinding for eBox web service with security setup
MyCustomBinding myCustomBinding = new MyCustomBinding();
Binding binding = myCustomBinding.GetCustomBinding();
binding.CloseTimeout = new TimeSpan(0, timeout, 0);
binding.ReceiveTimeout = new TimeSpan(0, timeout, 0);
binding.SendTimeout = new TimeSpan(0, timeout, 0);
binding.OpenTimeout = new TimeSpan(0, timeout, 0);
autoGeneratedClient client = new autoGeneratedClient(binding, endpointAddress);
client.ClientCredentials.ClientCertificate.Certificate = X509CertificateFactory.GetClientCertificate(clientCertificatePath, clientCertificatePassword);
client.ClientCredentials.ServiceCertificate.DefaultCertificate = X509CertificateFactory.GetServiceCertificate(serviceCertificatePath);
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
return client;
}

C# Wcf connections causing TCP/IP Port Exhaustion

I'm working on an ASP.NET MVC project and found several connections to a WCF service that are not closed and I think this is causing a TCP/IP Port Exhaustion.
I checked the server at the Resource Monitor/Network/TCP Connections and there are thousands of gray connections as "IPV6 Loopback" and at some point there are so many connections that the server stops responding on the service port.
Existis a dependency injection to work with the connections on the controllers and there is a "CloseChannel" method, but it was not called, I made some changes to it and started calling it in the Dipose method on the controllers to close the connections, but I did not get any results. The loopbacks continue to appear.
Two solutions I think to do is:
Remove the dependency injection and create the connection normaly
on each time with using.
Beside closing connections make some changes on the server as
described in this post
Doubt:
Is there any better option than the ones I proposed? If not, which one is the best in your opinion?
Thank you all!
PS.: Code used today to open and close connections:
This is called onthe controller:
IClient wcfClient = WcfChannel.CreateChannel<IClient>(connectionstr, WcfChannel.WcfBinding.NetTcpBinding);
This is the WcfChannel:
public static class WcfChannel
{
public static T CreateChannel<T>(string endpointAddress, WcfBinding wcfBinding)
{
Binding binding = null;
#region ReaderQuotas
XmlDictionaryReaderQuotas readerQuotas = new XmlDictionaryReaderQuotas()
{
MaxDepth = int.MaxValue,
MaxStringContentLength = int.MaxValue,
MaxArrayLength = int.MaxValue,
MaxBytesPerRead = int.MaxValue,
MaxNameTableCharCount = int.MaxValue
};
#endregion
switch (wcfBinding)
{
case WcfBinding.BasicHttpBinding:
case WcfBinding.NetMsmqBinding:
case WcfBinding.NetNamedPipeBinding:
throw new NotImplementedException();
case WcfBinding.NetTcpBinding:
binding = new NetTcpBinding()
{
Name = "NetTcpBinding",
MaxBufferPoolSize = long.MaxValue,
MaxBufferSize = int.MaxValue,
MaxReceivedMessageSize = int.MaxValue,
ReaderQuotas = readerQuotas,
Security = new NetTcpSecurity() { Mode = SecurityMode.None },
CloseTimeout = new TimeSpan(0, 5, 0),
OpenTimeout = new TimeSpan(0, 5, 0),
ReceiveTimeout = new TimeSpan(0, 5, 0),
SendTimeout = new TimeSpan(0, 5, 0)
};
break;
case WcfBinding.NetTcpBindingStreamed:
binding = new NetTcpBinding()
{
Name = "NetTcpBindingStreamed",
TransferMode = TransferMode.Streamed,
MaxBufferPoolSize = long.MaxValue,
MaxBufferSize = int.MaxValue,
MaxReceivedMessageSize = int.MaxValue,
ReaderQuotas = readerQuotas,
Security = new NetTcpSecurity() { Mode = SecurityMode.None },
CloseTimeout = new TimeSpan(0, 5, 0),
OpenTimeout = new TimeSpan(0, 5, 0),
ReceiveTimeout = new TimeSpan(0, 5, 0),
SendTimeout = new TimeSpan(0, 5, 0)
};
break;
case WcfBinding.WS2007HttpBinding:
case WcfBinding.WSHttpBinding:
throw new NotImplementedException();
default:
throw new NotImplementedException();
}
EndpointAddress endpoint = new EndpointAddress(endpointAddress);
var channelFactory = new ChannelFactory<T>(binding, endpoint);
T channelObj = channelFactory.CreateChannel();
return channelObj;
}
public static void CloseChannel(this object obj)
{
if (obj != null)
{
try
{
(obj as IClientChannel).Close();
}
catch (CommunicationException)
{
if (obj.GetType().GetMethod("Abort") != null)
{
(obj as IClientChannel).Abort();
}
}
catch (TimeoutException)
{
if (obj.GetType().GetMethod("Abort") != null)
{
(obj as IClientChannel).Abort();
}
}
catch (Exception)
{
//many connections doesn't have and Abort or close
}
if (obj.GetType().GetMethod("Dispose") != null)
{
(obj as IDisposable).Dispose();
}
obj = null;
}
}
public enum WcfBinding
{
BasicHttpBinding,
NetMsmqBinding,
NetNamedPipeBinding,
NetTcpBinding,
NetTcpBindingStreamed,
WS2007HttpBinding,
WSHttpBinding
}
}
I suspect that your problem is generated by the fact that the WCF session is not managed. The Net TCP Binding is a session based binding and the session needs to be managed. In contrast to ASP.NET, where the session is initiated and managed by the server, in WCF the session is initiated and managed by the client.
You can manage the session by using the ServiceContract/SessionMode, OperationContract/IsInitiating/IsTerminating annotation attributes. (documentation here: https://learn.microsoft.com/en-us/dotnet/framework/wcf/using-sessions)
On the client side, you need to call the CloseChannel method after ending the session. Also, you need to verify the channel state on all exception and call the abort method (some consideration regarding the use of Net TCP Binding client side here: https://blogs.msdn.microsoft.com/rodneyviana/2016/02/29/considerations-for-nettcpbindingnetnamedpipebinding-you-may-not-be-aware/). Also, on server side, as a best practice, one might want to enable service throttling in order to limit the sessions/service instances (https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-servicethrottlingbehavior-to-control-wcf-service-performance).

WCF Timeouts when target machine is not running

my .NET 4.5 application uses WCF net.tcp binding to cummunicate with server. The communication is pretty simple. Client just invoke one method and server returns true/false. The server must respond in 5 seconds. If not the client tries another server. The timing is critical for me.
WCF timeouts (Send, Recieve, Open, Close, Operation and ChannelInitializationTimeout) works fine when the PC with server is running. However when the PC is not running (or bad IP address is filled in config) it takes almost 30s until the exception is thrown. Is there any other timeout I must configure to get it working?
Here is my client code (nothing is placed in app.config file):
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None)
{
SendTimeout = TimeSpan.FromMilliseconds(Configuration.Instance.LocalConfiguration.Failover.SendTimeout),
ReceiveTimeout = TimeSpan.FromMilliseconds(Configuration.Instance.LocalConfiguration.Failover.RecieveTimeout),
OpenTimeout = TimeSpan.FromMilliseconds(Configuration.Instance.LocalConfiguration.Failover.OpenTimeout),
CloseTimeout = TimeSpan.FromMilliseconds(Configuration.Instance.LocalConfiguration.Failover.CloseTimeout),
TransactionFlow = false,
TransactionProtocol = TransactionProtocol.Default,
TransferMode = TransferMode.Buffered,
Security = new NetTcpSecurity() { Mode = SecurityMode.None },
ReliableSession = new OptionalReliableSession() { Enabled = false },
ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas() { MaxArrayLength = 16384, MaxBytesPerRead = 4096, MaxDepth = 32, MaxNameTableCharCount = 16384, MaxStringContentLength = 8192 },
Name = "NoSecurity",
MaxReceivedMessageSize = 65535,
MaxConnections = 10,
MaxBufferSize = 65535,
MaxBufferPoolSize = 524288,
ListenBacklog = 10,
HostNameComparisonMode = HostNameComparisonMode.StrongWildcard
};
BindingElementCollection be = binding.CreateBindingElements();
TcpTransportBindingElement tcpBe = be.Find<TcpTransportBindingElement>();
tcpBe.ChannelInitializationTimeout = TimeSpan.FromMilliseconds(Configuration.Instance.LocalConfiguration.Failover.InitializationTimeout);
tcpBe.TransferMode = TransferMode.Buffered;
CustomBinding customBinding = new CustomBinding(be);
FailoverClient.ListenerClient serviceClient = new FailoverClient.ListenerClient(customBinding, new EndpointAddress(address));
serviceClient.InnerChannel.OperationTimeout = TimeSpan.FromMilliseconds(Configuration.Instance.LocalConfiguration.Failover.OperationTimeout);
ps: The exception thrown after 30s is 'System.ServiceModel.EndpointNotFoundException ... the attempt lasted for 00:00:04.123. TCP error 10060...' with nested exception 'System.Net.Sockets.SocketException ...the remote party did not properly respond after period of time...'
EDIT:
I found a workaround, but it does not anwser my question. I can use asynchronous call and wait for completion.
Task<bool> task = serviceClient.HeartbeatAsync();
try
{
if (task.Wait(5000))
{
Console.WriteLine("Task result: " + task.Result);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

WCF Server Connect to the client Automatically When Connection was aborted

I am using WCF service in my WindowsApplication... when i was running the application both server and client, The server disconnected the connetion in few minutes.... How shall i reconnect the client automatically When Connection was aborted....
This is my Client code:
public void connecttoserver()
{
D:
try
{
EndpointAddress ea = new EndpointAddress(#"net.tcp://10.0.3.33:2222/ClsPCMain");
EndpointAddress ea = new EndpointAddress(StrAddress);
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, false);
binding.MaxBufferPoolSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.PortSharingEnabled = true;
binding.ReceiveTimeout = TimeSpan.MaxValue;
binding.SendTimeout = TimeSpan.MaxValue;
binding.OpenTimeout = TimeSpan.MaxValue;
binding.CloseTimeout = TimeSpan.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.MaxBufferPoolSize = Int32.MaxValue;
binding.MaxConnections = Int16.MaxValue;
binding.ReaderQuotas.MaxArrayLength = Int32.MaxValue;
binding.ReaderQuotas.MaxBytesPerRead = Int32.MaxValue;
binding.ReaderQuotas.MaxDepth = Int32.MaxValue;
binding.ReaderQuotas.MaxNameTableCharCount = Int32.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
binding.Security.Mode = SecurityMode.None;
ChannelFactory<InterfaceClass.IService> Client = new ChannelFactory<InterfaceClass.IService>(binding,ea);
InterfaceClass.IService serviceobj = Client.CreateChannel(ea);
clsStatus.connectstatus = false;
ClsPC objclsPc = serviceobj.PCInfoMethod(Environment.UserName, Environment.UserDomainName, Dns.GetHostName(), Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString());
if (objclsPc.imageid == 1)
{
clsStatus.FullSizeImage = true;
clsStatus.ThumbnailImage = false;
}
else
{
clsStatus.ThumbnailImage = true;
clsStatus.FullSizeImage = false;
}
Client.Close();
Client=null;
//serviceobj = null;
}
catch (Exception ex)
{
logobj.Write(ex);
}
}
This Is My Server Code:
public clsHostService()
{
string StrAddress = File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + "url2.txt");
ServiceHost host = new ServiceHost(typeof(clsService));
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, false);
ServiceEndpoint endpointinfo = host.AddServiceEndpoint(typeof(IService), binding, StrAddress);
endpointinfo.Binding.CloseTimeout = TimeSpan.MaxValue;
endpointinfo.Binding.OpenTimeout = TimeSpan.MaxValue;
endpointinfo.Binding.ReceiveTimeout = TimeSpan.MaxValue;
endpointinfo.Binding.SendTimeout = TimeSpan.MaxValue;
XmlDictionaryReaderQuotas BindingQuota = binding.ReaderQuotas;
BindingQuota.MaxArrayLength = Int32.MaxValue;
BindingQuota.MaxBytesPerRead = Int32.MaxValue;
BindingQuota.MaxDepth = Int32.MaxValue;
binding.MaxConnections = Int16.MaxValue;
binding.MaxBufferPoolSize = Int32.MaxValue;
binding.MaxBufferSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.CloseTimeout = TimeSpan.MaxValue;
binding.OpenTimeout = TimeSpan.MaxValue;
binding.ReceiveTimeout = TimeSpan.MaxValue;
binding.SendTimeout = TimeSpan.MaxValue;
ServiceThrottlingBehavior throttlingBehavior =new ServiceThrottlingBehavior();
throttlingBehavior.MaxConcurrentCalls = Int32.MaxValue;
throttlingBehavior.MaxConcurrentInstances = Int32.MaxValue;
throttlingBehavior.MaxConcurrentSessions = Int32.MaxValue;
host.Description.Behaviors.Add(throttlingBehavior);
host.Open();
Console.WriteLine("Server Started");
Console.ReadLine();
}
Now How Shall i Connect to the client Automatically When server cuts the Connection?
Anyone Tell me The Solution of this Problem...
Thanks in Advance.....
I use something like this:
//Somewhere in the main
ConfigureWcf();
ConnectToServer();
//...
void ConnectToServer()
{
myService = new ServiceReference.ServiceClient(context);
myService.Open();
myService.InnerChannel.UnknownMessageReceived += InnerChannel_UnknownMessageReceived;
myService.InnerChannel.Closed += InnerChannel_Closed;
}
void StartConnecting()
{
//use 5 attempts to connect to server
ConnectToServer();
}
void InnerChannel_Closing(object sender, EventArgs e)
{
//Connection to server closed!
//Write to log
StartConnecting();
}
I don't completely understand your question, I'm afraid - your Winforms app is hosting the service, or is it the client calling a WCF service??
WCF doesn't typically use the concept of having a constant connection between client and server.
The client builds a client-side proxy on which is calls methods that the server exposes. Basically, each call is independant of all the others - a connection only exists between the client and the server for the duration of the call. The connection isn't always up - it's only in place when a call is actually happening.
So I don't completely understand what you want to "reconnect" - there is not always-on connection in the first place.
What can happen is that if an exception happens on the server side and isn't caught and handled properly, then the client-side proxy can become invalid. In WCF terms, the "channel" between the client and the server has been "faulted" , e.g. has become unusable. If you were to call the server again with a client-side proxy in a faulted state, you'd receive a client-side exception.
You can check for a faulted channel state on the client-side proxy before making a call with this code:
if(client.State == CommunicationState.Faulted)
{
client = new YourServiceClient();
}
if the channel is indeed faulted, then you need to re-create the proxy again and you should be back in business.

Categories

Resources