What is the default timeout for the basichttpbinding in wcf - wcf

I am new to wcf, created a service and a consumer. As documentation suggest, default timeout is 10 minutes for ReceiveTimeout.
In consumer side, i tried to reproduce for timeout for the request but event after 25 minutes it works without breaking.
If someone can let me know what exactly the time we can open a channel with basichttp binding?
Below is the wcf app.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="Raj">
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm="">
</transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Raj">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="WCF_NewsService.News_Service" behaviorConfiguration="Raj">
<host>
<baseAddresses>
<add baseAddress="https://localhost:8732/Design_Time_Addresses/WCF_NewsService/News_Service/"/>
</baseAddresses>
</host>
<endpoint address="News_Service" binding="basicHttpBinding" contract="WCF_NewsService.INews_Service" bindingConfiguration="Raj"/>
</service>
</services>
</system.serviceModel>
Consumer Code:
var myBinding = new BasicHttpBinding();
myBinding.Security.Mode = BasicHttpSecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Certificate;
myBinding.MaxReceivedMessageSize = Int32.MaxValue;
myBinding.MaxBufferSize = Int32.MaxValue;
BindingParameterCollection bindingParameters = new BindingParameterCollection();
var address = new EndpointAddress("https:xxxx:8732/Design_Time_Addresses/WCF_NewsService/News_Service/News_Service");
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
//Client Credentials
string _thumbPrint = "5AD9BC96AA4D44852D1B97C91C1628C070E3187C";
ClientCredentials clientCredentials = new ClientCredentials();
clientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, _thumbPrint);
bindingParameters.Add(clientCredentials);
var factory = myBinding.BuildChannelFactory<IRequestChannel>(bindingParameters);
factory.Open();
var irc = factory.CreateChannel(address);
// --- Without body
Message createRequestMessage = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/INews_Service/Getnews");
irc.Open();
var result = irc.Request(createRequestMessage);
Thread.Sleep(TimeSpan.FromMinutes(25));
//--With body
TOInews tOInews = new TOInews { ID = 125, Body = "this is body test", Header = "This is header test" };
createRequestMessage = Message.CreateMessage(MessageVersion.Soap11, "http://tempuri.org/INews_Service/GetnewsById", tOInews);
//irc.Open();
var result1 = irc.Request(createRequestMessage);

ReceiveTimeout – used by the Service Framework Layer to initialize the session-idle timeout which controls how long a session can be idle before timing out.
I didn't find that you have ReceiveTimeout configured in the config file, you need to configure it.You can see the code below.You can check the documentation on how to configure the timeout value on the binding.
You can use Message Inspectors to capture WCF operation execution time. See this post for specific steps.
<basicHttpBinding>
<binding name="Raj" openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm="">
</transport>
</security>
</binding>
</basicHttpBinding>

Related

Problem increasing WCF service endpoint size configuration

I have an asp.net project that was hosting a WCF service (via the wcf file exposure technique for IIS) that was put together around 10 years ago. There is an operation on the service that retrieves content that is greater than the default 75K limit. The service configuration (in web.config) property on the binding was adjusted to be larger than the default and was working ok. The ASP.NET project was upgraded in VS2017/2019 - and (I assume) the project was adjusted (somehow). The service operation described above no longer works. I did a lot of investigation and all solutions were handled (which makes sense as the original version of the project was working). I even went through the process of building a new web.config with minimal configuration and still did not work. I also adjusted the service to include the Configure operation that could be used to configure the endpoint configuration in code. It also did not work. For this I have the following:
public static void Configure(ServiceConfiguration config)
{
BasicHttpBinding binding = new BasicHttpBinding();
binding.MaxReceivedMessageSize = int.MaxValue;
binding.MaxBufferSize = int.MaxValue;
binding.MaxBufferPoolSize = int.MaxValue;
binding.BypassProxyOnLocal = true;
binding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
{
MaxStringContentLength = int.MaxValue,
MaxDepth = int.MaxValue,
MaxArrayLength = int.MaxValue,
MaxBytesPerRead = int.MaxValue,
MaxNameTableCharCount = int.MaxValue
};
var endpoint = new ServiceEndpoint(
ContractDescription.GetContract(
typeof(IAuthenticateServicePack)),binding,new
EndpointAddress("http://localhost:49437/WCFSevices/AuthenticateServicePack.svc"));
//MyEndpointBehavior Behavior = new MyEndpointBehavior();
//endpoint.Behaviors.Add(Behavior);
config.AddServiceEndpoint(endpoint);
}
The web.config definitions is the following
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true"
/>
<behaviors>
<serviceBehaviors>
<behavior name="ServicePack.ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceThrottling maxConcurrentCalls="500" maxConcurrentSessions="500"
/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<clear />
<binding name="myBindingForBigArrays" maxReceivedMessageSize="2147483647"
transferMode="Buffered">
<readerQuotas
maxDepth="32"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="4096"
maxNameTableCharCount="10000"
/>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="Lapp.WebAdmin.Mvc.WCFSevices.AuthenticateServicePack"
behaviorConfiguration="ServicePack.ServiceBehavior">
<endpoint address="" binding="basicHttpBinding"
bindingConfiguration="myBindingForBigArrays"
contract="Lapp.WebAdmin.Mvc.WCFSevices.IAuthenticateServicePack" />
<host>
<timeouts closeTimeout="00:01:00" />
</host>
</service>
</services>
</system.serviceModel>
For some reason - the updated asp.net project does not seem to be handling the WCF service endpoint configuration. Has anyone run into this issue?
Note: I can test the older version of the service and is working properly -- and reviewing the old config with the new -- cannot identify any modification that would appear to be causing the new not to use the size limit settings.

