WCF Service 405 Error When Using Proxy - wcf

I have a WCF service that works perfectly fine unless I attempt to use a proxy in the communication stream such as:
AnonClient anonService = new AnonClient();
var bindHttp = anonService.Endpoint.Binding as BasicHttpBinding;
bindHttp.ProxyAddress = new Uri("http://149.169.227.131:3127");
bindHttp.BypassProxyOnLocal = false;
bindHttp.UseDefaultWebProxy = false;
As soon as the proxy is introduced - and it can be any proxy - IIS immediately rejects the request with a 405 error. There is no authentication occurring at the IIS level - I take of everything in code - anonymous access is enabled - so what is wrong with my IIS configuration?

Just to close this loop, the issue was using an Open Proxy with a WCF service which, by default, emits SOAP. Most open proxies block SOAP and were shutting things down. The solution is actually simple - add JSON attributes on top of the WCF service calls and run over the RESTful interface

Related

WCF client method

I am having a very strange issue on my WCF client method.
My client proxy did work quite well with a method:
QuoteResult result = proxy.GetQuote(param);
But after I made some changes to the WCF (Only database access codes), after I updated my client proxy, I have to use code in my client:
GetQuoteRequest request = new GetQuoteRequest(param);
QuoteResultDetail result = proxy.GetQuote(request).GetQuoteResult;
Can anyone tell me what's been changed in WCF service side or what caused this?

SOAP Connection WCF

I am connecting to a 3rd party API. They have provided me with a WSDL file which i have added by using a web reference. Is it possible to connect via SOAP and send multiple messages across the same connection?
I have created the client from the proxy classes but there doesn't appear to be a Open() or a Close() method. Does the client connect and disconnect when a method is called?
SampleService client = new SampleService
client.SampleMethod();
Edit:
I have added a "Service Reference" from the WSDL file. The client is constructed from the "PortType" in the WSDL file. There inst a Close() or a Abort() method. The only method on SampleService.client is SampleMethod()
They have provided me with a WSDL file which i have added by using a web reference.
In such case you are not using WCF but ASP.NET WebServices client. In your case it is probably not a big difference but ASP.NET WebServices are mostly for backward compatibility when moving legacy code to new version of .NET framework. Today you should rather use Add Service Reference to use WCF as other also recommended.
SOAP Connection WCF
There is nothing like SOAP connection. SOAP is application protocol tunneled through some transport protocol. In your case the transport protocol is HTTP.
I have created the client from the proxy classes but there doesn't
appear to be a Open() or a Close() method. Does the client connect and
disconnect when a method is called?
You don't need to call Open or Close. This is all handled in low level layer of communication stack. By default all HTTP client applications use something called persistent connection. It means that when you access some host for the first time TCP connection is established between your client computer and server hosting target resource. Subsequent calls reuse the same connection. If the connection is not in use for some predefined time (both client and server can have different timeouts) the connection is closed and next time the client wants to call the server it will create a new connection (again you don't need to bother with this).
So calling the method on SOAP proxy in your application can automatically open connection if no one exists. You don't need to explicitly close the connection but you should dispose the proxy to release its resources. Connection itself can live after the proxy was disposed and can be reused by another proxy.
You should add a service reference (WCF) instead of using the outdated Web Reference.
Then follow the bellow pattern:
try
{
SampleServiceClient client = new SampleServiceClient();
client.SampleMethod();
//... Make as many calls to as many methods as you like.
client.SampleMethod();
client.Close();
}
catch (Exception e)
{
//client is unusable once an exception occurs.
...
client.Abort();
throw;
}
You need to use the Add Service Reference rather than Add Web Reference. And once added you can invoke the service as shown:
using(SampleServiceClient client = new SampleServiceClient())
{
var response = client.SampleMethod();
}
Hope that helps.

How to write code that calls a WCF service and falls back from Kerberos to NTLM if needed?

