Using WCF on Localhost on Azure - wcf

In summary
How do I acces a WCF service on localhost when hosted in IIS on Azure? Azure does not bind localhost or 127.0.0.1 to my website.
Details
I have an ASP.Net application hosted on Azure. I have added a .svc and some workflows that I want to use via WCF. To keep matters simple, my web app simply calls the service on localhost, so I have endpoints like these in web.config;
<client>
<endpoint address="http://localhost:8080/Router.svc/Case" binding="basicHttpBinding" contract="NewOrbit.ExVerifier.Model.Workflow.Case.ICaseWorkflow" name="Case" />
<endpoint address="http://localhost:8080/Workflow/Case/Case_default1.xamlx" binding="basicHttpBinding" contract="*" name="Case_default1" />
</client>
This works just fine on my local machine. The problem is that when I publish this to Azure, the Website in IIS does not get a binding to localhost, instead the bindings are always to the actual IP address of the server.
It ends up looking like this in applicationHost.config:
<bindings>
<binding protocol="http" bindingInformation="10.61.90.44:80:" />
<binding protocol="https" bindingInformation="10.61.90.44:443:" />
<binding protocol="http" bindingInformation="10.61.90.44:8081:" />
</bindings>
So, as soon as my web app tries to call the service on localhost (or 127.0.0.1 for that matter) it fails instantly.
Needless to say, if I rdp on to the server and change the binding then all is fine.
What I find really odd is that there are tons of examples out there where people are accessing WCF services on localhost on Azure so I can't figure out why this is so. I have set the osFamily to 2 and in order to debug this I have enabled web publishing and remote desktop access which I guess, in theory, could mess things up.
What I have already looked at
I can rewrite the end-point address in my code at runtime to substitute localhost for the actual address or create the endpoint dynamically as described by Ron in the answers. Unfortunately I am using the WCF Routing service so I can version workflows. This means that my code calls the Router endpoint and the WCF Router in turns calls the actual service/workflow using an endpoint specified in web.config. I don't have control over the Routing services endpoint resolution without, I think, writing a whole set of routing logic which just seems to be a lot of work when all I want is to call localhost :)
Switching to using named pipes; Alas, it causes some strange issues with workflows, probably due to duplexing, and I am on a deadline so haven't got time to get to the bottom of that at the minute.

You have to build the endpoint address dynamically.
Step 1:
In your ServiceDefinition.csdef you need to declare an Endpoint.
<ServiceDefinition name="MyFirstAzureWorkflow" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="WorkflowWeb" vmsize="ExtraSmall">
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Endpoint1" endpointName="WorkflowService" />
</Bindings>
</Site>
</Sites>
<Endpoints>
<InputEndpoint name="WorkflowService" protocol="http" port="80" />
</Endpoints>
<Imports>
<Import moduleName="Diagnostics" />
</Imports>
</WebRole>
</ServiceDefinition>
Step 2:
When you want to call the service
var endpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["WorkflowService"].IPEndpoint;
var uri = new Uri(string.Format(
"http://{0}:{1}/MyService.xamlx",
endpoint.Address,
endpoint.Port));
var proxy = new ServiceClient(
new BasicHttpBinding(),
new EndpointAddress(uri));

Okay, so this is how I solved it. IMHO it's a hack but at least it works.
Basically, I need to add a "*" binding, so I can do this in Powershell. The general recipe is here: http://blogs.msdn.com/b/tomholl/archive/2011/06/28/hosting-services-with-was-and-iis-on-windows-azure.aspx
That deals with adding Named Pipes support, but the principle is the same. I just changed the Powershell script to:
import-module WebAdministration
# Set up a binding to 8080 for the services
Get-WebSite "*Web*" | Foreach-Object {
$site = $_;
$siteref = "IIS:/Sites/" + $site.Name;
New-ItemProperty $siteref -name bindings -value #{protocol="http";bindingInformation="*:8080:"}
}
This now allows me to use http://127.0.0.1:8080/service.svc to access my service.
Note: You do need to follow the rest of the recipe to set elevated execution context and change the powershell execution mode, so do follow it carefully

