C# WCF Client takes too long to opened state (DuplexClientBase<T>.Open()) - c#

I'm having a little problem with a WCF client. First, allow me to explain and give you details.
I'm currently developing a system, and I was thinking in separate the main application because I designed it to be updated with dlls. So I found MEF, and began to read a lot about it. But there was problem with MEF, it locks the file, no write. Then I found shadow copy. So now I placed the client in another AppDomain in the main Application. I've read that communication cross domains is possible through NET Remoting, so I made research and done it with WCF.
The main Application is the host, it loads the assembly in a new domain and starts the client. As the client is a DLL, there is no AppConfig file to load bindings, endpoints. I've created a class that helps me with that, so the config is added programatically.
Finally, it works!
But there is a little thing I don't think is ok. In the client, when the instruction DuplexClientBase.Open() is executed, it takes 20 seconds to open. I think is not OK 'cause when I move the client to a EXE (remember is a DLL and the config is added programatically) it doesn't take all that time.
Maybe is something wrong in the config, but I can't find it. So here are the souce code files. First, this is the App.config file, when the client is in a console application:
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="TcpBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false"
transferMode="Buffered" transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard" listenBacklog="10"
maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
<wsDualHttpBinding>
<binding name="HttpBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:8080/ProtoServicio/EPServicioTcp"
binding="netTcpBinding" bindingConfiguration="TcpBinding"
contract="TestServicio.IServicio" name="TcpBinding">
<identity>
<userPrincipalName value="OlinzerLaptopV\Olinzer" />
</identity>
</endpoint>
<endpoint address="http://localhost:8081/ProtoServicio/EPServicioHttp"
binding="wsDualHttpBinding" bindingConfiguration="HttpBinding"
contract="TestServicio.IServicio" name="HttpBinding">
<identity>
<userPrincipalName value="OlinzerLaptopV\Olinzer" />
</identity>
</endpoint>
</client>
</system.serviceModel>
And now, this is the code that creates the binding and endpoint:
internal static Binding GetBinding()
{
WSDualHttpBinding binding = new WSDualHttpBinding();
TimeSpan span = new TimeSpan( 0, 1, 0 );
binding.Name = "HttpBinding";
binding.CloseTimeout = span;
binding.OpenTimeout = span;
binding.ReceiveTimeout = span;
binding.SendTimeout = span;
binding.BypassProxyOnLocal = false;
binding.TransactionFlow = false;
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.MaxBufferPoolSize = 524288;
binding.MaxReceivedMessageSize = 65536;
binding.MessageEncoding = WSMessageEncoding.Text;
binding.TextEncoding = Encoding.UTF8;
binding.UseDefaultWebProxy = true;
binding.ReaderQuotas = new XmlDictionaryReaderQuotas();
binding.ReaderQuotas.MaxDepth = 32;
binding.ReaderQuotas.MaxStringContentLength = 8192;
binding.ReaderQuotas.MaxArrayLength = 16384;
binding.ReaderQuotas.MaxBytesPerRead = 4096;
binding.ReaderQuotas.MaxNameTableCharCount = 16384;
binding.ReliableSession = new ReliableSession();
binding.ReliableSession.Ordered = true;
binding.ReliableSession.InactivityTimeout = span;
binding.Security.Mode = WSDualHttpSecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
binding.Security.Message.NegotiateServiceCredential = true;
binding.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.Default;
return binding;
}
The file created by the code only contains the Http Endpoint. Maybe adding the tcp endpoint could make the diference, but, I have no idea how to make it. The function above is called by the constructor of the ClientClientBase class.
ServiceModel.DuplexClientBase<Servicio> MyClient = new ...<Servicio>(new InstanceContext(this), GetBinding(), GetEndpoint());
Feel free to notify me if you need anything else.

You are doing cross AppDomain communication within single process and you are using WsHttpBinding? Do you understand how big overhead this has? It also highly increases complexity of your application deployment. It is probably not source of your main problem but I would start with:
Replacing WsDualHttpBinding with NetNamedPipeBinding
To diagnosing your issue start with WCF tracing and check which operation on both client and server takes a long time - there can be problem with some security resolving because your setting uses message security.

Related

.NET Web Service Using WEB CONFIG Settings Hard Coded Net TCP

I wanted to confirm something.
Below is how I am spinning up a call to my WCF web service in my ASP.NET application.
var xml = "my xml string";
var ep = new EndpointAddress("http://myendpoint");
xml = new Proxy.ServiceClient(new NetTcpBinding(), ep).getNewXML(new Proxy.CallContext(), xml);
My web config looks similar to below. My question is, even though these settings are in the web config, the fact that my calls above are newing up the a service client and fresh New TCP binding everytime tell me that these settings aren't being referenced. Is this correct based on above?
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_SCSService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288"
maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://myendpoint"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_SCSService"
contract="Proxy.Service" name="NetTcpBinding_SCSService">
<identity>
<userPrincipalName value="user#user.com" />
</identity>
</endpoint>
</client>
</system.serviceModel>
That's correct. In this case, you are not using the configuration settings found in the config file.
Proxies typically derive from the abstract class ClientBase<T> which provides several different ways to create an instance of a client proxy. Some of the constructors listed will use all of the config file while others will attempt to use the config file to fill in the information that has not been explicitly supplied in the constructor. There are even constructor overloads which do not use the configuration file at all which ClientBase<TChannel>(Binding, EndpointAddress) is one of them.
If you wanted to use what was in the application configuration file, you could use:
var client = new Proxy.ServiceClient("NetTcpBinding_SCSService");

The caller was not authenticated by the service wsDualHttpBinding

