WCF erratically timing out despite binding timeout settings - c#

My system is composed of a bunch of WCF services that can be used by various clients.
The first thing I do is to run the services in interactive mode (I have a console popping and letting me know the service is started).
I can then run a given client that excercises any of my WCF services. When instantiated the client create a channel and associated timeouts in the following way:
var ctx = new InstanceContext(TestCallbackProxy.Instance);
string baseAddress = Constants.ServiceBaseAddress;
var binding = new NetNamedPipeBinding();
binding.MaxConnections = 10;
binding.OpenTimeout = System.TimeSpan.FromMinutes(1);
binding.CloseTimeout = System.TimeSpan.FromMinutes(1);
binding.ReceiveTimeout = System.TimeSpan.FromMinutes(5);
binding.SendTimeout = System.TimeSpan.FromMinutes(5);
var channelFactory = new DuplexChannelFactory<ITestService>(ctx, binding, new EndpointAddress(baseAddress + serviceName));
// Create channel to a specified endpoint
_channel = channelFactory.CreateChannel() as ITestService;
Now, the service eventually times out when left unused for a while, which from my understanding is expected. ie. The channel will simply vanish/be discarded by the system if unused - Something to do with reusablility and optimisation I believe.
However, when trying to prove this theory and reducing all the timeouts, I cannot get the service to break. ie. Should the service not timeout/break when trying to use it when left alone for more than 30sec? Used timeouts are:
binding.OpenTimeout = System.TimeSpan.FromMinutes(0.5);
binding.CloseTimeout = System.TimeSpan.FromMinutes(0.5);
binding.ReceiveTimeout = System.TimeSpan.FromMinutes(0.5);
binding.SendTimeout = System.TimeSpan.FromMinutes(0.5);

I think the reason is that you should be setting your timeouts on the service side, where you are setting up your hosts and defining endpoints, not on the client side. Here is an example:
var binding = new NetNamedPipeBinding();
binding.MaxConnections = 10;
binding.OpenTimeout = TimeSpan.FromMinutes(0.5);
binding.CloseTimeout = TimeSpan.FromMinutes(0.5);
binding.ReceiveTimeout = TimeSpan.FromMinutes(0.5);
binding.SendTimeout = TimeSpan.FromMinutes(0.5);
// Compose URIs
Uri uriBase = new Uri(baseAddress);
Uri uri = new Uri(baseAddress + something);
Uri uriMex = new Uri(baseAddress + something + "/mex");
// Create End Points
SomeHost = new CustomServiceHost(typeof(TestService), uriBase);
SomeHost.AddServiceEndpoint(typeof(ITestService), binding, uri);
SomeHost.AddServiceEndpoint(typeof(IMetadataExchange), binding, uriMex);
// Open the ServiceHost
SomeHost.Open();
Now you should see you service dying after 30sec.

Related

WCF Tcp binding in code issue

I've got a strange problem: I have a wcf service which needs to be hosted by tcp protocol on a standalone console application.
I have created a new console app project and added a lib reference for my wcf project. The problem occurs when I want to configure and broadcast the host.
var Uri = new Uri("net.tcp://myaddress:4322/MyService");
MyServiceHost = new ServiceHost(typeof(ImyService), Uri);
var binding = new NetTcpBinding();
MyServiceHost.AddServiceEndpoint(typeof(IImageExchangeService), binding, "");
var mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
MyServiceHost.AddServiceEndpoint(typeof(IMetadataExchange),mexBinding, "");
ServiceMetadataBehavior serviceBehavior = new ServiceMetadataBehavior();
serviceBehavior.HttpGetEnabled = true;
serviceBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
MyServiceHost.Description.Behaviors.Add(serviceBehavior);
When it comes to open the host, I get this message:
The contract name 'IMetadataExchange' could
not be found in the list of contracts implemented by the service WcfService.Ser
vices.MyService. Add a ServiceMetadataBehavior to the configuration
file or to the ServiceHost directly to enable support for this contract.
Now that I have better time to check this.
First you need to get the service behavior from the host or create a new one and add it if not found.
Setting the HttpGetEnabled requires you to also ad a metadata uri to the baseaddresses.
Also it does not seem to matter if the metadata endpoint is named "mex", as long as all endpoints added have unique names. So you can't use empty string for both endpoints.
var Uri = new Uri("net.tcp://myaddress:4322/MyService");
var MetadataUri = new Uri("http://myaddress:8000/MyService");
var MyServiceHost = new ServiceHost(typeof(MyService), Uri, MetadataUri);
var serviceBehavior = MyServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (serviceBehavior == null)
{
serviceBehavior = new ServiceMetadataBehavior();
MyServiceHost.Description.Behaviors.Add(serviceBehavior);
}
serviceBehavior.HttpGetEnabled = true;
serviceBehavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
MyServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
var binding = new NetTcpBinding();
MyServiceHost.AddServiceEndpoint(typeof(IImageExchangeService), binding, "image");