Related

WCF set Endpoint and Binding dynamically in code

Yes, I've read the other questions on SO, MSDN, and other sites, but I found no answers as clear as I can understand. I need to set my Silverlight application's WCF references relative to the site that it's loaded from, but I can't get it to work. There is no problem with the service itself, it is working. When I move from local to my real server, I get errors in my SL app complaining about not connecting to localhost.
Here is my ServiceReferences.ClientConfig file:
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_AccountManager">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
<binding name="CustomBinding_FileManager">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
<binding name="CustomBinding_SiteManager">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:60322/AccountManager.svc"
binding="customBinding" bindingConfiguration="CustomBinding_AccountManager"
contract="AccountManager.AccountManager" name="CustomBinding_AccountManager" />
<endpoint address="http://localhost:60322/FileManager.svc" binding="customBinding"
bindingConfiguration="CustomBinding_FileManager" contract="FileManager.FileManager"
name="CustomBinding_FileManager" />
<endpoint address="http://localhost:60322/SiteManager.svc" binding="customBinding"
bindingConfiguration="CustomBinding_SiteManager" contract="SiteManager.SiteManager"
name="CustomBinding_SiteManager" />
</client>
</system.serviceModel>
</configuration>
Yes, I will optimize the buffer/message sizes and I know the possible DoS exploits, forget about it for now, I need them for big file transfers. An approach I tried is while instantiating the clients, I've used this code:
fileManager = new FileManagerClient(new BasicHttpBinding(), new EndpointAddress("http://" + Settings.Host + "/FileManager.svc"));
accManager = new AccountManagerClient(new BasicHttpBinding(), new EndpointAddress("http://" + Settings.Host + "/AccountManager.svc"));
where Settings.Host is my own method which returns me the host that the SL app is running from, tested, works. When I uploaded my XAP and tried, it still wanted to go for http://localhost:60322/AccountManager.svc, after further investigation, I've realized that there are still lots of references to localhost, in unseen files:
AccountManager.disco:
<?xml version="1.0" encoding="utf-8"?>
<discovery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/disco/">
<contractRef ref="http://localhost:60322/AccountManager.svc?wsdl" docRef="http://localhost:60322/AccountManager.svc" xmlns="http://schemas.xmlsoap.org/disco/scl/" />
</discovery>
Parts of AccountManager.wsdl:
... <wsdl:import namespace="" location="http://localhost:60322/AccountManager.svc?wsdl=wsdl0" />...
...[lots of operation declarations]...
<wsdl:service name="AccountManager">
<wsdl:port name="CustomBinding_AccountManager" binding="tns:CustomBinding_AccountManager">
<soap12:address location="http://localhost:60322/AccountManager.svc" />
<wsa10:EndpointReference>
<wsa10:Address>http://localhost:60322/AccountManager.svc</wsa10:Address>
</wsa10:EndpointReference>
</wsdl:port>
</wsdl:service>
Part of AccountManager1.xsd:
<xs:import schemaLocation="http://localhost:60322/AccountManager.svc?xsd=xsd2" namespace="http://schemas.datacontract.org/2004/07/Leftouch.Data.Summary" />
Part of configuration.svcinfo:
<endpoint normalizedDigest="<?xml version="1.0" encoding="utf-16"?><Data address="http://localhost:60322/AccountManager.svc" binding="customBinding" bindingConfiguration="CustomBinding_AccountManager" contract="AccountManager.AccountManager" name="CustomBinding_AccountManager" />" digest="<?xml version="1.0" encoding="utf-16"?><Data address="http://localhost:60322/AccountManager.svc" binding="customBinding" bindingConfiguration="CustomBinding_AccountManager" contract="AccountManager.AccountManager" name="CustomBinding_AccountManager" />" contractName="AccountManager.AccountManager" name="CustomBinding_AccountManager" />
Part of Reference.svcmap:
</ClientOptions>
<MetadataSources>
<MetadataSource Address="http://localhost:60322/AccountManager.svc" Protocol="http" SourceId="1" />
</MetadataSources>
<Metadata>
<MetadataFile FileName="AccountManager2.xsd" MetadataType="Schema" ID="e473b2d5-7af3-4390-87c3-a4fc3f54fb96" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?xsd=xsd2" />
<MetadataFile FileName="AccountManager1.xsd" MetadataType="Schema" ID="fd3a1ae0-b38b-4586-8622-5b0ee07e39fb" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?xsd=xsd0" />
<MetadataFile FileName="AccountManager.xsd" MetadataType="Schema" ID="6a49ee64-6eac-40e2-bcff-26418435e777" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?xsd=xsd1" />
<MetadataFile FileName="AccountManager.disco" MetadataType="Disco" ID="9ec9a8cc-0cf0-4264-a526-b5a6c08f7d36" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?disco" />
<MetadataFile FileName="AccountManager1.wsdl" MetadataType="Wsdl" ID="54a5b2c0-9d0e-4043-a7e4-d27ae6674bfc" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?wsdl=wsdl0" />
<MetadataFile FileName="AccountManager.wsdl" MetadataType="Wsdl" ID="f8923013-3a6c-412b-b7da-bee5a5a7bb64" SourceId="1" SourceUrl="http://localhost:60322/AccountManager.svc?wsdl" />
..and ALL these again for other 2 services too.
I am not a master of web services/bindings/endpoints/operation contracts or any related stuff. I just want to make my totally already-nice-working (when URI is hardcoded) system work for relative URIs, that's all I need. There must be a simple solution. Can someone explain what exactly those file types and declarations resemble, which are important and which are optional, and how can I create dynamic service references in the cleanest form. Please, with explanations. I've already seen lots of posts and articles about dynamic service bindings and references, but honestly, everything gets messed up and I end up not understanding anything from it. Any constructive criticism and solutions are welcome.
Is the config file for your service (not the client) using endpoints with fully qualified addresses (like your client config)? If so, the reason you're seeing all those localhost references is because when you add the service reference, it's going to carry through that address in the generated files.
Update the endpoint in your service config file to either use the fully qualified address on that machine (i.e., http://somname.com/service.svc), or set the baseAddresses in the config file to the machine name.
Additionally, if you're using WCF 4.0 (VS 2010/.NET 4.0), you can have WCF create a default endpoint for your service(s) by ommitting the endpoints from the config file altogether (as I understand it - we're just moving to 4.0 at work now, so I haven't played with the new features).
EDITED TO ADD
New approach, same basic idea (that the URI is being imported from somewhere). Based on your comments below, it sounds like your service's config is set up fine, with no hard-coded URIs pointing to localhost.
When you move your application to the target server(s), are you updating your reference to your service (via the Add Service Reference) as well, or simply moving the files that generates from your local box to the target server?
If you are, I'm wondering if that might be the source of your problem. I would think that specifying the service address when you create the client should override anything in the WSDL-related files, but maybe its not.
Something to try:
Delete the <client> section from your Web.config. Then, when you create the client, do so like this:
fileManager = new FileManagerClient(new BasicHttpBinding("CustomBinding_FileManager"), new EndpointAddress("http://" + Settings.Host + "/FileManager.svc"));
Make sure you pass in the name of the binding configuration section in the BasicHttpBinding constructor, otherwise you'll get the binding with the default values, not the larger values you specified.
The idea here is to eliminate any chance that the client config file settings are overriding what you're passing in on the FileManagerClient creation.
I'd consider it less than ideal to have to update the service reference for every deployment to each individual server - what you're trying to accomplish makes sense. I do something similar in an n-tier app I've written - the only difference is that I don't use service references, I generate the proxy via SvcUtil and then generate channels via ChannelFactory<T>, which is another route you might want to look at.
If none of this help, please feel free to e-mail me (my e-mail address is in my profile) - it might be easier to figure this out via e-mail exchange and then post the final solution.

How to use Fiddler to monitor WCF service

I have a WCF service that accepts a complex type and returns some data. I want to use Fiddler to see what the incoming requests to the service looks like. The client is .net console app which uses a Service reference proxy. Is this possible with Fiddler. I'm new to this tool and have only used it in the past to post data with the request builder.
You need to add this in your web.config
<system.net>
<defaultProxy>
<proxy bypassonlocal="False" usesystemdefault="True" proxyaddress="http://127.0.0.1:8888" />
</defaultProxy>
</system.net>
then Start Fiddler on the WEBSERVER machine.
Click Tools | Fiddler Options => Connections => adjust the port as 8888.(allow remote if you need that)
Ok, then from file menu, capture the traffic.
That's all, but don't forget to remove the web.config lines after closing the fiddler, because if you don't it will make an error.
Reference : http://fiddler2.com/documentation/Configure-Fiddler/Tasks/UseFiddlerAsReverseProxy
Fiddler listens to outbound requests rather than inbound requests so you're not going to be able to monitor all the requests coming in to your service by using Fiddler.
The best you're going to get with Fiddler is the ability to see all of the requests as they are generated by your Console App (assuming that the app generates web requests rather than using some other pipeline).
If you want a tool that is more powerful (but more difficult to use) that will allow you to monitor ALL incoming requests, you should check out WireShark.
Edit
I stand corrected. Thanks to Eric Law for posting the directions to configuring Fiddler to be a reverse proxy!
Just had this problem, what worked for me was to use localhost.fiddler:
<endpoint address="http://localhost.fiddler/test/test.svc"
binding="basicHttpBinding"
bindingConfiguration="customBinding"
contract="test"
name="customBinding"/>
Consolidating the caveats mentioned in comments/answers for several use cases.
Mostly, see http://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/ConfigureDotNETApp
Start Fiddler before your app
In a console app, you might not need to specify the proxyaddress:
<proxy bypassonlocal="False" usesystemdefault="True" />
In a web application / something hosted in IIS, you need to add the proxyaddress:
<proxy bypassonlocal="False" usesystemdefault="True" proxyaddress="http://127.0.0.1:8888" />
When .NET makes a request (through a service client or HttpWebRequest, etc) it will always bypass the Fiddler proxy for URLs containing localhost, so you must use an alias like the machine name or make up something in your 'hosts' file (which is why something like localhost.fiddler or http://HOSTNAME works)
If you specify the proxyaddress, you must remove it from your config if Fiddler isn't on, or any requests your app makes will throw an exception like:
No connection could be made because the target machine actively refused it 127.0.0.1:8888
Don't forget to use config transformations to remove the proxy section in production
So simple, all you need is to change the address in the config client: instead of 'localhost' change to the machine name or IP
This is straightforward if you have control over the client that is sending the communications. All you need to do is set the HttpProxy on the client-side service class.
I did this, for example, to trace a web service client running on a smartphone. I set the proxy on that client-side connection to the IP/port of Fiddler, which was running on a PC on the network. The smartphone app then sent all of its outgoing communication to the web service, through Fiddler.
This worked perfectly.
If your client is a WCF client, then see this Q&A for how to set the proxy.
Even if you don't have the ability to modify the code of the client-side app, you may be able to set the proxy administratively, depending on the webservices stack your client uses.
Standard WCF Tracing/Diagnostics
If for some reason you are unable to get Fiddler to work, or would rather log the requests another way, another option is to use the standard WCF tracing functionality. This will produce a file that has a nice viewer.
Docs
See https://learn.microsoft.com/en-us/dotnet/framework/wcf/samples/tracing-and-message-logging
Configuration
Add the following to your config, make sure c:\logs exists, rebuild, and make requests:
<system.serviceModel>
<diagnostics>
<!-- Enable Message Logging here. -->
<!-- log all messages received or sent at the transport or service model levels -->
<messageLogging logEntireMessage="true"
maxMessagesToLog="300"
logMessagesAtServiceLevel="true"
logMalformedMessages="true"
logMessagesAtTransportLevel="true" />
</diagnostics>
</system.serviceModel>
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information,ActivityTracing"
propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="xml" />
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="C:\logs\TracingAndLogging-client.svclog" type="System.Diagnostics.XmlWriterTraceListener"
name="xml" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>
I have used wire shark tool for monitoring service calls from silver light app in browser to service. try the link gives clear info
It enables you to monitor the whole request and response contents.
I just tried the first answer from Brad Rem and came to this setting in the web.config under BasicHttpBinding:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding bypassProxyOnLocal="False" useDefaultWebProxy="false" proxyAddress="http://127.0.0.1:8888" ...
...
</basicHttpBinding>
</bindings>
...
<system.serviceModel>
Hope this helps someone.
You can use the Free version of HTTP Debugger.
It is not a proxy and you needn't make any changes in web.config.
Also, it can show both; incoming and outgoing HTTP requests.
HTTP Debugger Free
Use fiddler a Reverse Proxy is the final solution for me.
First, configure fiddler as reverse proxy with REGDIT, like the doc said: https://docs.telerik.com/fiddler/configure-fiddler/tasks/usefiddlerasreverseproxy#configure-fiddler-as-reverse-proxy
1)Click Tools > Fiddler Options. Ensure Allow remote clients to connect is checked
2)Create a new DWORD named ReverseProxyForPort inside HKEY_CURRENT_USER\SOFTWARE\Microsoft\Fiddler2.
3)Set the DWORD to the local port where Fiddler will re-route inbound traffic.
4)Restart Fiddler.
Second, change the client to call service through proxy
for example , here is my client app.config:
<client>
<endpoint address="http://localhost:61236/WeatherForecastService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IWeatherForecastService"
contract="ServiceReference1.IWeatherForecastService" name="BasicHttpBinding_IWeatherForecastService" />
</client>
change the client to use proxy endpoint address.
WeatherForecastServiceClient client = new WeatherForecastServiceClient("BasicHttpBinding_IWeatherForecastService", "http://localhost:8888/WeatherForecastService.svc");
var data = client.GetData(1000);
client.Close();
Change the localhost in the URL to localhost.fiddler, this small change worked for me.
Also if anyone testing the service from WCF Test Client don't forget to edit the URL in the config endpoint
Right click on the config file
Click Edit with Svc Config Editor
Click on Endpoints and edit the endpoint to localhost.fiddler
Check Start a new proxy while calling method