I have searched and tried to apply the solution given on the other posts, but i cant solve my problem yet.
I have to use wsDualHttpBinding for duplex connection.
When I try to run my client on the same machine with the WCF server, it can run perfectly, but when i move the client to other machine on the same domain, it return an error "The caller was not authenticated by the service"
here is the app.config on my client
<wsDualHttpBinding>
<binding name="duplexendpoint" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default"/>
</security>
</binding>
</wsDualHttpBinding>
then i tried to give the credential via the code :
client.ClientCredentials.Windows.ClientCredential.UserName = "serverusername";
client.ClientCredentials.Windows.ClientCredential.Password = "serverpassword";
client.ClientCredentials.Windows.ClientCredential.Domain = "serverdomain";
and it give an error "Client is unable to finish the security negotiation within the configured timeout"
is there any way to solve my problem? thanks.
oke I have found the solution for my problem, i have to turn off the firewall from the client machine.

Issues connecting to a web service in C#

I am using a third party wsdl to connect to a service. I have been provided a security certificate and a username / password.
I have:
Installed the certificate on my Windows 7 machine
Ensured it has the correct permissions
Have the correct location for the API stored in the web.config
The code fails each time. The error messages change, but they include:
Authentication failed because the remote party has closed the transport stream.
An existing connection was forcibly closed by the remote host
Could not create SSL/TLS secure channel
This is the code I am executing:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
//Third party client
var client = new ConnectionPortClient();
//Including these two lines or not does not affect the outcome
//client.ClientCredentials.UserName.UserName = "username";
//client.ClientCredentials.UserName.Password = "password";
client.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(#"C:\..\cert.p12", "password", X509KeyStorageFlags.MachineKeySet);
var results = client.getResults("");
And here is the relevant part of the web.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="assessmentBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://endpoint/" binding="basicHttpBinding"
bindingConfiguration="assessmentBinding" contract="API.Assessment"
name="assessmentSOAP" />
</client>
</system.serviceModel>
Any thoughts on what's going on here?
you use Certificate message credential type but you are trying to set up UserName/Password for UserName message credential type - this is wrong. check the article about Message Security with a Certificate Client

WCF over HTTPS and Signing the body

I've got a SOAP service I want to connect to. It needs to be accessed trough https and it needs to have it's body signed by a certificate.
I've tried the following code:
<basicHttpBinding>
<binding name="P4Binding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
Setup up my client as follows:
P4_ServiceReference.P4PortTypeClient client = new P4_ServiceReference.P4PortTypeClient();
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
client.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(#"[..].cer");
client.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(#"[..]", "somepass");
Even changed my Reference.cs to include the ProtectionLevel=ProtectionLevel.Sign on the ServiceContractAttribute and the OperationContractAttribute.
What happens is that the wse:security header is created, but the body is not being signed. The service returns Element http://schemas.xmlsoap.org/soap/envelope/Body must be signed.
What am I missing so that the body gets signed properly?
Fixed it using this customBinding instead of the basicHttpBinding.
//Setup custom binding with HTTPS + Body Signing + Soap1.1
CustomBinding binding = new CustomBinding();
//HTTPS Transport
HttpsTransportBindingElement transport = new HttpsTransportBindingElement();
//Body signing
AsymmetricSecurityBindingElement asec = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
asec.SetKeyDerivation(false);
asec.AllowInsecureTransport = true;
asec.IncludeTimestamp = true;
//Setup for SOAP 11 and UTF8 Encoding
TextMessageEncodingBindingElement textMessageEncoding = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
//Bind in order (Security layer, message layer, transport layer)
binding.Elements.Add(asec);
binding.Elements.Add(textMessageEncoding);
binding.Elements.Add(transport);
It seems that TransportWithMessageCredential only uses the Transport for security and ignores everything else.

How to set up a WCF client using wsDualHttpBinding in code?

I have a need to connect to a WCF service I wrote without having to deploy an app.config for the client application I'm writing. However, I've been having a very difficult time trying to figure out how to set up things from the client side in code. This is as far as I've gotten... does anyone have any ideas what I need to do to get this to work? I'd really appreciate it.
This is the code I've got so far:
String baseAddress = "http://localhost/CommService";
WSDualHttpBinding binding = new WSDualHttpBinding();
binding.Name = "WSDualHttpBinding_ICommService";
binding.ClientBaseAddress = new Uri(baseAddress);
binding.ReliableSession.Ordered = true;
binding.ReliableSession.InactivityTimeout = new TimeSpan(0, 10, 0);
binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
binding.SendTimeout = new TimeSpan(0, 0, 5);
InstanceContext context = new InstanceContext(this);
client = new CommServiceClient(context, "WSDualHttpBinding_ICommService");
client.Endpoint.Binding = binding;
And this is my client app's app.config:
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_ICommService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:00:05"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/CommService/"
binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_ICommService"
contract="Services.ICommService" name="WSDualHttpBinding_ICommService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
You can easily achieve what you want. See code below :
Uri baseAddress = new Uri("http://localhost/CommService");
WSDualHttpBinding wsd = new WSDualHttpBinding();
EndpointAddress ea = new EndpointAddress(baseAddress, EndpointIdentity.CreateDnsIdentity("localhost"));
client = new CommServiceClient(new InstanceContext(this), wsd, ea);
Let me explain a bit :
first we create an instance of a WSDualHttpBinding with the default settings (those are the exact ones the generated app.config has). If you want to modify any of the settings, you can modify them trough the exposed properties.
then we create an EndPointAddress with th desired URL and identity. No need to link it with a binding because we will link all of them in the Service Client constructor.
lastly we create the Service Client. One of the contructor overloads allows us to specify a Binding and an Endpoint Address.
in general every element available in the app.config file has an associated Class in .NET code and every attribute or child element has an associated Property in the specified class.

Categories

Resources