WCF 4.0 Add WebHttpBinding Endpoint by Default - wcf

Is there a way to do this globally, automatically for all my WCF services via configuration in WCF 4.0?
That is, I know WCF 4.0 exposes new configuration techniques that applies certain behaviors by default to all hosted endpoints, and that you don't need to explicitly specify individual endpoints by config anymore...but can I do something in the config that says to automatically host all services with both a BasicHttpBinding and a WebHttpBinding (using a /web relative address for the WebHttpBinding)? Or do I still need to use a custom ServiceHostFactory for this?
Thanks.

See the Developer's Introduction to WCF 4 for lots of interesting stuff in WCF 4.
One of the new features is called default protocol mapping, and this combined with the default endpoints provided by WCF 4 might solve your problem.
Default endpoints means that WCF 4 will provide one endpoint for each contract your service class implements (typically only 1), and for each base address defined in your config (or code for the ServiceHost).
In order to make sure a http:// endpoint gets exposed automagically with the webHttpBinding, you also need to override the system default (which is basicHttpBinding) - which you can do thanks to the protocol mappings.
<configuration>
<system.serviceModel>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
</system.serviceModel>
</configuration>

Related

WCF - Is the services element mandatory

I think my question is rather simple, so I'll stick to the point:
Is it by any means possible to expose a service without specifying the services element and only the serviceHostingEnvironment element? I.e. would the below configuration be enough to host a WCF service? I'm asking because i've seen applications that - as far as I can tell - lack the services element, and I thought that was mandatory.
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
<serviceActivations>
<add relativeAddress="Service.svc" service="Namespace.To.My.Service" />
</serviceActivations>
</serviceHostingEnvironment>
With WCF 4.0 you don't need explicit service configuration as opposed to prior versions. It automatically adds default endpoints if no endpoints are defined explicitly.
Whatever configuration you mentioned in question is called File-less activation and you can activate service without even having physical .svc file. In WCF 4 you can define virtual service activation endpoints like one you have defined.
WCF detects what contracts are implemented by service and then method AddDefaultEndpoints adds one default endpoint per base address for each service contract implemented by the service. Note that this behavior is only when no explicit endpoints are added (either programmatically or through configuration). Should you add one explicit endpoint WCF stops adding default endpoints and it gives control to developer to customize it further.

Service vs Client nodes/sections in Web.Config

What is the difference between the Service node/section and the Client node/section in the configuration section? Why configure endpoints in one section over the other? Which is best for interoperability?
I'm currently building a service that talks to another service. I have endpoints for my clients and endpoints for the other service. Visual Studio seems to lump all the endpoints into the Client section.
I thought that client node was for your consumption and service node was for producing. But when you create a new wcf service visual studio puts your new service endpoint settings under the client node. I have moved my endpoint between both sections trying to figure out what the difference is.
When should I use service over client?
<system.serviceModel>
<services>
<service> <!--I noticed some tutorials and using wcf config edit tool
puts producer endpoint settings here -->
<endpoint blah settings/>
<endpoint blah settings/>
</service>
</services>
<client> <!--Visual Studio puts both producer and consumer endpoint
settings here -->
<endpoint blah settings />
<endpoint blah settings />
<endpoint blah settings />
</client>
<bindings>.....
</system.serviceModel>
Many settings in the WCF web.config (or app.config for that matter) can be shared for both consumers of a service as well as publishers of a service including:
Bindings
Endpoint Behaviors
Diagnostics
However as you have discovered, some config is specific to a service. A well-written service usually specifies:
It's base address. This is a convenience when defining a service as it allows your to define endpoints using relative addresses. Clients however don't use this particular setting as they need an absolute path. For this reason it makes no sense to specify in the section
Services can also be clients. If the client and server endpoints were all plonked together, WCF would not be able to know which should utilise the base address for one thing
Service behavior
By dividing up config between client and server, WCF is better able to know where to look for endpoints.
Which is best for interoperability?
I don't think that has anything to do with it. WCF is a means to achieve interopability but just by using WCF does not imply you will achieve it. Interopability is established when both parties agree on say a particular service contract; canonical data model; data transformation; message version or many of the other patterns as defined by SOA Patterns.org So there are various patterns you must follow. e.g. If you change a method on service contract but have not updated the clients then you have broken interopability by breaking the schema of the service.
Visual Studio seems to lump all the endpoints into the Client section
If your WCF process is both a consumer and producer of WCF services then it should not be putting all the endpoints under