How to configure WCF service from code when hosted in IIS?

My WCF service exposes an https AND an http endpoint. Apart from the SSL they are identical. They map to the same code.
The ultimate intention is for external users to connect via https, internal users to use http.
In development this gives me a problem. Cassini, the development web server packaged in VS, hates SSL.
I'm wondering if I can configure the service from code, so when running under Cassini, I would not configure https.
Hence the question - How do I configure the service from code if it is IIS hosted? I'd be very happy with alternative answers on how I can persuade Cassini to NOT complain about the https part of the configuration.
"IIS will take care of spinning up the necessary ServiceHost based on your *.svc file - not a whole lot you can do about that, really."
Not too close to the truth. Exactly in the SVC file of your service there is attribute named Factory. Where you can specify the the class and the assebly where the class is located. This class may be your own descendant of Web|DataServiceHostFactory
So your svc markup would look like this
<%# ServiceHost
Language="C#"
Debug="true"
Service="name.space.myService"
CodeBehind="name.space.myService.svc.sc"
Factory = "name.space.WebServiceHostFactoryEx, assembly.name"
%>
The WebServiceHostFactory will be created for every service hit and will recreate your host the way you want it.
You will also need to inherith WebServiceHost and create it the way you need it with certain endpoins, behaviors, addresses, etc settings - whatever you like.
There is very nice post from Michele Bustamante here
EDIT: I figured out the above link is not working anymore, so here it is another one.
I am using this in IIS hosted enviroment for couple of services that are initialized same way.
When you're hosting in IIS, you're leaving a lot of care taking into the realm of IIS - you cannot really grab a hold of your service in this case.
IIS will take care of spinning up the necessary ServiceHost based on your *.svc file - not a whole lot you can do about that, really.
My solution would be different - externalize the <service> tag in your configuration file (web.config):
<system.serviceModel>
<services>
<service configSource="service.dev.config" />
</services>
</system.serviceModel>
In your dev environment, only expose the http endpoint - so your service.dev.config would look something like this:
<service name=".....">
<endpoint name="default"
address="....."
binding="basicHttpBinding" bindingConfiguration="insecure"
contract="......" />
</service>
Create a second service.prod.config which then contains both endpoints - http and https:
<service name=".....">
<endpoint name="default"
address="....."
binding="basicHttpBinding" bindingConfiguration="insecure"
contract="......" />
<endpoint name="secure"
address="....."
binding="basicHttpBinding" bindingConfiguration="secure"
contract="......" />
</service>
and reference that in your web.config on the deployment server.

