WCF endpoints, baseAddressPrefixFilters, host headers - wcf

I have two websites on the same machine. The first (client) references a WCF service on the second site(server).
How do I set the address for the service reference? When moving from development on my local machine to the group development server, how do I change the url for the service? The sites are differentiated by host headers, like
http://dev.admin/...
and
http://dev.public/...
I sense that this can be handled using multiple endpoints, but I'm very new to WCF and really don't have a clue what I'm doing here.

After much frustration, I managed to determine that both web.config files (on the client and server, both of which are web apps in this case), the following sections have to be changed:
Client:
<client>
<endpoint
address="http://mysite.com:port/services/someservice.svc"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ISomeService"
contract="MyServices.ISomeService"
name="BasicHttpBinding_ISomeService" />
</client>
</system.serviceModel>
Server
<system.serviceModel>
<serviceHostingEnvironment>
<baseAddressPrefixFilters>
<add prefix="http://mysite.com:port/services"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<behaviors>
<serviceBehaviors>
<behavior name="MyServices.SomeServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MyServices.SomeServiceBehavior"
name="MyServices.SomeService">
<endpoint address="http://mysite.com:port/services/someservice.svc"
name="endpoint.SomeService"
binding="basicHttpBinding"
bindingConfiguration=""
contract="MyServices.ISomeService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
The thing to note here is that the host address in all three relevant sections (client endpoint address, server baseAddressPrefixFilter value, and server endpoint address) have to match.
I'm able to switch between servers by modifying these, as long as they match. I would still prefer a way to set this based on which machine the server is running on, but this works for the moment.
WCF Impressions
What's hot: persistent object. The client proxy object (created when you add a service reference) maintains a persistent connection to the service on the server. The service instance referenced by the client proxy maintains its state between calls, which can simplify method signatures and makes the client proxy object, and the service as a whole, much more useful for certain applications. Parameter object types can be shared between the client and server if they're declared in a common library, meaning that you don't have to create two very similar classes or wrapper classes to pass non-primitive data structures back and forth.
What's not: configuration is a royal pain, poorly documented, and far too involved. Getting this to work in a test/dev/staging/production environment configuration where the service neesd to be aware of its location is frustrating. I'm not convinced that making the service aware of its domain url (rather than, say, a relative path to whatever it's running on) has any significant benefit, security concerns aside.
That said, I'm continuing to go down the WCF path as the advantages thus-far outweigh the headaches.

Easiest way: run the WCF parts on different ports.

Related

HTTP could not register URL ... because TCP port ... is being used by another application

First, I am not good in WCF.
I have a WCF service hosted in WindowsService.
Since sometime the service stoped to run because of the exception:
HTTP could not register URL http://+:8092/MyService/ because TCP port 8092 is being used by another application.
Nothing uses this port, it says the same about any port I tried.
SSL certificate is configured.
There are many machines that can start this service, but the most required (customer's) machine cannot.
I saw many posts in this site or anywhere else, but cannot find a solution.
I never see the post like "It helped me".
I am stuck several days already, help please.
Below the data from config file:
<system.serviceModel>
<services>
<service name="MyCompany.MyApp.MyAppService" behaviorConfiguration="MetadataSupport">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8092/MyAppService" />
<add baseAddress="net.tcp://localhost:8093/MyAppService" />
<add baseAddress="net.pipe://localhost/" />
</baseAddresses>
</host>
<endpoint binding="wsDualHttpBinding" contract="MyCompany.MyApp.IMyAppService" />
<endpoint binding="netTcpBinding" contract="MyCompany.MyApp.IMyAppService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<endpoint address="tcpmex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MetadataSupport">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True" httpGetUrl="" />
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug httpHelpPageEnabled="True" includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
You are using WCF duplex communication with wsDualHttpBinding. In this case, WCF creates a HTTP socket on port 8092 to service client callbacks. Clearly the client was conflicting with IIS 5.X. (I guess you have XP and IIS 5.x)
To resolve this problem you have to provide a clientBaseAddress in the binding configuration on the client and specify a different port.
Sample client configuration:
I hope that this is really the problem in your machine, please notify me about the results of this solution.
Good luck :-)
Try running the windows service as someone with admin privileges. Certain versions of Windows (2008/Vista and up) are picky about who can open ports. If that helps, then you certainly don't want to actually run the service as an admin, but it at least points you in the permissions direction.
Also, you mention an SSL cert, but it is an 'http' url, not 'https'. That seems unusual.
I suggest to do the following diagnostics steps:
Try hosting the WCF Service in a Self-Host manner (Console Application):
use the class HttpServiceHost
use this binding: var binding = new HttpBinding(HttpBindingSecurityMode.Transport);
AddServiceEndpoint(typeof(YourServiceClass),binding,"https://url...");
If it works for you it seems that you have problems in configuring the WCF service to work under Managed-Windows Service.
Lets me know your results :-)

