I'm using WCF in communication between a server and client (both written in C#).
In release-mode, the timouts should be set to ~20 seconds, but in debug mode I want to set them to a higher value so that I can debug/step in my code without the timeout occurring.
I know that I can change the timeouts by modifying the app.config file. However, I've got two different bindings and 4 time out values in each so I would have to change in several places, and its easy to forget.
To solve this, I would like to have a small #if DEBUG-section in my code which programmatically changes the timeout values to 1 hour.
I tried to use the following code to do this:
Configuration configuration =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ServiceModelSectionGroup serviceModel =
ServiceModelSectionGroup.GetSectionGroup(configuration);
BindingsSection bindings = serviceModel.Bindings;
foreach (var configuredBinding in bindings.WSHttpBinding.ConfiguredBindings)
{
configuredBinding.CloseTimeout = new TimeSpan(0, 30, 0);
configuredBinding.OpenTimeout = new TimeSpan(0, 30, 0);
but the *Timeout properties are readonly so I get a compilation error.
I'm not fond of the idea of creating bindings from scratch programmatically. If I change some of the attributes in the app.config, I have to remember to do the same change in the code to make sure that the debug-behavior is similar to the release-behavior (except for the timeouts..)
How to handle this?
You could do the following:
create the binding and the endpoint in code
set the timeouts on the binding instance
then create your client proxy using those two elements
Something like:
BasicHttpBinding myBinding = new BasicHttpBinding("ConfigName");
myBinding.CloseTimeout = .......
myBinding.OpenTimeout = .......
myBinding.ReceiveTimeout = .......
myBinding.SendTimeout = .......
EndpointAddress myEndpoint = new EndpointAddress("http://server:8181/yourservice");
YourServiceClient proxy = new YourServiceClient(myBinding, myEndpoint);
That way, you can leverage the basic config when describing binding timeouts and yet you can tweak the settings you want and create your client proxy from it.
You can create a second binding in the web.config and set a longer sendTimeout.
if (debug)
{
proxy = new MyClient("WSHttpBinding_MyLocal");
}
else
{
proxy = new MyClient("WSHttpBinding_MyDev");
}
<wsHttpBinding>
<binding name="WSHttpBinding_MyLocal" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:20:00"
...
Related
We have some weird behavior with WCF bindings configured in configuration files.
We do service calls that may be long-running so we need a send-/operation-timeout longer than the default 1 minute.
Our WCF configuration reflects that, setting sendTimeout to 10 minutes.
But if the service call exceeds 1 minute there is an error message saying the operation timed out after 1 minute at the one-minute mark.
Debugging this we check whether the configuration is correct, like this (here the service call made is shorter than 1 minute for the purpose of debugging):
public class MyWcfClient : ClientBase<IMyWcf>, IMyWcf
{
public ResultType MyMethod()
{
var originalBinding = base.Endpoint.Binding;
var result = this.Channel.MyMethod();
var changedBinding = base.Endpoint.Binding;
return result;
}
}
Here originalBinding will contain the configured settings (sendTimeout = 10 minutes, etc.). But after the call, checking the changedBinding variable, there are other values in the binding, among others the sendTimeout is 1 minute
and it seems the latter one is the one used by the service-call considering the timeout response when making a long-running call. The type of the binding has changed as well from NetTcpBinding to CustomBinding.
Now changing the code slightly, to:
public class MyWcfClient : ClientBase<IMyWcf>, IMyWcf
{
public void MyMethod()
{
var originalBinding = base.Endpoint.Binding;
var sendTimeout = ((IContextChannel)base.Channel).OperationTimeout;
var changedBinding = base.Endpoint.Binding;
}
}
Here we get the same behavior when it comes to the binding values as before. The variable sendTimeout gets value 1 minute, so again it seems the changed binding value is the one honored.
A third example, setting OperationTimeout explicitly before making the service call the set value is honored.
public class MyWcfClient : ClientBase<IMyWcf>, IMyWcf
{
public ResultType MyMethod()
{
((IContextChannel)base.Channel).OperationTimeout = TimeSpan.FromMinutes(10);
var result = this.Channel.MyMethod();
return result;
}
}
Here when making a long-running service-call (though less than 10 minutes) there is no timeout.
So it works setting timeout explicitly in code but we would like to do it all in configuration files.
The binding looks similar to this (same on server and client side):
<binding name="NetTcpBinding"
sendTimeout="00:10:00"
receiveTimeout="00:10:00"
openTimeout="00:10:00"
closeTimeout="00:10:00"
transactionFlow="false"
portSharingEnabled="true"
maxReceivedMessageSize="2147483647"
maxBufferPoolSize="2147483647"
maxBufferSize="2147483647" >
...
</binding>
Any ideas on the explanation for this? What can we do for the configuration to be honored?
Turns out this is a bug in the telemetryClient Wcf-extension. Without it the binding is kept and the timeout works.
https://github.com/Microsoft/ApplicationInsights-SDK-Labs/issues/124
I am posting this because I was unable to find any place on Stack Overflow that addresses this issue for a .Net-Core project utilizing WCF by adding the service reference through Connected Services.
My issue was that I was facing client side timeouts because of long running operation requests.
So, how does one increase the timeout values for the wcf client objects since .Net-Core no longer uses the web config to store the configuration values for the WCF service references? (Please see my provided answer)
Under Connected Services in Solution Explorer, after adding a WCF service, a few files are generated for that service. You should see a folder with the name you gave the WCF service reference and under that a Getting Started, ConnectedService.json and a Reference.cs file.
To increase any of the client service object's timeout values, open Reference.cs and locate method: GetBindingForEndpoint
Inside this method you should see something like this:
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_IYourService))
{
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
result.MaxBufferSize = int.MaxValue;
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
result.MaxReceivedMessageSize = int.MaxValue;
result.AllowCookies = true;
//Here's where you can set the timeout values
result.SendTimeout = new System.TimeSpan(0, 5, 0);
result.ReceiveTimeout = new System.TimeSpan(0, 5, 0);
return result;
}
Just use result. and the timeout you want to increase like SendTimeout, ReceiveTimeout, etc. and set it to a new TimeSpan with the desired timeout value.
I hope this proves to be a useful post to someone.
Answer by Ryan Wilson will work but only until you will try to update service. Reference.cs will be overwritten.
In .NET Core 3.1 you can grammatically modify binding timeouts:
public MemoqTMServiceClass(string api_key)
{
client = new TMServiceClient();
var eab = new EndpointAddressBuilder(client.Endpoint.Address);
eab.Headers.Add(
AddressHeader.CreateAddressHeader("ApiKey", // Header Name
string.Empty, // Namespace
api_key)); // Header Value
client.Endpoint.Address = eab.ToEndpointAddress();
client.Endpoint.Binding.CloseTimeout = new TimeSpan(2, 0, 0);
client.Endpoint.Binding.OpenTimeout = new TimeSpan(2, 0, 0);
client.Endpoint.Binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
client.Endpoint.Binding.SendTimeout = new TimeSpan(0, 10, 0);
}
Just implement the following partial method in the generated proxy class to configure the service endpoint. Place the partial method in your own file to make sure it will not be overwritten.
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);
We have a WCF service (NetTcpBinding) that sits behind a load balancer. I've read that in order to avoid "stickyniss" I have lower the LeaseTime the channels get in the channel pool.
I've only found samples how to set this value using the config file, but I would like to set it programmaticaly, any pointers?
You can access the LeaseTimeout property via the TcpTransportBindingElement, through the ConnectionPoolSettings property:
TcpTransportBindingElement tcpBE = new TcpTransportBindingElement();
tcpBE.ConnectionPoolSettings.LeaseTimeout = TimeSpan.FromSeconds(1);
If you have a NetTcpBinding object, you'll need to first convert it into a CustomBinding, then access the binding element. The example below shows one way of doing this.
NetTcpBinding myOriginalBinding = CreateBinding();
CustomBinding newBinding = new CustomBinding(myOriginalBinding);
TcpTransportBindingElement tcpBE = newBinding.Elements.Find<TcpTransportBindingElement>();
tcpBE.ConnectionPoolSettings.LeaseTimeout = TimeSpan.FromSeconds(1);
Is there a shortcut for creating the most basic WCF Binding based on the address of a given Endpoint?
Endpoint: net.tcp://localhost:7879/Service.svc
Instead of a big block of if statements...
Binding binding = null;
if (endpoint.StartsWith("net.tcp"))
{
binding = new NetTcpBinding();
}
else if (endpoint.StartWith("http"))
{
binding = new WsHttpBinding();
}
.
.
.
Is there a shortcut in the Framework library that will do this for me that I just can't find or can I not find it because it doesn't publicly exist?
WCF in .NET 4 does that automatically for you - the feature is called default endpoints.
Read about all of WCF 4's new features here: A Developer's Introduction to WCF 4
Default endpoints is about the second or so paragraph into the article.
While WCF 4 supports default service endpoints, it does not support default client endpoints. Unfortunately the methods used by the framework to create default bindings are internal, but the logic behind it is simple, so I have reimplemented it to use on the client side (skipping original caching and tracing logic):
private static Binding GetBinding(string scheme)
{
// replace with ConfigurationManager if not running in ASP.NET
var configuration = WebConfigurationManager.OpenWebConfiguration(null);
var sectionGroup = ServiceModelSectionGroup.GetSectionGroup(configuration);
Debug.Assert(sectionGroup != null, "system.serviceModel configuration section is missing.");
var mapping = sectionGroup.ProtocolMapping.ProtocolMappingCollection
.OfType<ProtocolMappingElement>()
.SingleOrDefault(e => e.Scheme == scheme);
if (mapping == null)
throw new NotSupportedException(string.Format("The URI scheme {0} is not supported.", scheme));
var bindingElement = sectionGroup.Bindings.BindingCollections.Single(e => e.BindingName == mapping.Binding);
var binding = (Binding) Activator.CreateInstance(bindingElement.BindingType);
var bindingConfiguration = bindingElement.ConfiguredBindings.SingleOrDefault(e => e.Name == mapping.BindingConfiguration);
if (bindingConfiguration != null)
bindingConfiguration.ApplyConfiguration(binding);
return binding;
}
Without any configuration this code is equivalent to the code in the question, but you can select and configure your bindings inside the system.serviceModel/protocolMapping section.
After looking at the issue deeper I don't really need to read the configuration in manually. Instead I need to send the binding information along with the address and contract.
http://www.codeproject.com/KB/WCF/WCFDiscovery.aspx?display=PrintAll
I have built a simple component that serializes the binding information.
http://nardax.codeplex.com/
I have a Silverlight 3.0 application that is using a WCF service to communicate with the database, and when I have large amounts of data being returned from the service methods I get Service Not Found errors. I am fairly confident that the solution to it is to simply update the maxItemsInObjectGraph property, but I am creating the service client progrogrammatically and cannot find where to set this property. Here is what I am doing right now:
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
MaxReceivedMessageSize = int.MaxValue,
MaxBufferSize = int.MaxValue
};
MyService.MyServiceServiceClient client = new MyService.MyServiceProxyServiceClient(binding, new EndpointAddress(new Uri(Application.Current.Host.Source, "../MyService.svc")));
It's not defined in binding, but in Service Behavior.
In Silveright, maxItemsInObjectGraph defaults to int.MaxValue.
Here is an article on how to change it for .NET application, but not Silverlight: Programattically setting the MaxItemsInObjectGraph property in client
A snippet of the code:
protected ISecurityAdministrationService GetSecAdminClient()
{
ChannelFactory<ISecurityAdministrationService> factory = new ChannelFactory<ISecurityAdministrationService>(wsSecAdminBinding, SecAdminEndpointAddress);
foreach (OperationDescription op in factory.Endpoint.Contract.Operations)
{
DataContractSerializerOperationBehavior dataContractBehavior =op.Behaviors.Find<DataContractSerializerOperationBehavior>() as DataContractSerializerOperationBehavior;
if (dataContractBehavior != null)
{
dataContractBehavior.MaxItemsInObjectGraph = 2147483647;
}
}
ISecurityAdministrationService client = factory.CreateChannel();
return client;
}
The following is a function that I've used inside a client object that inherits from
System.ServiceModel.ClientBase(Of IServiceName)
The purpose of the method is to programatically set the MaxItemsInObjectGraph value for each operation. This allows me to have much more complex structures.
Private Sub IncreaseObjectCount()
For Each op As System.ServiceModel.Description.OperationDescription In Me.Endpoint.Contract.Operations
For Each dscob As System.ServiceModel.Description.DataContractSerializerOperationBehavior In op.Behaviors.FindAll(Of System.ServiceModel.Description.DataContractSerializerOperationBehavior)()
dcsob.MaxItemsInObjectGraph = Integer.MaxValue
Next dcsob
Next op
End Sub
I usually call it in the constructors of the object.
Change the maxItemsInObjectGraph in your WCF service for each endpoint, changing it in Silverlight means the client will be able to support the behavior, but the service must support it aswell.
After changing it in your service, regenerate the proxy/update web service, and you will get a new ServiceReference.config, that will include the new maxItemsInObjectGraph value