No connection to wcf service with oob except when fiddler is running - wcf

I have a silverlight application and the application connects with wcf (SSL/https) to a public service hosted on iis. Everything works fine if I start the application in Browser. As soon as I start the application in "Out of Browser Mode" it doesn't work anymore. I tried to figure out the Problem with fiddler but as long as fiddler is running, everything works fine. I found many posts in Internet about this but nothing worked. Are there any idea? What does fiddler do exactly and making it running in oob?
Summary:
1. Everything ok "In Browser"
2. No Connection to public Service when running "Out of Browser"
3. It's runinng "Out of Browser" as long Fiddler is running
Below are some info how I do the connects.
Thank you very very much for a help.
Best regards.
Marc
Here are some info how I do everything:
Is it possible that the self signed certificate has something to do with all?
The connect on Client side to the public service looks like this:
PublicServiceClient proxy;
BinaryMessageEncodingBindingElement binaryMessageEncodingBindingElement = new BinaryMessageEncodingBindingElement();
HttpsTransportBindingElement httpsTransportBindingElement = new HttpsTransportBindingElement();
httpsTransportBindingElement.MaxBufferSize = int.MaxValue;
httpsTransportBindingElement.MaxReceivedMessageSize = int.MaxValue;
httpsTransportBindingElement.TransferMode = TransferMode.Buffered;
Binding binding = new CustomBinding(binaryMessageEncodingBindingElement, httpsTransportBindingElement);
binding.SendTimeout = new TimeSpan(0, 0, _WcfTimeout);
binding.ReceiveTimeout = new TimeSpan(0, 0, _WcfTimeout);
binding.OpenTimeout = new TimeSpan(0, 0, _WcfTimeout);
binding.CloseTimeout = new TimeSpan(0, 0, _WcfTimeout);
proxy = new PublicServiceClient(binding, new EndpointAddress("https://" + App.CurrentParameter.WcfDomain + "/PublicService.svc"));
Binding Server side (web.config):
<binding name="Web.PublicService.customBinding0" sendTimeout="00:01:00" receiveTimeout="00:01:00" openTimeout="00:01:00" closeTimeout="00:01:00">
<binaryMessageEncoding maxReadPoolSize="2147483647" maxWritePoolSize="2147483647">
<readerQuotas maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxDepth="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647"/>
</binaryMessageEncoding>
<httpsTransport maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" keepAliveEnabled="false"/>
</binding>
Service Server side (web.config):
<service name="Web.PublicService">
<endpoint address="" binding="customBinding" bindingConfiguration="Web.PublicService.customBinding0" contract="Web.PublicService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>

If you disable HTTPS Decryption in Fiddler (and restart it) and the app stops working through Fiddler, that means that the self-signed certificate in use on the server is the problem, and you need to fix it by trusting that certificate.
If disabling HTTPS decryption in Fiddler doesn't make a difference, the problem is likely related to the security zone settings. See http://blogs.msdn.com/b/fiddler/archive/2010/11/22/fiddler-and-silverlight-cross-zone-cross-domain-requests.aspx for details on why that might be.

Related

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

Transport level security in an intranet Silverlight 5 application

