WCF client request returns bad request (400) - c#

My client application use a WCF web service which is hosted in my local IIS. This web service use for upload an image. Once image size become bigger it gives bad request(400).
Client is configure to dynamically get the web service URL.
Client Code
string serviceUrl=GetUrl(); /* http://localhost:85/ImageUploaderService.svc */
TimeSpan timeOut = new TimeSpan(0, 30, 0);
EndpointAddress endPoint = new EndpointAddress(serviceUrl);
BasicHttpBinding binding = new BasicHttpBinding()
{
CloseTimeout = timeOut,
MaxReceivedMessageSize = 65536,
OpenTimeout = timeOut,
ReceiveTimeout = timeOut,
SendTimeout = timeOut,
MaxBufferSize = 65536,
MaxBufferPoolSize = 524288,
UseDefaultWebProxy = true,
};
binding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
{
MaxArrayLength = 64000000,
MaxStringContentLength = 8192,
MaxDepth = 32,
MaxNameTableCharCount = 16384,
MaxBytesPerRead = 4096
};
client = new ImageUploaderServiceClient(binding, endPoint);
Web Service side
<basicHttpBinding>
<binding maxBufferSize="64000000" maxReceivedMessageSize="64000000" maxBufferPoolSize="64000000">
<readerQuotas maxDepth="64000000" maxStringContentLength="64000000" maxArrayLength="64000000" maxBytesPerRead="64000000" />
<security mode="None"/>
</binding>
</basicHttpBinding>
What is the wrong I am doing. Please guide me through the correct way.

You should increase MaxReceivedMessageSize on client side as well probably:
BasicHttpBinding binding = new BasicHttpBinding()
{
MaxReceivedMessageSize = 64000000,
MaxBufferSize = 64000000,
MaxBufferPoolSize = 64000000,
// .....
};
binding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
{
MaxArrayLength = 64000000,
MaxStringContentLength = 64000000,
MaxDepth = 64000000,
MaxBytesPerRead = 64000000
};
I had the same problem once - the server and client binding configuration should be the same.

Related

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;
}

WCF client failed when receive bytes array over 350 MB

When I receive bytes array over 350 MB, I am getting error as "The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error."
Client side config
var binding = new NetTcpBinding(SecurityMode.None)
{
PortSharingEnabled = true,
MaxBufferSize = Int32.MaxValue,
MaxReceivedMessageSize = Int32.MaxValue,
ReaderQuotas = new XmlDictionaryReaderQuotas
{
MaxArrayLength = Int32.MaxValue,
MaxBytesPerRead = Int32.MaxValue,
MaxDepth = Int32.MaxValue,
MaxNameTableCharCount = Int32.MaxValue,
MaxStringContentLength = Int32.MaxValue,
},
MaxBufferPoolSize = 0,
TransactionFlow = false,
TransactionProtocol = TransactionProtocol.Default,
TransferMode = TransferMode.Streamed,
OpenTimeout = new TimeSpan(0, 10, 0),
CloseTimeout = new TimeSpan(0, 10, 0),
SendTimeout = new TimeSpan(0, 10, 0),
ReceiveTimeout = new TimeSpan(0, 10, 0)
};
container.Register(Component.For<IFtpsServiceFacade>()
.AsWcfClient(
new DefaultClientModel(
WcfEndpoint.BoundTo(binding)
.At(string.Format("net.tcp://{0}/FileService.Ftps",
"localhost")))
));
Server side config.
var binding = new NetTcpBinding
{
PortSharingEnabled = true,
MaxBufferSize = Int32.MaxValue,
MaxReceivedMessageSize = Int32.MaxValue,
ReaderQuotas = new XmlDictionaryReaderQuotas
{
MaxArrayLength = Int32.MaxValue,
MaxBytesPerRead = Int32.MaxValue,
MaxDepth = Int32.MaxValue,
MaxNameTableCharCount = Int32.MaxValue,
MaxStringContentLength = Int32.MaxValue,
},
MaxBufferPoolSize = 0,
TransactionFlow = false,
TransactionProtocol = TransactionProtocol.Default,
TransferMode = TransferMode.Buffered,
OpenTimeout = new TimeSpan(0, 10, 0),
CloseTimeout = new TimeSpan(0, 10, 0),
SendTimeout = new TimeSpan(0, 10, 0),
ReceiveTimeout = new TimeSpan(0, 10, 0)
};
container.Register(Component.For<IFtpsServiceFacade>()
.ImplementedBy<FtpsServiceFacade>()
.AsWcfService(
new DefaultServiceModel()
.AddEndpoints(
WcfEndpoint.BoundTo(binding)
.At(string.Format("net.tcp://{0}/FileService.Ftps",
"localhost"))
)).LifestyleSingleton() );
The establishment of the communication channel between the server-side and the client-side requires that the server-side and the client-side have the same binding settings. Therefore, the above error occurred. In order to solve this problem, we should change the settings on the server-side instead of the client-side. The max size of the supported file above 2GB, finished by the below configuration.
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
binding.MaxBufferSize = Int32.MaxValue;
binding.MaxBufferPoolSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
Especially to the security mode, it should be fully consistent with the setting located on the client-side.
Feel free to let me know if the problem still exists.

