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.
Related
I read all over the msdn where it says to enable port sharing : The port sharing service should be started and my net.tcp binding should specify 'portSharingEnabled = True'.
I also see that net.tcp binding documentation shows the default value for portsharing as false.
But in my VS 2013, WIN 7 machine, I have a console app hositing many services and I am able to run it from VS without any issues. My servichost is able to host more than 10 services with the same port. What am I missing to understand ? Any ideas ?
I use this endpoint followed by servicename for all my services:
<service name="Lookup" behaviorConfiguration="">
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8000/"/>
</baseAddresses>
</host>
<endpoint
name="IEntitiesLookup"
binding="netTcpBinding"
address="LookupService"
contract="ILookup" />
</service>
I managed to clear my understanding on port sharing to an extent. But would be happy for more thoughts on this.
I managed to find the reason behind the above scenario. Within a process, I am able to host several endpoints which shares the same port. This does not need port sharing to be enabled. But if I have another process which tries to host some services with same port numbers, then an exception for 'ports already in use' happens. In this case, we then need to enable port sharing in the binding of all the endpoints in both the service host processes and start the PortSharing service.
I believe this boils down to the understanding that in the transport layer, the port numbers are tied to the process.
Is it possible to define a WCF backup list in a client, so that a single-point-of-contact routing service is not nessasary?
I have two services implementing the same contact (interface). If the first service is not avaliable I would like the client to know that the backup service is to be used.
Is this possible or do I have to create a routing service (single-point-of-contact) that the client would communication with?
<client>
<endpoint address="http://localhost:49192/OrdinaryCustomerService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICustomer"
contract="OrdinaryCustomerServiceReference.ICustomer" name="OrdinaryCustomerService" />
<endpoint address="http://localhost:49860/PremiumCustomerService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICustomer"
contract="PremiumCustomerServiceReference.ICustomer" name="PremiumCustomerService" />
</client>
<routing>
<backupLists>
<backupList name="CustomerBackupList">
<add endpointName="PremiumCustomerService"/>
</backupList>
</backupLists>
</routing>
Just an idea but i have a similar issue and i have been thinking about creating a routing service on the client (IIS webserver in my case) so that all request on the webserver can fail over to different web services. We also have multiple webservers for fail over so i would put a router on each.
Not ideal but best solution i have found so far. If the router on the IIS box goes down chances are the IIS will be down as well and therefore our system would have kicked over tot he other webserver anyway.
We also have proper wfc routers with backup for our middle teir but before it was a manual change to the webservice to handle this.
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.
I'm trying to get my head around the addressing of WCF services.
We have a client-server setup where the server occasionally (maybe once a day) needs to push data to each client. I want to have a lightweight WCF listener service on each client hosted in an NT service to receive that data. We already have such an NT service setup hosting some local WCF services for other tasks so the overhead of this is minimal.
Because of existing legacy code on the server I believe the service needs to be exposed as ASMX and use basicHttpBinding to allow it to connect.
Each client is registered on the server by the user (they need to configure them individually) so discovery is not the issue.
My question is, how does the addressing work? I imagine the user entering the client's address on the server in the form
http://0.0.0.0/MyService
or even
http://hostname/MyService
If so, how do I configure the client service in its App.config? Do I use localhost?
If not then what is the reccommended way of exposing the service to the server?
Note:
I don't want to host in IIS as that adds extra requirements to the hardware required for the client.
The clients will be almost certainly located on LANs, not over the public internet
You configure the base address of the service like so:
<system.serviceModel>
<services>
<service name="Ns.FooService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:9999" />
</baseAddresses>
</host>
<endpoint
address="/foo"
binding="basicHttpBinding"
contract="Ns.IFooContract" />
</service>
</services>
</system.serviceModel>
And then your service could be accessible through http://servename:9999/foo. You may take a look at this article for more information.
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>