I need to call a WCF service programmatically. The service may be hosted with either NTLM or Kerberos authentication and needs to work under either. That is, if connecting to the service via Kerberos fails, then it should fall back to NTLM.
Here's the code I'm using for Kerberos auth (if relevant, the service is hosted in SharePoint 2010 and is being called from a web part):
public static SiteMembershipSvc.SiteMembershipServiceClient InitialiseSiteMembershipService(string url)
{
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
url = url.EndsWith("/") ? url + SiteMembershipAddress : url + "/" + SiteMembershipAddress;
var endpoint = new EndpointAddress(url);
var proxy = new SiteMembershipSvc.SiteMembershipServiceClient(binding, endpoint);
proxy.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
return proxy;
}
Calling a method on the proxy when run in an NTLM environment gives the error:
The HTTP request is unauthorized with
client authentication scheme
'Negotiate'. The authentication header
received from the server was 'NTLM'.
Note: The URL may be in another web application on another server. I can't check what authentication the web part's web app runs under and assume it is the same as where the WCF service is hosted.
How can I (automatically or manually) ensure authentication falls back from Kerberos back to NTLM on failure?
Update:
As mentioned, the authentication error occurs when a web method is called. However I don't want to wait that long as there are several web methods in the service called from several places. I'd like to test the authentication at the point where the proxy is configured (in the code snippet above).
I've tried using proxy.Open() but that doesn't seem to cause the failure.
This is a bit off a curveball, but why is it falling back to NTLM. I've had significant difficulty with security in active directory and WCF all related to service principal names (SPNs).
Kerberos will fail if you are running the service as something other than Network Service unless you have an SPN declared in the domain for your service. To set the SPN you need the windows server administrative kit, which has the command setspn.
setspn -A HTTP\machinename domain\service_account
This will then allow Kerberos to share client credentials to your service within the domain.
Please do some reading, as you could break kerberos for any other services running on the same box depending on your setup.
(I recognize the original post is very old.)
Can you use something other than BasicHttpBinding (like WsHttpBinding)? According to this article, BasicHttpBinding is the one exception to the binding objects, in that it does not automatically negotiate. This is why allowNTLM has no effect.
I had the same error msg which I posted about here and solved it by creating a dynamic endpoint like so:
public static SiteMembershipSvc.SiteMembershipServiceClient InitialiseSiteMembershipService(string url)
{
//create endpoint
EndpointAddress ep = new EndpointAddress(new Uri(string), EndpointIdentity.CreateUpnIdentity("MyDomain\WCFRunAsUser"));
//create proxy with new endpoint
SiteMembershipSvc.SiteMembershipServiceClient service = new SiteMembershipSvc.SiteMembershipServiceClient("wsHttp", ep);
//allow client to impersonate user
service.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
//return our shiny new service
return service;
}
I was running the WCF service as a specific Active Directory user rather than the default NETWORK_SERVICE.
Try setting:
proxy.ClientCredentials.Windows.AllowNTLM = true;
According to this, AllowNTLM is now obsolete - i'm not sure what the correct alternative is.
I guess you are using the full dns name of the server as the address of the service. Try using the NETBIOS name or the IP address. That should force it to use NTLM.
If you know what protocol the server is using you can configure your app to use either the full name or the ip.
Hope that works for you.
If your Kerberos fail it will automatically default to NTLM, you don't have to do anything special.
http://www.windowsecurity.com/articles/Troubleshooting-Kerberos-SharePoint-environment-Part1.html
http://www.windowsecurity.com/articles/Troubleshooting-Kerberos-SharePoint-environment-Part2.html
http://www.windowsecurity.com/articles/Troubleshooting-Kerberos-SharePoint-environment-Part3.html
I haven't been able to find a way to do this automatically. Instead I've added UI to the application where the type of authentication must be chosen.

Silverlight WCF Service to Service calls

Question:
Are there known issues making calls to a service that calls another service from Silverlight?
Scenario:
I have the following 3 projects:
SilverlightClient - Silverlight project with a Button
SilverlightClient.Web - A web application that hosts the SilverlightClient.xap.
BackEnd - A different web application that hosts the FOO Service which does some special backend processing.
I have created a Silverlight WCF-Enabled web service in both SilverlightClient.Web and Backend. These are respectively SilverlightClientService and BackEndService.
From SilverlightClient.Web I add a service reference to BackEndService. I have a test ASPX page that I've written code that calls BackEndService successfully.
From SilverlightClient I add a service reference to SilverlightClient.Web's SilverlightClientService. If my SilverlightClientService returns plain data, such as a string, it works quite well.
The moment, however, that I change SilverlightClientService to call BackEndService, I get the following exception:
HTTP 415 - "The request failed with HTTP status 415: Unsupported Media Type."
I had an issue with 2 services not communicating. We finally figured out that using Cassini (the built in Visual Studio IIS) to host the ListenerService 'BackEnd' was causing the problem. Switching the project to start in a virtual directory of IIS allowed the two to communicate.
I was seeing : An error occurred while receiving the HTTP response to http://localhost:1484/MainListenerService.cs. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details. and this error:
The HTTP request was forbidden with client authentication scheme 'Anonymous'.
Are you using basicHttpBinding? Silverlight only supports basicHttpBinding but the default when you create a WCF service is wsHttpBinding. You should change that on your web.config before adding the reference on your Silverlight project. Check out this video from Tim Heuer: http://silverlight.net/learn/videos/all/how-to-consume-wcf-and-aspnet-web-services-in-silverlight/