I am implementing transport level security in an intranet Silverlight 5 application.
Binding used is custom netTcpBinding and on server end I have enabled security with below settings and PrincipalPermission.
<customBinding>
<binding closeTimeout="00:05:00" openTimeout="00:05:00" receiveTimeout="02:00:00" sendTimeout="00:05:00">
<binaryMessageEncoding maxSessionSize="1000000">
<readerQuotas maxDepth="64" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="16384" maxNameTableCharCount="16384" />
</binaryMessageEncoding>
<windowsStreamSecurity protectionLevel="EncryptAndSign"/>
<tcpTransport portSharingEnabled="false" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
When my client is a normal c# console app and proxy created using channel fatory everything works fine.
var tcpBinding = new CustomBinding();
tcpBinding.Elements.Add(new BinaryMessageEncodingBindingElement());
var windowsStreamSecurityBindingElement=new WindowsStreamSecurityBindingElement();
windowsStreamSecurityBindingElement.ProtectionLevel= System.Net.Security.ProtectionLevel.EncryptAndSign;
tcpBinding.Elements.Add(windowsStreamSecurityBindingElement);
tcpBinding.Elements.Add(new TcpTransportBindingElement { MaxReceivedMessageSize = int.MaxValue, MaxBufferSize = int.MaxValue });
tcpBinding.ReceiveTimeout = new TimeSpan(6, 0, 0);
tcpBinding.SendTimeout = new TimeSpan(0, 30, 0);
tcpBinding.ReceiveTimeout = TimeSpan.FromDays(1);
var proxy = new ChannelFactoryServiceWrapper<IHello>(#"net.tcp://XYZ.globaltest.ABC.com:5580/Hello/tcp", tcpBinding).Channel;
var ping = proxy.Ping();
On client(Silverlight 5) I am using same above piece of code but it’s giving compile time error since WindowsStreamSecurityBindingElement is not available in Silverlight 5.
Please tell me any alternative for this.

Trouble connecting to API

I am new to WCF/APIs and know little to nothing about security. Let me know if I need to provide any more information.
I am trying to connect to a service using
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ISalesOrderService">
<security mode="Transport" >
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
<binding name="BasicHttpBinding_IDocumentationService">
<security mode="TransportCredentialOnly" >
<transport clientCredentialType="Basic"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="address1"
name="BasicHttpBinding_ISalesOrderService"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ISalesOrderService"
contract="SoCalls.ISalesOrderService" />
<endpoint address="address2"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IDocumentationService"
contract="DocCalls.IDocumentationService"
name="BasicHttpBinding_IDocumentationService" />
</client>
</system.serviceModel>
With this, I get this error:
'System.ServiceModel.Security.MessageSecurityException'
The HTTP request is unauthorized with client authentication scheme 'Basic'.
The authentication header received from the server was 'Basic Realm'.
Edit
I followed the instructions suggested in the link provided in the comments, still is giving me this error. I updated my code but I think I am still a bit confused on whether to use HTTP/HTTPS due to lack of knowledge of either service.
Here is how I instantiate my service:
private static SoCalls.SalesOrderServiceClient CreateSalesOrderServiceClient()
{
BasicHttpBinding myBinding = new BasicHttpBinding();
myBinding.MaxReceivedMessageSize = 10000 * 2;
myBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress ea = new EndpointAddress("address1");
SoCalls.SalesOrderServiceClient client = new SoCalls.SalesOrderServiceClient();
client.ClientCredentials.UserName.UserName = ("username");
client.ClientCredentials.UserName.Password = ("password");
return client;
}
As it seems, I did not have access to the API with this specific database which is what was giving me my error. I tried sending other credentials for a separate database from the same server and it worked perfectly fine. Purchased the license required and the code works as expected.

Cannot connect to a WCF service hosted in a Worker Role

I've created a WCF service and hosted it in cloud through a worker role. Unfortunately when I try to connect to the worker role service I get an exception with the message:
"No DNS entries exist for host 3a5c0cdffcf04d069dbced5e590bca70.cloudapp.net."
3a5c0cdffcf04d069dbced5e590bca70.cloudapp.net is the address for the worker role deployed in azure staging environment.
The workerrole.cs has the following code to expose the WCF service:
public override void Run()
{
using (ServiceHost host = new ServiceHost(typeof(MyService)))
{
string ip = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["tcppoint"].IPEndpoint.Address.ToString();
int tcpport = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["tcppoint"].IPEndpoint.Port;
int mexport = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["mexinput"].IPEndpoint.Port;
// Add a metadatabehavior for client proxy generation
// The metadata is exposed via net.tcp
ServiceMetadataBehavior metadatabehavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(metadatabehavior);
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
string mexlistenurl = string.Format("net.tcp://{0}:{1}/MyServiceMetaDataEndpoint", ip, mexport);
string mexendpointurl = string.Format("net.tcp://{0}:{1}/MyServiceMetaDataEndpoint", RoleEnvironment.GetConfigurationSettingValue("Domain"), 8001);
host.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, mexendpointurl, new Uri(mexlistenurl));
// Add the endpoint for MyService
string listenurl = string.Format("net.tcp://{0}:{1}/MyServiceEndpoint", ip, tcpport);
string endpointurl = string.Format("net.tcp://{0}:{1}/MyServiceEndpoint", RoleEnvironment.GetConfigurationSettingValue("Domain"), 9001);
host.AddServiceEndpoint(typeof(IMyService), new NetTcpBinding(SecurityMode.None), endpointurl, new Uri(listenurl));
host.Open();
while (true)
{
Thread.Sleep(100000);
Trace.WriteLine("Working", "Information");
}
}
}
The tcppoint and mexinput are configured with the ports 8001 and 9001. Also Domain is configured with worker role deployment url:3a5c0cdffcf04d069dbced5e590bca70.cloudapp.net
On the client part(a console app), we are using the following configuration in app.config::
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IMyService" 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:50:00"
enabled="false" />
<security mode="None">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="httpp:\\3a5c0cdffcf04d069dbced5e590bca70.cloudapp.net:9001/MyServiceEndpoint" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IMyService" contract="ServiceReference1.IMyService"
name="NetTcpBinding_IMyService" />
</client>
<behaviors>
<serviceBehaviors>
<behavior name="behave">
<serviceMetadata httpGetEnabled="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.net>
<defaultProxy useDefaultCredentials="true">
<proxy autoDetect="False" usesystemdefault="False" bypassonlocal="True" />
</defaultProxy>
The following code is built using the sample code available in msdn as background. Locally it is working fine. Unfortunately when i deploy it to cloud, the exception occurs. Moreover, when i use the virtual ip instead of the url, a connection time out occurs with the exception the remote machine did not respond.
Looks like you have your service setup to listen on net.tcp (TCP) and your client using http bindings. I would not expect that to work even locally. I am assuming you have actually opened port 9000 in the ServiceDefinition. Remember that will be a load-balanced endpoint. Are you trying to communicate to this instance from within the deployment (inter-role) or from outside the cloud?
I have found it is a lot easier to setup the host and client (when communicating within a role) through code. Try this:
http://dunnry.com/blog/2010/05/28/HostingWCFInWindowsAzure.aspx
If you are trying to hit the service from a client outside the deployment, this still applies, but for the client building part. You will need to use the external DNS name and port defined in ServiceDefinition.
I have also seen DNS errors if you try to hit the endpoint too soon before the role was ready. It can take a bit to propogate the DNS and you should try not to resolve it until it is ready, lest you cache a bogus DNS entry. If you can resolve that DNS name however to your VIP address, that is not the issue.
public void CallWebService(string data)
{
try
{
string uri = "url"+data;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream str = response.GetResponseStream();
StreamReader sr = new StreamReader(str);
String IResponse = sr.ReadToEnd();
}
catch (Exception ex)
{
System.Console.WriteLine("Message: "+ex.Message);
}
}
Hope it helps you.