How to configure WCF with NO security, and most minimal bindings

I've been having major problems with WCF, which are not amenable to any wisdom I can find. I've tried basicHttpBinding, wsHttpBinding, netTcpBinding (with the Net.Tcp service running on both machines). The behaviour can be boiled down to:
works on same machine, when running in debugger, standalone (non-service) process, Windows service
cannot be accessed from other machine, unless I'm running the service in the debugger
I must confess to being baffled by the plethora of options for bindings/security/etc. I must also confess to being ignorant of the restrictions on running as a Windows service, although I'm sure I've read somewhere that the SYSTEM account does not have network credentials. I've tried running the service under my own credentials, with the same results.
I'm up against a deadline in a few hours, and at the moment I'm going to have to resort to running as a standalone process, which is pretty embarassing.
I'm sure I've made some simple but crucial mistake in my understanding, and would be happy to be enlightened. But for now I'd be happy if someone knows a quick and dirty way to run WCF between two machines on the same Windows network without any security necessary, where one is a windows service and the other is a Windows GUI app.
This calls for the NetNamedPipe binding (on-machine communication)!
Your config would have to look something like:
<system.serviceModel>
<bindings>
<netNamedPipeBinding>
<binding name="NoSecurityIPC">
<security mode="None" />
</binding>
</netNamedPipeBinding>
</bindings>
<client>
<endpoint name="internal"
address="channel1"
binding="netNamedPipeBinding"
bindingConfiguration="NoSecurityIPC"
contract="IYourService" />
</client>
<services>
<service name="Namespace.YourService">
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/" />
</baseAddresses>
</host>
<endpoint
address="channel1"
binding="netNamedPipeBinding"
bindingConfiguration="NoSecurityIPC"
contract="IYourService" />
</service>
</services>
</system.serviceModel>
Marc
Is it a Windows Firewall issue? BasicHttpBinding defaults to security mode "none", and setting it on netTcp for client and service is as simple as putting a security mode="none" element under the root binding element in both the client and server config. Seems like the firewall on the server would be the only thing that'd keep you from connecting if the security mode is set to none.
1) as well as opening the firewall, you almost certainly need to explicitly permit binding the serving port via the APIs on HTTP.SYS. This can be done by the built in netsh http add command on Vista or later, via the downloadable httpcfg tool on earlier systems, or by directly P/Invoking against the HTTP APIs with administrative privilege as a set-up step.
2) if you have multiple services, getting them to share the address space on a given port is far easier if they talk HTTP than net.tcp
3) as a default, a service that talks across the network should be run with Network Service identity, ideally as a service-specific SID : even if the data are not sensitive, exposing a high privilege user like System on the network is not good practice.