SOAP service on Java returns incorrect types in Response

I use a third-party server written in Java.
WSDL is taken with the style of rpc/literal.
Connection to the service is initialized as follows:
private static MLPortChannel GetMerlionClient()
{
BasicHttpsBinding binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
binding.MaxReceivedMessageSize = 4096000;
EndpointAddress adress = new EndpointAddress(new Uri(#"https://apitest.merlion.com/rl/mlservice3"));
ChannelFactory<MLPortChannel> factory = new ChannelFactory<MLPortChannel>(binding, adress);
factory.Credentials.UserName.UserName = mlLogin;
factory.Credentials.UserName.Password = mlPassword;
return factory.CreateChannel();
}
It is works correctly only for one method and returns the correct data type and the data.
When I call other methods, they returns error as:
"Can not convert an object of type " ... MLService3RLTest.CatalogResult [] " of the type " ... MLService3RLTest.ShipmentDatesResult []"
In this example return type must be ShipmentDatesResult[].
I tested the service via special tool. All requests and responses is correct and returned correct XML.
What may be the cause of this error? Perhaps something needs to be configured for SOAP service. Maybe some magic option with right value?
If, instead of referring to the service, make a web link which uses the technology of web services .Net FrameWork 2.0 what works
var client = new WpfApplication1.com.merlion.apitest.MLService();
var myCredentials = new System.Net.NetworkCredential(Логин, Пароль);
// Create a webrequest with the specified URL.
var url = "https://apitest.merlion.com/rl/mlservice3";;
client.Credentials = myCredentials.GetCredential(new Uri(url), "Basic");
textBox.AppendText(client.helloWorld("Привет"));
var ответ = client.getCatalog("N1");
var массив = new string[] { "" };
var rz = client.getItems("N10100", массив, "", 0, 2, "");
add
client.PreAuthenticate = true;

WCF basicHttpBinding and HTTP proxy

I'm trying to get my generated WCF ServiceClient to send its requests to the WCF service through a HTTP (not HTTPS) proxy with username/password authentication, however I just can't get it work. My WCF service uses basicHttpBinding so I tried to configure my ServiceClient instance like so:
var svc = new ServiceClient();
var b = svc.Endpoint.Binding as BasicHttpBinding;
b.ProxyAddress = new Uri(proxyAddress);
b.UseDefaultWebProxy = false;
b.Security.Mode = BasicHttpSecurityMode.Transport;
b.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
b.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Basic;
svc.ClientCredentials.UserName.UserName = proxyUsername;
svc.ClientCredentials.UserName.Password = proxyPassword;
This however results in a System.ArgumentException saying:
The provided URI scheme http is invalid. expected https
When I set the b.Security.Mode to BasicHttpSecurityMode.None though, it seems the HTTP proxy settings are ignored by WCF altogether!
The second solution I tried was to set the DefaultWebProxy property of WebRequest and set the UseDefaultWebProxy property to true such as so:
var webProxy = new WebProxy(proxyAddress, true);
webProxy.Credentials = new NetworkCredential(proxyUsername, proxyPassword);
WebRequest.DefaultWebProxy = webProxy;
var svc = new ServiceClient();
var b = svc.Endpoint.Binding as BasicHttpBinding;
b.UseDefaultWebProxy = true;
However this also doesn't work and ServiceClient doesn't send it's requests through the HTTP proxy.
I'm out of ideas here so please let me know what I am doing wrong, thank you!
Set the security mode to BasicHttpSecurityMode.TransportCredentialOnly. This allows for passing plain-text authentication details over HTTP.

Using BasicHttpSecurityMode.TransportWithMessageCredential in a partial (medium) trust enviroment

I have an application which consumes a WCF web service, i log in to said service using credentials supplied by the company who maintain the service.
This is the code I created for binding the service.
I used svcutil.exe to generate a ClientSearchService.cs file and imported it into the project
BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.Name = "BasicHttpBinding_IClientSearch";
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
myBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
myBinding.MaxBufferSize = 524288;
myBinding.MaxBufferPoolSize = 524288;
myBinding.MaxReceivedMessageSize = 524288;
myBinding.ReaderQuotas.MaxDepth = 32;
myBinding.ReaderQuotas.MaxArrayLength = 524288;
myBinding.ReaderQuotas.MaxStringContentLength = 524288;
myBinding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCredential;
EndpointAddress endPointAddress = new EndpointAddress(serviceEndPointAddress);
ClientSearchClient myClient = new ClientSearchClient(myBinding, endPointAddress);
myClient.ClientCredentials.UserName.UserName = userName;
myClient.ClientCredentials.UserName.Password = userPass;
var request = new schemas.advancedcheck.co.uk.DriverChecksRequest();
request.FromDate = new DateTime(2014, 1, 1);
request.ToDate = DateTime.Now;
var response = myClient.GetDriverChecks(request);
If i execute this in a full trust environment i have no issues and the data I expect to see is returned successfully, however, where the code will be hosted will be a partial trust enviroment and when ran in a partial trust enviroment it throws this error:
The Binding with name BasicHttpBinding_IClientSearch failed validation because it contains a BindingElement with type System.ServiceModel.Channels.TransportSecurityBindingElement which is not supported in partial trust. Consider using BasicHttpBinding or WSHttpBinding, or hosting your application in a full-trust environment.
is there another method i can use to consume this web service in a partial trust enviroment?

How to get a web service object?

I'm working on implementing some code in C# using a web service, but my only reference is a Java code they used to load test.
Java gets the object calling by calling this
lotService=(LotService) ic.lookup("mes-webservices/lotService/remote");
where IC is an InitialContext object.
I need to do this same call on C# but I have no idea how. Is there a simple way just like this java method to do it in C#?
You can do similar thing in C# by adding service reference to web service. I assume your webservice and consuming client are both in .NET.
Psuedo code would be
LocationWebService objService = new LocationWebService(); // this is proxy class of web service created when you add web reference
string result = objService.GetLocationName(4); //call web method
Below are the steps:
Add service refrence in your project
Create ServiceClient instance
By using above created instance call methods it is exposing
That is it.
First right-click your project and select "Add Service Reference."
Once you have it you need to create the service client object. Whatever you named your service reference above you'll have a new type available in your project (named, I think, the service reference name appended with "Client" on the end. Example: if the service is FooService, you'll have a client type called FooServiceClient available.)
To instantiate, you need a binding. You can create it programmatically:
var binding = new BasicHttpBinding()
{
CloseTimeout = new TimeSpan(0, 1, 0),
OpenTimeout = new TimeSpan(0, 1, 0),
ReceiveTimeout = new TimeSpan(0, 10, 0),
SendTimeout = new TimeSpan(0, 1, 0),
AllowCookies = false,
BypassProxyOnLocal = false,
HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
MaxBufferSize = 65536,
MaxBufferPoolSize = 524288,
MaxReceivedMessageSize = 65536,
MessageEncoding = WSMessageEncoding.Text,
TextEncoding = Encoding.UTF8,
TransferMode = TransferMode.Buffered,
UseDefaultWebProxy = true
};
binding.ReaderQuotas.MaxDepth = 32;
binding.ReaderQuotas.MaxStringContentLength = 8192;
if (isHttps)
binding.Security = new BasicHttpSecurity() { Mode = BasicHttpSecurityMode.Transport };
Then you need an endpoint. Create like so:
var endpoint = new EndpointAddress(serviceUri);
Then just instantiate the service client:
var serviceClient = new FooServiceClient(binding, endpoint);
You can call your service methods from the service client instance.

Categories

Resources