Increasing the timeout value in a WCF service

How do I increase the default timeout to larger than 1 minute on a WCF service?
Are you referring to the server side or the client side?
For a client, you would want to adjust the sendTimeout attribute of a binding element. For a service, you would want to adjust the receiveTimeout attribute of a binding elemnent.
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="longTimeoutBinding"
receiveTimeout="00:10:00" sendTimeout="00:10:00">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="longTimeoutService"
behaviorConfiguration="longTimeoutBehavior">
<endpoint address="net.tcp://localhost/longtimeout/"
binding="netTcpBinding" bindingConfiguration="longTimeoutBinding" />
</service>
....
Of course, you have to map your desired endpoint to that particular binding.
Under the Tools menu in Visual Studio 2008 (or 2005 if you have the right WCF stuff installed) there is an options called 'WCF Service Configuration Editor'.
From there you can change the binding options for both the client and the services, one of these options will be for time-outs.
You can choose two ways:
1) By code in the client
public static void Main()
{
Uri baseAddress = new Uri("http://localhost/MyServer/MyService");
try
{
ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService));
WSHttpBinding binding = new WSHttpBinding();
binding.OpenTimeout = new TimeSpan(0, 10, 0);
binding.CloseTimeout = new TimeSpan(0, 10, 0);
binding.SendTimeout = new TimeSpan(0, 10, 0);
binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
serviceHost.AddServiceEndpoint("ICalculator", binding, baseAddress);
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
}
catch (CommunicationException ex)
{
// Handle exception ...
}
}
2)By WebConfig in a web server
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
For more detail view the official documentations
Configuring Timeout Values on a Binding
Class WSHttpBinding
Different timeouts mean different things. When you're working on the client.. you're probably looking mostly at the SendTimeout - check this reference - wonderful and relevant explanation:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/84551e45-19a2-4d0d-bcc0-516a4041943d/
It says:
Brief summary of binding timeout knobs...
Client side:
SendTimeout is used to initialize the OperationTimeout, which governs the whole interaction for sending a message (including receiving a reply message in a request-reply case). This timeout also applies when sending reply messages from a CallbackContract method.
OpenTimeout and CloseTimeout are used when opening and closing channels (when no explicit timeout value is passed).
ReceiveTimeout is not used.
Server side:
Send, Open, and Close Timeout same as on client (for Callbacks).
ReceiveTimeout is used by ServiceFramework layer to initialize the session-idle timeout.
In addition to the binding timeouts (which are in Timespans), You may also need this as well. This is in seconds.
<system.web>
<httpRuntime executionTimeout="600"/><!-- = 10 minutes -->