WCF: How do I add a ServiceThrottlingBehavior to a WCF Service? - c#

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>

Related

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

How to host two WCF services with .net.tcp binding in windows Service

i want to host two services
Service 1 (located on D Drive)
process data based on configuration configured in xml
net.tcp://ServerIP/Pune_service
Service 2 (located on E Drive)
process data based on configuration configured in xml
net.tcp://ServerIP/Mumbai_service
now i tried to host these services with net.tcp binding in two different Windows Service
Windows service 1 Started Successfully
but when tried to start second windows service i'am getting Error i.e.
AddressAlreadyInUseException
string httpBaseAddress = "http://" + _szServerIP + "/" + _szCurruntLocation + "_FileServer";
string tcpBaseAddress = "net.tcp://" + _szServerIP + "/" + _szCurruntLocation + "_FileServer";
Uri[] adrbase = { new Uri(httpBaseAddress), new Uri(tcpBaseAddress) };
m_svcHost = new ServiceHost(typeof(MyService.CalcServiceClient), adrbase);
ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior();
//mBehave.AddressFilterMode=AddressFilterMode.Any)]
m_svcHost.Description.Behaviors.Add(mBehave);
BasicHttpBinding httpb = new BasicHttpBinding();
m_svcHost.AddServiceEndpoint(typeof(MyService.ICalcService), httpb, httpBaseAddress);
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
NetTcpBinding tcpb = new NetTcpBinding();
tcpb.MaxConnections = 10;
tcpb.MaxReceivedMessageSize = Int32.MaxValue;
tcpb.MaxBufferPoolSize = Int32.MaxValue;
tcpb.MaxBufferSize = Int32.MaxValue;
tcpb.ReceiveTimeout = new TimeSpan(0, 10, 0);
tcpb.OpenTimeout = new TimeSpan(0, 10, 0);
tcpb.CloseTimeout = new TimeSpan(0, 10, 0);
tcpb.PortSharingEnabled = true;
m_svcHost.AddServiceEndpoint(typeof(MyService.ICalcService), tcpb, tcpBaseAddress);
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
m_svcHost.Open();
Console.WriteLine("Service is live now at : {0}", httpBaseAddress);
Console.ReadLine();
Here is the link for AddressAlreadyInUseException.
I think you may remove;
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
You are trying to add a second IMetadataExchange contract for tcp binding.
Also you need to add;
mBehave.HttpGetEnabled = true;
to get mex information.
As far as I know,MexTcpBinding disable the port sharing. Which means that:
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
CustomBinding mexBinding2 = new CustomBinding(mexBinding);
mexBinding2.Elements.Find<TcpTransportBindingElement>().PortSharingEnabled==false //true
Here is an article worth reading.
https://blogs.msdn.microsoft.com/drnick/2006/08/23/an-unanticipated-addendum-for-certain-mex-scenarios/
I suggest you could write the custom binding, and then add the binding to the mex endpoint.
TextMessageEncodingBindingElement encoding = new TextMessageEncodingBindingElement();
TcpTransportBindingElement transport = new TcpTransportBindingElement();
transport.PortSharingEnabled = true;
CustomBinding binding1 = new CustomBinding(encoding, transport);
m_svcHost.AddServiceEndpoint(typeof(IService), tcpb, tcpBaseAddress);
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), binding1, "mex");
Here is related issue on this topic.
https://blogs.msdn.microsoft.com/praburaj/2012/10/16/nettcpbinding-mextcpbinding-sharing-same-port-throws-addressalreadyinuseexception-on-upgrade-to-net-4-5/
you could also comment the following lines to ensure that codes run correctly.
tcpb.MaxConnections = 10;
tcpb.PortSharingEnabled = true;

C# How to Update Visual Studio 2107 xxx.exe.config binding at runtime?

A xxx.exe.config file is created when I compile my C# web service code. However, I want to modify one of the bindings at run time. An example of the xxx.exe.config file generated by Visual Studio is:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ContentService"
messageEncoding="Mtom" />
</basicHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
I want to add some parameters at run time to the binding named "BasicHttpBinding_ContentService" that are equivalent to manually coding:
<binding name="BasicHttpBinding_ContentService"
messageEncoding="Mtom"
maxBufferSize="5000000"
maxBufferPoolSize="524288"
maxReceivedMessageSize="2147483648"
transferMode="Streamed" />
I think the C# code to define the parameter settings looks like:
using System.ServiceModel;
BasicHttpBinding myBinding = new BasicHttpBinding("BasicHttpBinding_ContentService");
myBinding.MaxBufferSize = 5000000;
myBinding.MaxBufferPoolSize = 524288;
myBinding.MaxReceivedMessageSize = 2147483648;
myBinding.TransferMode = TransferMode.Streamed;
But I can't find a C# example (that works) that applies 'myBinding' to my Visual Studio .config file. The samples I do find reference classes like ServiceHost and ServiceClient that are undefined in my environment.
Note - I am using .NET 4.6.
I change quite alot of service endpoint on the fly but never use the config. I bind the webreference once then call it by code so i can change properties on the fly. Here's a very compact sample showing one that actually works
var binding = new BasicHttpBinding();
binding.CloseTimeout = new TimeSpan(0, 1, 30);
binding.OpenTimeout = new TimeSpan(0, 1, 30);
binding.ReceiveTimeout = new TimeSpan(0, 1, 30);
binding.SendTimeout = new TimeSpan(0, 1, 30);
binding.MaxReceivedMessageSize = 100000000;
binding.ReaderQuotas.MaxDepth = 2147483647;
binding.ReaderQuotas.MaxStringContentLength = 2147483647;
binding.ReaderQuotas.MaxArrayLength = 2147483647;
binding.ReaderQuotas.MaxBytesPerRead = 2147483647;
binding.ReaderQuotas.MaxNameTableCharCount = 2147483647;
var endpoint = new EndpointAddress("http:\\example.com\MyService\Service.svc");
// MyService is the service object name that is in the web reference
var svc = new MyService.Service(binding, endpoint);
var clientData = svc.GetClientData("SomeClientName");
try something like this and let me know...
NTEGRAWSSOAPClient _wsProtheus = null; // NTEGRAWSSOAPClient is a SOAP client class generated by vs2017 on register webservice
var endpointConfiguration = NTEGRAWSSOAPClient.EndpointConfiguration.INTEGRAWSSOAP; //INTEGRAWSSOAP is a ConfigurationName of service
_wsProtheus = new NTEGRAWSSOAPClient(endpointConfiguration,new EndpointAddress("http://new address?wsdl", new SpnEndpointIdentity("your identi")));
BasicHttpBinding bind = (BasicHttpBinding)_wsProtheus.Endpoint.Binding;
bind.CloseTimeout = TimeSpan.Parse("02:00:00");
bind.OpenTimeout = TimeSpan.Parse("02:00:00");
bind.ReceiveTimeout = TimeSpan.Parse("02:00:00");
bind.SendTimeout = TimeSpan.Parse("02:00:00");
bind.MaxBufferPoolSize = Int32.MaxValue;
bind.MaxBufferSize = Int32.MaxValue;
bind.MaxReceivedMessageSize = Int32.MaxValue;
bind.ReaderQuotas.MaxDepth = 32;
bind.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
bind.ReaderQuotas.MaxArrayLength = Int32.MaxValue;
bind.ReaderQuotas.MaxBytesPerRead = Int32.MaxValue;
bind.ReaderQuotas.MaxNameTableCharCount = Int32.MaxValue;
bind.Security.Mode = BasicHttpSecurityMode.None;

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 client request returns bad request (400)

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.

Categories

Resources