Moving service configuration from the config to code

I have the following configuration in my app.config:
<bindings>
<customBinding>
<binding name="myBinding">
<textMessageEncoding messageVersion="Soap12"/>
<httpTransport/>
</binding>
</customBinding>
<wsHttpBinding>
<binding name="myBinding" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8">
<security mode="Transport">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="/../" binding="wsHttpBinding" bindingConfiguration="myBinding" contract="myContract" name="myName"/>
</client>
Using this configuration the service works as expected.
For several reasons i can't use the app.config file in the production environment, so i want to define the bindings in c# instead. I did the following:
var binding = new BasicHttpBinding();
var address = new EndpointAddress(url);
binding.Security = new BasicHttpSecurity() { Mode = BasicHttpSecurityMode.Transport };
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
var client = new MyClient(binding, address);
This works for the first part, but then fails on using an incorrect message version. I can see this is defined in the custombinding, but i'm not sure how to translate this binding to my code. I did try quite a lot, but with no result so far.
Does anyone know how to do this?
I would recommend you to leverage the ConfigurationChannelFactory<TChannel> class to configure your client using XML configuration from a source other than an app.config file (e.g. an XML string read from a database, from a resource in your executable, or from some other custom source).
The XML format is IMHO easier to read and maintain than a configuration built using code.
To do this, the steps are as follows:
Get a string with your XML configuration data, e.g.:
string configurationData = #"<configuration>
<system.serviceModel>
...
";
Save it to a temporary file:
var tempFileName = Path.GetTempFileName();
File.WriteAllText(tempFileName, configurationData);
Generate a System.Configuration.Configuration object from the temp file:
var filemap = new ExeConfigurationFileMap
{
ExeConfigFilename = tempFileName
};
var config = ConfigurationManager.OpenMappedExeConfiguration(filemap, ConfigurationUserLevel.None);
Create a ChannelFactory<TChannel> from the configuration:
var channelFactory = new ConfigurationChannelFactory<TChannel>(endpointConfigurationName, config, remoteAddress);
Once you've created your ChannelFactory<TChannel>, you can delete the temporary file.
You are using BasicHttpBinding instead of CustomBinding
you should do something like this:
var binding = new CustomBinding();
TextMessageEncodingBindingElement textBindingElement = new TextMessageEncodingBindingElement
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None),
WriteEncoding = System.Text.Encoding.UTF8,
ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max
};
binding.Elements.Add(textBindingElement);
But, if you are using .net core you might have issues with this, because there is an open issue for this on GitHub: https://github.com/dotnet/wcf/issues/2711
It seems you are using wshttpbinding.
You could try the code below.Please change to your address and contract.
WSHttpBinding wsbinding = new WSHttpBinding();
wsbinding.MaxBufferPoolSize = 2147483647;
wsbinding.MaxReceivedMessageSize = 2147483647;
wsbinding.MessageEncoding = WSMessageEncoding.Mtom;
wsbinding.TextEncoding = Encoding.UTF8;
wsbinding.Security.Mode = SecurityMode.Transport;
wsbinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
using (ChannelFactory<ICalculatorService> channelFacoty = new ChannelFactory<ICalculatorService>(wsbinding, new EndpointAddress("http://localhost")))
{
ICalculatorService cal = channelFacoty.CreateChannel();
Console.WriteLine( cal.Add(1, 3));
Console.Read();
}
Try the WebHttBinding:
binding = new WebHttpBinding
{
TransferMode = TransferMode.Buffered,
ReceiveTimeout = TimeSpan.FromMinutes(1),
SendTimeout = TimeSpan.FromMinutes(1),
MaxReceivedMessageSize = 2147483647,
MaxBufferPoolSize = 2147483647,
ReaderQuotas =
{
MaxDepth = 2147483647,
MaxStringContentLength = 2147483647,
MaxArrayLength = 2147483647,
MaxBytesPerRead = 2147483647,
MaxNameTableCharCount = 2147483647
},
Security = new WebHttpSecurity()
{
Mode = WebHttpSecurityMode.Transport,
Transport = new HttpTransportSecurity()
{
ClientCredentialType = HttpClientCredentialType.Ntlm
}
}
};

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: How do I add a ServiceThrottlingBehavior to a WCF Service?