Securing WCF hosted inside public MVC2 App

I've got a WCF service that is to be called by an application hosted on the web server (for the short-medium term, we'll only need a single web server so disregard scalability issues)
The web server serves a public website. at example.com
The WCF service exposes calls which amongst other things run jobs and provide certain admin functionality not supported by the web model eg long running database operations.
The WCF service has to be hosted inside the web site as it uses compatibility mode to take advantage of the Asp.Net http(s) pipeline - specifically, the service can generate emails and the emails are templated using MVC. One side-effect of this is that the call has to use the publicly visible hostname eg https://example.com/JobService.svc so that links in emails point to example.com as opposed to localhost or similar.
Obviously, I don't want the general public to be able to kick off jobs/admin tasks so I want to secure the WCF service.
I can only use https as opposed to net.tcp or similar for the binding thanks to relying on the Asp.net http pipeline.
I have to bind to the publicly accessible IP address to be able to use the proper hostname (unless someone knows a way around this?)
I can't use kerberos/NTLM as the server isn't on a domain (and NTLM is weak anyway)
I can't use certificates as it complains:
The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'None'.
NB: I don't quite understand this as the website itself is only served via https. http simply returns a redirect to the same page via https.
(An interesting issue I'm having is that although the mex is served via https, the URLs inside the WSDL use http. I'm assuming this is a side-effect of not being able to set up TLS properly on my service so it thinks it's http even though it also responds on https)
So, I'm running out of ideas for how to secure my service. I could, of course, from within the service itself examine the request and determine if it comes from an IP used by the current server - but this feels very nasty and I'm effectively ignoring the work of experts and trying to put something in its place - Not a very good place to start.
Can anyone suggest a way to limit access to this service to processes on the local machine?
I've attached my current config below. (This is currently giving me the certificate error mentioned above)
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="WebJobServiceHTTPBinding" openTimeout="00:10:00"
sendTimeout="00:10:00">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"
aspNetCompatibilityEnabled="true">
<serviceActivations>
<add relativeAddress="WebJob.svc"
service="MyApp.WebJobService"
factory="MyApp.WCFDIServiceHostFactory" />
</serviceActivations>
</serviceHostingEnvironment>
<services>
<service behaviorConfiguration="WebJobServiceBehavior" name="MyApp.WebJobService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="WebJobServiceHTTPBinding"
name="HTTPEndpoint" contract="MyApp.JobService.Common.IWebJobService" />
</service>
</services>
<standardEndpoints>
<mexEndpoint>
<standardEndpoint name="WebJobServiceMex" />
</mexEndpoint>
</standardEndpoints>
<behaviors>
<serviceBehaviors>
<behavior name="WebJobServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate findValue="[Thumbprint of x509 cert used by website for SSL]"
storeName="Root" x509FindType="FindByThumbprint" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
"Can anyone suggest a way to limit access to this service to processes on the local machine?"
Run your service in a different web site in IIS, if you're not already.
You could bind your service in IIS to the internal network IP address which would allow internal LAN clients to access the service but not external clients.
Another binding option is to bind to a port that is not open on your firewall in order to allow access from internal clients only. Even better, bind to a port that is not open on your firewall, and bind to the internal LAN IP.
You could also try binding to IP address 127.0.0.1.
In the end, I was forced to implement my own Authentication system. This was relatively simple as authenticatio implied authorization - ie no permission levels. That said, I'm still unhappy at the solution and will change it if another option presents itself.

WCF base address not found

My service can work with normal WCF calls, but to expose metadata (the wsdl file) I have to change configuration in such a way the normal WCF host fails.
I've spend countless hours on google trying to solve this, big problem there is that hosting a service inside a website is never discussed (yes this is different).
requirements:
Runs in an existing web site
Use sessions
Operable with Java, and as much .net versions as possible.
Expose metadata (wsdl will be enough)
edits:
IIS cannot be used
I'm using .NET 4 and WCF 4.
In this configuration the metadata can be reached (through the wsdl file) but when trying to host the normal wcf endpoints I get and InvalidOperationException:
Could not find a base address that matches scheme http for the endpoint with binding WSHttpBinding. Registered base address schemes are [].
So the base address is ignored.
But when I supply full addresses to the endpoints (simply copy the base address in front of the current address) the normal WCF calls work fine, but when trying to access metadata I get the following error:
No protocol binding matches the given address 'http://localhost:8080/Functionality'.
Protocol bindings are configured at the Site level in IIS or WAS configuration.
Here is the web.config serviceModel section, I made a small test web site just for testing this, but it would be to much to post all of it here, if you send me a pm though I will e-mail it to you.
<system.serviceModel>
<services>
<service behaviorConfiguration="metadataSupport" name="MyStuff.TestWithMetadata">
<endpoint address="Functionality" binding="wsHttpBinding" name="FunctionalityBinding"
contract="MyStuff.ITestWithMetadata" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="metadataSupport">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="metadataSupport">
<!--Navigate with browser to httpGetUrl for the wsdl file-->
<serviceMetadata httpGetEnabled="true" httpGetUrl="Metadata" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false">
<serviceActivations>
<add relativeAddress="TestWithMetadata.svc" service="MyStuff.TestWithMetadata" />
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
If anyone has any ideas on how to solve this, please help out.
When you host your service in IIS (which I assume from your requirement "Runs in an existing web site"), then your base address in the config is moot - it will not be used at all.
When hosting in IIS, your service address is determined by:
your server name
possibly a port number
the virtual directory (and possibly subdirectories thereof) where the *.svc file lives
the *.svc file itself (including extension)
So it might be something like:
http://MyServer:7777/ExistingWebApp/TestWithMetadata.svc
or whatever it is that you have in your case.
You seem to be using .NET 4 and WCF 4 (never mentioned that.....) and in that case, you could skip the *.svc file altogether by adapting your config entry:
<serviceHostingEnvironment multipleSiteBindingsEnabled="false">
<serviceActivations>
<add relativeAddress="MyService" service="MyStuff.TestWithMetadata" />
</serviceActivations>
</serviceHostingEnvironment>
In this case, the value of relativeAddress= becomes the service address (within the virtual directory this web.config lives in) - so your service address would be something like:
http://MyServer:7777/ExistingWebApp/MyService
No need for a *.svc file at all in this situation.
Turned out I should use httpGetUrl link to get the metadata, instead of the .svc file, with that the base address can be ignored.
I also moved this test stuff to the actual web site and got tons of problems with zero endpoints being loaded. That was caused by the service reference in serviceActivations not set to the full service name (needs to have namespace included).
I accepted marc's answer because he did help me along and to prevent this question from popping up in unanswered.

WCF cannot find base address for http using REST service

I'm seeing the following error coming from WCF when trying to hit my REST WCF service on IIS 6.0:
Could not find a base address that matches scheme http for the endpoint with binding WebHttpBinding. Registered base address schemes are [].
My web.config looks like:
<system.serviceModel>
<serviceHostingEnvironment>
<baseAddressPrefixFilters>
<!--LOCAL-->
<add prefix="http://localhost/CustomTrackingService/CustomTrackingService.svc"/>
<!--TEST-->
<!--<add prefix="http://mytestserver/CustomTrackingService/CustomTrackingService.svc"/>-->
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<services>
<service name="MyService.CustomTrackingService">
<endpoint
address="MyAction"
binding="webHttpBinding"
contract="MyContract.ICustomTrackingService"
behaviorConfiguration="RestBehavior" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="RestBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
This works fine on my test server and works fine locally if I let Casini grab it (change base address prefix localhost/CustomTrackingService to localhost:1234/). I cannot remember what causes this to occur and my Google-fu is not producing useful results. Any ideas?
So looks like the problem is that locally i was trying to use a relative address with no base address defined. This worked on my test server because the test server incorrectly had more than one host header defined, which seems to translate into more than one base address defined in WCF, which is a no-no. i originally used the on the test server because i was getting an error about more than one base address for http, and without realizing the real problem, I filtered out the one I wanted using . Thsi won't work locally because I have no host headers defined, so the filter provided nothing and the relative addressing attempt failed because no base address was specified.
I'm going to do some more experimenting to see what the best set-up for my situation is, but checking the host headers in IIS definitely helped. Also, this link was a huge help in understanding what was really going on.
Why are you using a base address prefix + an unrelated value in endpoint#address if you're hosting in IIS?

SSL WCFs with custom binding

Has anyone ever tried to use custom binding with SSL in a WCF web service? I've seen a number of examples on how to do this with basicHttpBinding and wsHttpBinding but the equivalent always fails for customBinding. Specifically what I'm currently working with (the most successful configuration yet) looks something like this:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
</serviceHostingEnvironment>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="binaryHttps">
<binaryMessageEncoding />
<httpsTransport />
</binding>
</customBinding>
</bindings>
<services>
<service behaviorConfiguration="MyServiceBehavior" name="MyService">
<host>
<baseAddresses>
<add baseAddress="https://(myserver)/"/>
</baseAddresses>
</host>
<endpoint address=""
binding="customBinding" bindingConfiguration="binaryHttps"
contract="MyService" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
This actually allows us to access the service from the web, get it's WSDL and add a service reference inside visual studio alright, but when we actually try and use it live in our silverlight-3 application, it just sits there indefinitely waiting for a response and never times out. It actually ends up giving me low memory problems after a while on my machine (with 6GB of memory). The odd thing is that all this worked (and still does) perfectly in the development environment (using strictly the VS application hosts), it wasn't until we tried to deploy it to an actual server with a real SSL certificate that all these issues popped up.
I've searched fairly exhaustively for a solution to this problem but have so far not found anything and have tried just about everything - Is there anyone out there that's encountered this before and got around it?
So it turns out the problem wasn't with our web.config at all, it had to do with an issue with IIS 7 and Wildcard SSL certificates.
Namely, IIS 7 doesn't allow you to specify the hostname when binding an IP to an SSL connection and certificate. I'd guess that this is because it expects a non-wildcard SSL certificate that it can extract the explicit hostname from. What we ended up having to do was to go into the applicationHost.config file in {WindowsDir}\{System32}\{Inetsrv}\{config} and find the entry with our web service's bound IP address and change it explicitly to (ip):(hostname). It was then even displayed properly in the IIS config GUI.
After doing this we were to completely turn off all but SSL channels on all our servers and everything worked beautifully.
Thank god that's over!
AFAIK, using SSL has performance problem. We are using WCF behiovr to do the authentication. The way that we are using is that Silverlight => ASP.NET => WCF. We configured the Endpoint behivor in both Silverlight and WCF. Whenever we call the service, we passed the token for authentication.
Are you saying that you can use custom binding in ClientConfig of Silverlight?