How can I set an HTTP Proxy (WebProxy) on a WCF client-side Service proxy?

How can I set the HTTP proxy programmatically, on a WCF client, without using the default proxy?
Proxies, proxies, proxies.
According to the WCF model of development, I generate client-side "proxy"
classes by running svcutil.exe on the WSDL for the service. (This also
produces a client-side config file).
In my code I new-up an instance of that class and I can connect to the
service. Very nice.
var svcProxy = new MyWebService();
svcProxy.GetInformation(request);
We call this thing a proxy class, but there is another proxy - the http proxy. This
service is using wsHttpBinding basicHttpBinding, so it is going over
http. Now, suppose I want to connect the client to the web service over
a http proxy (modeled by a System.Net.WebProxy in the .NET BCL). I know
from my extensive, delightful experience reading .NET and WCF documentation, that
the WCF runtime, if not instructed otherwise, will use the default
system proxy when communicating over http/https.
I can set that from the command line in
WinXP / 2003 with ProxyCfg.exe as described here, and in later
versions of Windows with netsh.exe as described here.
I can also specify the default web proxy for use within the application
by setting the System.Net.WebRequest.DefaultWebProxy property.
But suppose I want to connect over a proxy that is different than the
system-wide proxy? For instance maybe there is no system-wide proxy but
I need to use one for the web service in particular. Or maybe there is
a system-wide proxy but I need to use a different one, for the web
service. And in fact maybe there are multiple web service clients, and
each one should get a different proxy.
How can the proxy be set per-binding?
In the ASMX model, I could do this:
var svcProxy = new MyWebService();
svcProxy.Proxy = new System.Net.WebProxy("http://proxyserver:1234", true);
svcProxy.GetInformation(request);
But this is not possible with WCF; the WCF-generated client-side proxy
classes do not expose a Proxy property. How do I set the http proxy, per client-side proxy, and how do I set authentication on the http proxy as well?
Related:
- how-to-set-proxy-with-credentials-to-generated-wcf-client
It makes sense that there is no Proxy property on the WCF proxy, because not all WCF proxies use HTTP for communication. After further review, I found that it is possible to set the proxy in WCF programmatically, if the WCF proxy uses an HTTP binding. I am documenting it here in case someone else needs it. To set the HTTP Proxy in code for a WCF client, do this:
// instantiate a proxy for the service
var svc= new ServiceClient();
// get the HTTP binding
var b = svc.Endpoint.Binding as System.ServiceModel.BasicHttpBinding;
b.ProxyAddress = new Uri("http://127.0.0.1:8888");
b.BypassProxyOnLocal = false;
b.UseDefaultWebProxy = false;
And to set the endpoint address - where to reach the server - in code, you would do something like this:
var e = svc.Endpoint;
e.Address = new System.ServiceModel.EndpointAddress(
"http://remoteserver:5555/WcfXmlElement");
The proxy settings are part of the binding configuration. For example, look at the ProxyAddress property of the BasicHTTPBinding and WSHttpBinding classes/configuration elements.
Looks like you're leaving your endpoint configuration in the app.config file, in which case you should be able to set the address there.
I have had a similar problem, but I also needed to use a username and password for the proxy that differ from the username and password used to access the service.
I tried building it up through a UriBuilder, which would output the proxy address as "http://username:password#myproxyserver/". Unfortunately, the particular proxy I was using didn't work with this technique.
What I found after extensive Googling, is that you can change the proxy through WebRequest.DefaultProxy (static property).
For example:
WebProxy proxy = new WebProxy("http://myproxyserver",true);
proxy.Credentials = new NetworkCredential("username", "password");
WebRequest.DefaultWebProxy = proxy;
You could also try this :
Programmatically get whatever binding you are using,and then set the proxy on it directly e.g.
var binding = new WSDualHttpBinding("WSDualHttpBinding_IMainService");
binding.ProxyAddress = new Uri("http://192.168.5.1:3128");
where "WSDualHttpBinding_IMainService" is the name of your binding from your config file.
Also you have to set UseDefaultWebProxy=false; otherwise your proxy will be ignored.
I found a solution for someone who might use .NET Core 2.x
Which initially cause an issue when trying to set proxy by using
System.ServiceModel.BasicHttpBinding;
as answered by Cheeso.
You have to update WCF to the latest (v.4.7.0).
Go to NuGet Package Manager -> Update all related Project URL of WCF.
There must be:
System.ServiceModel.Security
System.ServiceModel.NetTcp
System.ServiceModel.Http