I have the below code for returning back an instance of my WCF Service ServiceClient:
var readerQuotas = new XmlDictionaryReaderQuotas()
{
MaxDepth = 6000000,
MaxStringContentLength = 6000000,
MaxArrayLength = 6000000,
MaxBytesPerRead = 6000000,
MaxNameTableCharCount = 6000000
};
var throttlingBehaviour = new ServiceThrottlingBehavior(){MaxConcurrentCalls=500,MaxConcurrentInstances=500,MaxConcurrentSessions = 500};
binding = new WSHttpBinding(SecurityMode.None) {MaxReceivedMessageSize = 6000000, ReaderQuotas = readerQuotas};
dualBinding = new WSDualHttpBinding(WSDualHttpSecurityMode.None)
{MaxReceivedMessageSize = 6000000, ReaderQuotas = readerQuotas};
endpointAddress = new EndpointAddress("http://localhost:28666/DBInteractionGateway.svc");
return new MusicRepo_DBAccess_ServiceClient(new InstanceContext(instanceContext), dualBinding, endpointAddress);
Lately I was having some trouble with timeouts and so I decided to add a throttling behavior, like such:
var throttlingBehaviour = new ServiceThrottlingBehavior () {
MaxConcurrentCalls=500,
MaxConcurrentInstances=500,
MaxConcurrentSessions = 500
};
My question is, where in the above code should I add this throttlingBehaviour to my MusicRepo_DBAccess_ServiceClient instance?
From some of the examples I found on the web, they are doing something like this:
ServiceHost host = new ServiceHost(typeof(MyService));
ServiceThrottlingBehavior throttleBehavior = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 40,
MaxConcurrentInstances = 20,
MaxConcurrentSessions = 20,
};
host.Description.Behaviors.Add(throttleBehavior);
host.Open();
Notice that in the above code they are using a ServiceHost whereas I am not, and they are then opening it (with Open()) whereas I open the MusicRepo_DBAccess_ServiceClient instance...and this is what got me confused.
Can be done in code for those, like me, who configure at runtime.
vb version:
Dim stb As New ServiceThrottlingBehavior
stb.MaxConcurrentSessions = 100
stb.MaxConcurrentCalls = 100
stb.MaxConcurrentInstances = 100
ServiceHost.Description.Behaviors.Add(stb)
c# version:
ServiceThrottlingBehavior stb = new ServiceThrottlingBehavior {
MaxConcurrentSessions = 100,
MaxConcurrentCalls = 100,
MaxConcurrentInstances = 100
};
ServiceHost.Description.Behaviors.Add(stb);
Throttling is a service side (server) behavior not client side one
Arnon
You can specify the behavior in the configuration file afaik, and the generated client will obey, using behaviors.
Some configuration sections excluded for brevity
<service
behaviorConfiguration="throttleThis" />
<serviceBehaviors>
<behavior name="throttleThis">
<serviceMetadata httpGetEnabled="True" />
<serviceThrottling
maxConcurrentCalls="40"
maxConcurrentInstances="20"
maxConcurrentSessions="20"/>
</behavior>
</serviceBehaviors>

Categories

Resources