How to specify implemented Service Contract dll in WCF config

My service implementation is present in Calc.dll.
WCF Service is present in Svc.dll
I have added contract inside endpoint tag in the WCF app.config file of Svc.dll.
<service behaviorConfiguration="Default" name="MySvc">
<endpoint contract="Company.ICalc" .... />
How does WCF know that the service is implemented in Calc.dll? We have just specified the contract name.
In order for this to work, your svc.dll project must somehow reference calc.dll - and thus, the .NET / WCF runtime can find the specified namespace and class.

Custom binding element can't be loaded in WCF under IIS, however it can load under WCF Self-Host

I'm able to run the WCF-SecureProfile sample that comes with the MSFT WCF samples download (http://msdn.microsoft.com/en-us/library/ee818238.aspx)
However I can't port this server component to IIS. I get the error that
<MakeConnectionBindingElement/> can't be loaded. Considering that I have the behavior extensions loaded I don't know why IIS can't see the extension, however the self-host version of my app can.
I uploaded the sourcecode of the project into codeplex for easy browsing. Here is a direct link to web.config and all other files.
2
I got the sample and set it up to run on IIS local. I didn't get the same issue as the one in this question but I did run into a big gotcha. Accessing the service in IIS gave me this error message:
Contract requires Duplex, but Binding 'BasicHttpBinding' doesn't support it or isn't configured properly to support it.
After some head scratching, I found the cause of this issue. WCF 4 now assigns default bindings to each transport (I'm liking this feature less & less). For the HTTP transport, the default binding is basicHttpBinding. The problem is the customBinding config does not override any default binding. This causes WCF to attempt to configure duplex over basicHttpBinding which of course isn't supported. The fix is to turn off the default transport mapping for HTTP and assign it to your custom binding as shown below for this service:
<protocolMapping>
<clear/> <!-- removes all defaults which you may or may not want. -->
<!-- If not, use <remove scheme="http" /> -->
<add scheme="http" binding="customBinding" bindingConfiguration="rspBinding"/>
</protocolMapping>
Once I added this to the serviceModel element, the IIS based service worked just fine.

404 BadRequest exposing WCF service through external IP using IIS host headers

We host a WCF webservice on Windows Server 2003. This server only has 2 internal IP's. We want to expose the service externally. This is done through the firewall that maps an external IP to the service.
So, I would need to modify the service to display that external IP for the internal links. This is not an issue since it should only be used externally.
Changing the Host Header value in IIS gives a 'Bad Request (Invalid Hostname)' response from IIS. I also added an 'address' value to the endpoint entry in the web.config ... but it sill just points to the internal machine name. Any ideas?
edit: I can verify that IIS7 has the exact same behaviour. Address didn't work. Different hostname gave Invalid Hostname error. Is there seriously no way to present a different (fictive) IP? :/
edit2:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicAnonymous">
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Extended">
<serviceMetadata httpGetEnabled="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</serviceBehaviors>
</behaviors>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="false" logMessagesAtServiceLevel="false" logMessagesAtTransportLevel="true" maxMessagesToLog="3000"/>
</diagnostics>
<services>
<service behaviorConfiguration="Extended" name="AnCWCFWebService.ProductInfoProvider">
<endpoint address="" binding="basicHttpBinding" name="ASMX" bindingConfiguration="BasicAnonymous" contract="AnCWCFWebService.Interfaces.IProductInfoProvider"/>
</service>
</services>
</system.serviceModel>
404 BadRequest Due to IIS Configuration...
If you are receiving a 404 BadRequest error from IIS after attempting to modify host headers in IIS, this is common, but there is a fix!
Fix By Making IIS Configuration Changes
How can WCF support multiple IIS Binding specified per site?
Fix By Making WCF Code Modifications
Alternatively, the following article explains how one developer solved this issue with a combination of configuration and code:
Well, that was fun! An adventure in WCF, SSL, and Host Headers
http://geekswithblogs.net/rakker/archive/2008/07/03/123562.aspx
The article references two important links...
The first one explains how to properly set the host headers in IIS:
Configuring Server Bindings for SSL Host Headers (IIS 6.0): http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/8d9f2a8f-cd23-448c-b2c7-f4e87b9e2d2c.mspx?mfr=true
After getting host headers working, you'll find that...
"you can't have more than one host
header for IIS or wcf will break"
The solution to working around this limitation is found within this article, and there is also a comment on the GeeksWithBlogs.net article above that provides an enhanced variation:
WCF: This collection already contains
an address with scheme http
If you are still experiencing trouble, let us know in the comments below...
If the Service is Not Working...
My experience with WCF is that it is very tricky at times, especially with configuration. If one is following best practices and not doing anything non-standard, the great majority of deployment problems are the result of a botched configuration file.
In theory (not so much in practice, due to architectural differences), setting up a WCF service on IIS should be no different than setting up a typical virtual directory and corresponding application for web application or for an ASMX web service.
Therefore, I recommend that if this is the first WCF service you are exposing to the Internet, follow the same simple approach you would take when exposing your first website. Basically, create a new sample "WCF Service Application" (this is available in the Add New Project dialog, under the Web section of C# or VB).
Once you have it working, follow your deployment practices to move it into a production sandbox and test it locally. This sandbox would preferably already have some web sites or web services installed and known to be accessible from the Internet, in order to eliminate any doubt about the typical network configuration issues. If you have a sample ASMX web service that is already successfully exposed on the Internet from that server, that would be best.
Next, try testing the the ASMX and the WCF services from web browser, both locally on the server, internally on other desktops and then finally externally.
Testing URLs
We want to test accessing the standard SVC and ASMX file from the web browser in all the varieties of URL flavors that are available and relevant. The results should be similar, with summary page about he service rendering in the window. The difference will be that the ASMX web service's summary will likely allow you to execute the web methods on the service if that feature has not been disabled in the web.config file.
Compare the results of browser fetches of the following styles of URLs...
http://localhost/WcfService1/Service1.svc
http://localhost/WcfService1/Service1.asmx
http://MachineName or MachineFQN/WcfService1/Service1.svc
http://MachineName or MachineFQN/WcfService1/Service1.asmx
http://MachineLocalIP#1/WcfService1/Service1.svc
http://MachineLocalIP#1/WcfService1/Service1.asmx
http://MachineLocalIP#2/WcfService1/Service1.svc
http://MachineLocalIP#2/WcfService1/Service1.asmx
http://ExternalIP/WcfService1/Service1.svc
http://ExternalIP/WcfService1/Service1.asmx
All of these tests should return similar results.
Testing Service Methods
If you feel like it, go head and test some web methods on the ASMX web service for any of the tested URLs, from the web browser. You'll soon see that we can test ASMX web services a different way also...
Next we'll test web methods on both the WCF service and the ASMX web service by using the WcfTestClient.exe application that is found in the Visual Studio 2008 distribution (C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE).
You will need to add the services through the File->Add Service menu item, typing in the URL above for each service URL that you wish to test. Make sure to include the filename of the SVC and ASMX files. If all is well, the MEX endpoint that is enabled by the "httpGetEnabled" attribute of the <serviceMetadata/> element in the web.config file will return the data that is necessary for the utility to operate, thereby populating the tree with the inventory of our service methods like this:
From this point, it will be useful to refer to the following to resources:
WCFTestClient: http://msdn.microsoft.com/en-us/library/bb552364.aspx
What's New for WCF in Visual Studio 2008: http://msdn.microsoft.com/en-us/magazine/cc163289.aspx
Conclusion
If you make it this far, then I do not expect any other issues and you should now attempt to compare the setup of the samples to the WCF service that you are attempting to publish to the Internet, and hopefully the differences will be obvious.
Remember to treat the WCF service like an ASMX web service during you diagnostics, assuming that the web.config is known to be set up correctly.
If you are still unable to make things work, check this guide for further technical advice:
Deploying an IIS-hosted WCF service: http://msdn.microsoft.com/en-us/library/aa751792.aspx
Finally, if all else fails, just wrap your WCF service in an ASMX web service:
How to: Expose WCF service also as ASMX web-service: http://kjellsj.blogspot.com/2006/12/how-to-expose-wcf-service-also-as-asmx.html
You just need to configure your host header in the IIS so that the links in the WSDL references will use the donmain name rather local machine name.
Check out
Steps to configure IIS host header so that WCF will use domain name in WSDL references.
Why not just assign a new IP address to the server instead of messing around with hostnames? A Windows Server can have multiple IP addresses for the same NIC.
Here is an article that talks about it.