Can IIS-hosted WCF service be configured for BOTH Windows Auth and Anonymous?

I've got a small WCF webservice working with the built-in WCF Service Host and with hosting by the Visual Studio 2008 built-in development webserver.
I these hosting enviroments I have relied on the WCF Test Client for invoking the service methods.
Now I am running into problems with my next phase of testing:
I have it hosted in IIS 5.1 on my WinXP dev machine and I think maybe the problem is I cannot continue to use WCF Test Client anymore. Here is what's happening:
Case 1: "Anonymous Access" is CHECKED (ENABLED)
WCF Test Client UI comes up properly, exposing the WebMethods and the INVOKE button.
Yet when I click INVOKE it fails to connect with a backend data store (a 3rd party product) that requires Windows authentication. I could post the error I get back from the product.DLL but I don't think it is relevant.
Case 2: "Anonymous Access" is un-CHECKED (DISABLED)
WCF Test Client UI fails to even initialize properly. My researching of this tells me that MEX (WS-Metadata Exchange) requires "Anonymous Access" and (apparently) WCF Test Client requires MEX. Here are key snippets of the error being returned:
Error: Cannot obtain Metadata from http://localhost/wcfiishost
The remote server returned an error: (401) Unauthorized.HTTP GET Error
URI: http://localhost/wcfiishost
There was an error downloading 'http://localhost/wcfiishost'.
The request failed with the error message:
Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service
The are lots of explanations of binding options, message security, etc. and stuff I honestly do not understand. Here is my take on where I am but I would love your opinions:
(a) Because I know my WCF webservice MUST be configured to use Windows Authentication, I conclude I cannot continue to use the WCF Test Client when hosting my service in IIS. That it has effectively outlived it's usefulness to me. I will just have to take the time to write a web client because WCFTestClient won't work without Anonymous.
(or)
(b) It is possible to use WCF Test Client if it and the hosted service are configured propertly (I just don't know what the special configuration techniques are for this).
Which is correct? Time to stop using WCFTestClient or is there a way to have it both ways? Thanks in advance for your advice.
EDIT: 11 June 09
Is there anything else I can provide to help someone else help me on this question?
I just tried to have the same setup - but in my case, everything seems to work just fine.
ASP.NET web site
WCF service, using basicHttpBinding without any special settings at all
IIS Application with anonymous = enabled and Windows authentication = enabled (both turned on)
I can easily connect to it with the WcfTestClient and retrieve the metadata, and I can then call it, no problem.
Inside my service function, I check to see whether the current user is a known user or not, it is correctly identified as a Windows authenticated user:
ServiceSecurityContext ssc = ServiceSecurityContext.Current;
if (ssc.IsAnonymous)
{
return "anonymous user";
}
else
{
if(ssc.WindowsIdentity != null)
{
return ssc.WindowsIdentity.Name;
}
if (ssc.PrimaryIdentity != null)
{
return ssc.PrimaryIdentity.Name;
}
}
return "(no known user)";
I don't really know, what more to check for (except I'm on Vista with IIS7). Any chance you could include this code to check for the user in your service code? Just to see....
Marc
Marc, your setup is not even close to Johns.
John uses WSHttpBinding that uses Windows Credentials for Message mode transport. The Windows Authentication isn't being used with BasicHttpBinding. Furthermore, John had AnonymousAuthentication disabled, which is why the Metadata Exchange (mex) is failing.
The call won't even reach inside the service side function, because we get a Error 401 (Unauthorized) when we try to call.
Just know John, I have the same issue, and I'm trying to somehow set up separate bindings per endpoint. Hopefully that will work.
When I set the title/subject of this question and reached a dead end here, I opened up the same issue in the MSDN forum with a different emphasis on the title (content of question essentially the same).
For me, the real issue was how to use WCFTestClient in IIS without Anonymous Authentication being set (because my service needed Integrated Windows Authentication only).
Mex apparently requires Anonymous and by default WCFTestClient seems to need Mex. The key seems to be accomodating both my doctoring up the web.config file carefully.
Anyway, I got it working with this web.config below (the MSDN link is here:
<?xml version="1.0"?>
<configuration>
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="wsBindingConfig"
contract="sdkTrimFileServiceWCF.IFileService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="basic"
binding="basicHttpBinding"
bindingConfiguration="bindingConfig"
contract="sdkTrimFileServiceWCF.IFileService" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="bindingConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
<wsHttpBinding>
<binding name="wsBindingConfig">
<security mode="Transport">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</serviceBehaviors>
</behaviors>