Configuring WCF client binding to use X509 certificate in dotnet core 2.2

I'm trying to convert an old WCF client to dotnet core. I successfully generated my proxies from the wsdl and have been trying to configure them so I can successfully call the endpoint. It appears, based on some googling, that under dotnet core I need to configure my WCF client from code.
Here's the WCF configuration section from the web.config of the old application:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<endpointBehaviors>
<behavior name="clientEndpointCredential">
<clientCredentials>
<clientCertificate storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName" findValue="CERTNAME" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="OUR_Customer_OUTBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="Certificate" proxyCredentialType="None" realm="" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://the-full-url" behaviorConfiguration="clientEndpointCredential" binding="basicHttpBinding" bindingConfiguration="OUR_Customer_OUTBinding" contract="CustomerInterface.OUR_Customer_OUT" name="HTTPS_Port" />
</client>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="false" maxMessagesToLog="3000" />
</diagnostics>
</system.serviceModel>
Here's what I've come up with to configure it in dotnet core:
private OUR_Customer_OUTClient GetCustomerClient()
{
TimeSpan Minutes(int minutes) => new TimeSpan(0, minutes, 0);
var binding = new BasicHttpBinding();
binding.Name = "OUR_Customer_OUTBinding";
binding.AllowCookies = false;
binding.SendTimeout = Minutes(1);
binding.ReceiveTimeout = Minutes(10);
binding.OpenTimeout = Minutes(1);
binding.CloseTimeout = Minutes(1);
binding.MaxBufferPoolSize = 2147483647;
binding.MaxReceivedMessageSize = 2147483647;
binding.TextEncoding = Encoding.UTF8;
binding.TransferMode = TransferMode.Buffered;
binding.BypassProxyOnLocal = false;
binding.UseDefaultWebProxy = true;
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
var endpointAddress = new EndpointAddress("https://the-full-url");
var client = new OUR_Customer_OUTClient(binding, endpointAddress);
client.ClientCredentials.ClientCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindBySubjectName,
"CERTNAME");
return client;
}
And here's the code I'm using to call the endpoint (dotnet core proxies don't yet support synchronous calls):
SearchResponse searchResponse = Task.Run(() => GetCustomerClient().SearchAsync(message)).Result;
However, I'm getting the following error:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Basic realm="XISOAPApps"'
Can anyone see anything wrong with my approach or suggest ways I could use to debug this? I'm a WCF newbie and am tearing my hair out at this point.
For the benefit of any others who may be unlucky enough to hit the same problem, the central issue turned out to be that the X509 certificate was not being sent. (The endpoint we were hitting accepted either a certificate or basic auth, thus the 401.)
The reason the certificate wasn't being sent was because the dotnet core networking stack is stricter than the .NET one, and requires the certificate to either have its Enhanced Key Usage set to ClientAuthentication (1.3.6.1.5.5.7.3.2) or have no EKU at all (see the source code here). Ours wasn't - it was set to Server Authentication. So the certificate was quietly discarded, despite having been loaded up successfully.
This github issue provides further details.
Your code snippets seem good. We may have one more thing to do. when server authenticates the client with a certificate, we should establish the trust relationship each other, please refer to the below link.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication
Besides, we should provider an Identity flag to identity the server, like below.
<client>
<endpoint address="http://vabqia593vm:4434/Service1.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1" name="WSHttpBinding_IService1" behaviorConfiguration="mybeh">
<identity>
<dns value="vabqia130vm"/>
</identity>
</endpoint>
</client>
We could generate client proxy class by Micorosoft WCF Web Service Reference Provider.(Add Connected Services).
Feel free to let me know if there is anything I can help with.
Abraham

Disable CustomUserNamePasswordValidator for specific operation

I am using a CustomUserNamePasswordValidator for my WCF web service. However, i am trying to add a IsAlive operation, which should be able to be called from clients, even when not authenticated.
For example, i want to be able to do a check, if a service is online and accessible on startup, so i can notify the user on missing inet connection or a not available service (due to maintenance).
I have code for all this already in place. What i am missing is how i can access the operation without passing a username and password.
I could probably just add a second service which allows anon access, but i'd really prefer to use the existing service.
The Validator is implemented like this (i ommited the actual checking code):
public sealed class MyCredentialValidator : UserNamePasswordValidator
{
public MyCredentialValidator ()
{
}
public override void Validate(string userName, string password)
{
Debug.WriteLine("MyCredentialValidator : Validate called.");
// do some checks
var isValid = CheckCredentials(userName, password)
if(!isValid)
{
throw new FaultException(...);
}
}
}
It is registered in the web.config like so:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="SecureBehavior">
<serviceMetadata httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyCredentialValidator,..."/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
<bindings>
<wsHttpBinding>
<binding name="SecureBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxStringContentLength="2147483647"/>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="my service" behaviorConfiguration="SecureBehavior">
<endpoint address="" binding="wsHttpBinding" contract="my contract" bindingConfiguration="SecureBinding">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
client side configuration:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="SecureBinding"
closeTimeout="00:10:00"
openTimeout="00:10:00"
receiveTimeout="00:10:00"
sendTimeout="00:10:00"
maxReceivedMessageSize="2147483647">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
<readerQuotas maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxStringContentLength="2147483647"/>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://my service url"
contract="my contract"
binding="wsHttpBinding"
bindingConfiguration="SecureBinding"
name="secure" />
</client>
</system.serviceModel>
client side wcf call code:
var cf = new ChannelFactory<my contract>("secure");
using (IClientChannel channel = (IClientChannel)cf.CreateChannel())
{
channel.OperationTimeout = TimeSpan.FromSeconds(3);
bool success = false;
try
{
channel.Open();
result = ((my contract)channel).IsAlive();
channel.Close();
success = true;
}
finally
{
if (!success)
{
channel.Abort();
}
}
}
I have done something like this before,
depending on how you have integrated your custom validator in the wcf pipleline,
you could simply before you do the actual validation, which I guess returns something like true or false, you could check the incoming url or address and see if it is going to be going to your IsAlive operation, if that is the case, you could simply do a early return true.
Wcf has a few ways with which you can check what operation the client has called.
to be more accurate, I would need to know how you wrote your custom validator and where in the pipeline it integrates.

WCF Service over netTCPBinding timing out for Clients in LN, working fine for Clients in US

I have a WCF Service exposed via TCPbinding running on a server in NY. I have no issues connecting to the service and getting back the results from clients connecting to this service from Americas but having issues for clients from London/Europe. I am not quite sure why this timeout issue happens but below are by Client and Server settings.
Server
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="TCPBinding_IDataService"
receiveTimeout="00:20:00"
openTimeout="00:05:00"
maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647"
maxConnections="10"
maxBufferSize="2147483647">
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
<security mode="Message">
<message clientCredentialType="Windows"/>
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="DataServiceBehavior" name="DIT.Data.DRD.Service.PIERDataService">
<endpoint address="DataService" binding="netTcpBinding" bindingConfiguration="TCPBinding_IDataService"
contract="DIT.Data.DRD.Service.IPIERDataService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="MEX" binding="mexTcpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:9100/DRDService"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DataServiceBehavior" >
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="false"/>
<dataContractSerializer maxItemsInObjectGraph="61200000" />
<serviceThrottling maxConcurrentCalls="100"
maxConcurrentInstances="1000"/>
</behavior>
</serviceBehaviors>
</behaviors>
<diagnostics performanceCounters="Default">
<messageLogging logEntireMessage="true" logMalformedMessages="false"
logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="false" />
</diagnostics></system.serviceModel>
My client has the following settings in C# code
private DataServiceClient GetClient(string uri, int? timeout)
{
EndpointAddress endpointAddress = new EndpointAddress(new Uri(uri),
EndpointIdentity.CreateDnsIdentity("localhost"),
new System.ServiceModel.Channels.AddressHeaderCollection());
NetTcpBinding svcBinding = new NetTcpBinding();
svcBinding.Security.Mode = SecurityMode.Message;
svcBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
svcBinding.MaxReceivedMessageSize = 2147483647;
svcBinding.MaxBufferPoolSize = 2147483647;
svcBinding.MaxBufferSize = 2147483647;
svcBinding.MaxConnections = 10;
svcBinding.ReaderQuotas.MaxBytesPerRead = 2147483647;
svcBinding.ReaderQuotas.MaxDepth = 2147483647;
svcBinding.ReaderQuotas.MaxArrayLength = 2147483647;
svcBinding.ReaderQuotas.MaxNameTableCharCount = 2147483647;
svcBinding.ReaderQuotas.MaxStringContentLength = 2147483647;
if (timeout.HasValue)
svcBinding.SendTimeout = svcBinding.ReceiveTimeout = new TimeSpan(0, timeout.Value, 0);
else
svcBinding.SendTimeout = svcBinding.ReceiveTimeout = new TimeSpan(0, 5, 0); // this is default
PIERDataServiceClient dsc = new PIERDataServiceClient(svcBinding, endpointAddress); //this is wcf client from ClientBase
return dsc;
}
Can someone having experience with WCF timeout issues shed some light on this? I've been trying to follow the gzillion posts on various forums but the understanding I gathered and implementation in the form of code and configuration is not helping much.
TIA,
Shravan

In WCF, for a webHttpBinding, how do I specify credentials in the client side web.config when the server is using basic authentication?

I have two WCF RESTful services - the "general" service is public and has no security; the "admin" service I intend to use basic authentication over SSL. This is my server side web.config:
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="general" maxReceivedMessageSize="2147483647">
<readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" />
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
<binding name="admin" maxReceivedMessageSize="2147483647">
<readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" />
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="MyNamespace.AppServices.GeneralService">
<endpoint address="" binding="webHttpBinding" contract="MyNamespace.Contracts.IGeneralService" behaviorConfiguration="web" bindingConfiguration="general" />
</service>
<service name="MyNamespace.AppServices.AdminService">
<endpoint address="" binding="webHttpBinding" contract="MyNamespace.Contracts.IAdminService" behaviorConfiguration="web" bindingConfiguration="admin" />
</service>
</services>
</system.serviceModel>
On the client side, I currently have code that looks like this:
private static IGeneralService GetGeneralChannel()
{
WebHttpBinding binding = new WebHttpBinding();
binding.Security.Mode = WebHttpSecurityMode.None;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
binding.ReaderQuotas.MaxArrayLength = Int32.MaxValue;
WebChannelFactory<IGeneralService> cf = new WebChannelFactory<IGeneralService>(binding, new Uri("http://localhost:1066/GeneralService"));
IGeneralService channel = cf.CreateChannel();
return channel;
}
private static IAdminService GetAdminChannel()
{
WebHttpBinding binding = new WebHttpBinding();
binding.Security.Mode = WebHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
binding.ReaderQuotas.MaxArrayLength = Int32.MaxValue;
WebChannelFactory<IAdminService> cf = new WebChannelFactory<IAdminService>(binding, new Uri("http://localhost:1066/AdminService"));
cf.Credentials.UserName.UserName = "myUserName";
cf.Credentials.UserName.Password = "myPassword";
IAdminService channel = cf.CreateChannel();
return channel;
}
The question is, since I obviously do not want to hard-code all of this configuration information, how do I need to provide it in the web.config on the client? It is pretty clear to me that the binding element needs to look pretty much the same on the client as it does on the server. However, where do I indicate the credentials that are assigned to the WebChannelFactory?
Any help and/or insight will be appreciated.
Thanks,
Steve
You cannot put those credentials (username and password) into web.config and have WCF read them from there. This is one of the very few features in WCF which cannot be done in config - you have to set those credentials in your code.
Of course, in your code, you can read them from e.g. a database table, or a config entry somewhere - but you have to do that yourself. WCF can't be configured to automagically read those settings from somewhere.