Converting "HelloWorld" WCF Web Service to use https? - wcf

It's really hard to pick up web services if you're a beginner, not because the concept is hard - it isn't - but because the technology has gone through a lot of twists and turns and googling for help doesn't help if all you get back are answers for implementations done slightly differently.
[For example our solution has never had a .svc file or .asmx file though those turn up regularly in answers and our web.config doesn't have any behavior or binding element, as others seem to have]
We've used a tutorial to set up what I think is termed a "WCF Web Service" running on IIS6. It's working fine.
But we'd like to convert it to use encryption/https.
So we've checked the Require secure channel box in IIS:
Not sure what else to configure in there, but ... anyway, moving on. Next I'd imagine we have to modify our web.config file ... but what and how? Here's what we've got under system.serviceModel in our web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"></serviceHostingEnvironment>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"></standardEndpoint>
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
So what do we need to do next?

Ok, so it's hard to be prescriptive without ALL of the code unfortunately, but here's the overview:
You'll want to add those bindings and behaviors into the web.config.
I'd start with a basicHttpBinding, and just make it work like it does currently, but this time you'll be specifying your binding details instead of using defaults. To "turn off" https, change the Security mode in the bindingConfiguration to None.
You'll have something like this for your WCF service when you are done:
<services>
<service behaviorConfiguration="webServiceClientBehavior" name="My.Service.ServiceName">
<endpoint address="http://localhost:5803/LSClient" binding="basicHttpBinding" bindingConfiguration="secureBinding" contract="My.Service.IServiceName"/>
</service>
</services>
For the bindingConfiguration:
<bindings>
<basicHttpBinding>
<binding name="secureBinding">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
For the behaviorConfiguration:
<serviceBehaviors>
<behavior name="webServiceClientBehavior">
<!--For MetaData-->
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:5802/LSClientMD"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
These will need to be adjusted slightly for your implementation, but that's a basic overview.

Related

Publish WCF service to live website

I have only been playing w/ wcf stuff for about a week. I have it working on the dev server in Visual Studio, and now I want to put the project on the web. I used publish in Visual Studio to put it up w/ ftp. My FTP client confirms the files are there, but when I enter the address in a browser, I get the following error:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /EquipService.svc
Is there some setting I need to change or some setup I need to do on the server? I don't know why it says the file is unavailable since FileZilla shows the files on the server. Any help would be appreciated.
Thanks
EDIT:
Here is the Web.config, but just as a preface, I don't know what any of this is doing, I just copied bits and pieces from another guys project until the errors stopped and it worked. :|
<?xml version="1.0" encoding="UTF-8"?>
<protocolMapping>
<add scheme="http" binding="webHttpBinding" bindingConfiguration="webHttpBinding"/>
</protocolMapping>
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="metadataSupport">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
<baseAddressPrefixFilters>
<add prefix ="localhost"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<bindings>
<webHttpBinding>
<binding name="webHttpBinding">
<security mode="None">
</security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service name="EquipService.svc">
<endpoint address="~/EquipService.svc" binding="webHttpBinding" contract="Equipment.IEquipService" />
<endpoint contract="IMetadataExchange" binding="mexHttpBinding" address="mex" />
</service>
</services>
Im still not quite understanding why the services work on the Visual Studio server, and not on a web server.
But thanks for looking.
Use the WCFTestClient.exe to test your service.
Couple of things that I have learned. Its always good to create a seperate project for Services.
You can create a webservice and it can be consumed in the same web project using the localhost as address.
I had a scenario where I was trying to call it from my website's HTML page using javascript and it didn't work because I created the webservice in the regular webapp. In order to access it from javascript i needed to publish that service over the internet so the javascript can refer to a link (rather than localhost).
Well I did manage to find out the cause of the problem. It was the server. For some reason its physical path was pointing to an incorrect folder, and now the ball is in their court to fix it.
Thanks for the help

"The caller was not authenticated by the service" when using a customBinding only on machines on a domain

I wrote a WCF service hosted by IIS 6 on a server that is not part of a domain. It uses the following configuration:
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="Services.DeliveryStatsService">
<endpoint address="" binding="customBinding" bindingConfiguration="BindingWithMaxClockSkewForIncorrectlyConfiguredWindowsServer"
contract="Services.IDeliveryStatsService" />
</service>
</services>
<bindings>
<customBinding>
<binding name="BindingWithMaxClockSkewForIncorrectlyConfiguredWindowsServer">
<binaryMessageEncoding />
<security>
<localClientSettings maxClockSkew="00:20:00" />
<localServiceSettings maxClockSkew="00:20:00" />
<secureConversationBootstrap />
</security>
<httpTransport />
</binding>
</customBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
It would've been a simple basicHttpBinding, except that the server's clock is not set to the right time and its administrator will not change that, so a customBinding is required to allow for "clockSkew."
Clients use pretty much the same configuration (binding-wise) and can access the service without any trouble, as long as they are not part of a domain. However, clients that are part of a domain are rejected with the message "The caller was not authenticated by the service."
I turned on tracing and it would seem that the problem comes from a token exchange using SSPI negociation. Unfortunately, I can't seem to find the right configuration that will allow both machines that are not part of a domain and machines that are part of a domain to access the service. I have tried several values for authenticationMode, without avail. What's more, as far as I'm concerned, I don't need any particular security on this service.
WCF configuration is far from being my specialty and I haven't found an answer anywhere else, so I hope someone at Stack Overflow will be able to help. Thanks in advance.
Why do you need to set maxClockSkew when you don't need security? It is for handling time differences in timestamps which are not send without security. Once you add security element you turn on authentication because all attributes in the element have default values. Default value for mode is sspiNegotiated. I would start with removing security element.

WCF Over SSL Uses Machine Name IIS 7.5

I am having trouble setting up SSL with my WCF on IIS 7.5. I have seen this post:
WCF not using computer name instead of domain name when viewing MyService.svc?wsdl
However, the solution for IIS 7 does not seem to be working for me. In addition, I have a wildcard ssl, I'm not sure if that makes a difference.
I have tried modifying the applicationHost.config to both:
<bindings>
<binding protocol="https" bindingInformation="<ip or *>:443:<my.domain.com>" />
</bindings>
and
<bindings>
<binding protocol="https" bindingInformation="<ip or *>:443:<mycname>" />
</bindings>
IIS Resets seem to have no impact.
Little help anyone?
Going to answer my own question. The correct way to fix this is to adjust the web config on your WCF to include httpsGetEnabled="true". The relevant portion should look like this:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpsGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
After making this adjustment, you will need to delete, and re-add your web reference. I rebuilt the project, but I am not sure if that is necessary.

WCF Error - Could not find a base address that matches scheme

I'm trying to get a WCF web service to work with SSL, as you can imagine it works on my machine, however when I run it on the production environments I get this instead:
Could not find a base address that matches scheme http for the endpoint with binding BasicHttpBinding. Registered base address schemes are [https].
Despite many hours of wrestling with this problem I still have very little idea what this error message actually means - googling for this error message finds loads of people saying that I should either specify an address in my endpoint configuration or add a base address to my service, however:
My service worked perfectly fine without specifying either with SSL disabled
In fact, my service works perfectly fine with SSL with the exact same configuration on another machine
Besides, I've found a post which reliably informs me that when hosting under IIS the base address is ignored anyway.
As you can probably tell, I'm currently feeling a very fustrated at my utter failure to achieve what I believed to be a relatively simple task, so:
What does this error message actually mean?
How are base addresses determined when hosting under IIS?
Where can I find reliable, understandable documentation about what all of my copy-pasted configuration actually means?
What do I need to do to get my service to actually work?
The interesting bits of my web.config are:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<services>
<service name="MyService" behaviorConfiguration="MyBehavior">
<endpoint binding="basicHttpBinding" bindingConfiguration="SecureTransport"
bindingNamespace="http://MyNamespace/Service" name="Basic"
contract="MyContract" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="SecureTransport">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
One thing that is off field but can cause this message is if the SSL certificate on the server is expired or not set up correctly.

WCF - Windows authentication - Security settings require Anonymous

I am struggling hard with getting WCF service running on IIS on our server. After deployment I end up with an error message:
Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service.
I want to use Windows authentication and thus I have Anonymous access disabled. Also note that there is aspNetCompatibilityEnabled (if that makes any difference).
Here's my web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<bindings>
<webHttpBinding>
<binding name="default">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="Windows"/>
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="AspNetAjaxBehavior">
<enableWebScript />
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="defaultServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization principalPermissionMode="UseWindowsGroups" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="xxx.Web.Services.RequestService" behaviorConfiguration="defaultServiceBehavior">
<endpoint behaviorConfiguration="AspNetAjaxBehavior" binding="webHttpBinding"
contract="xxx.Web.Services.IRequestService" bindingConfiguration="default">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" name="mex" contract="IMetadataExchange"></endpoint>
</service>
</services>
</system.serviceModel>
I have searched all over the internet with no luck. Any clues are greatly appreciated.
So it seems like pretty common issue. The point is to remove mex from your bindings:
<endpoint address="mex" binding="mexHttpBinding" name="mex" contract="IMetadataExchange"></endpoint>
Alternativelly you enable Anonymous access in IIS and in your web.config you make sure anonymous access is denied.
Hope this will help some other soul.
(I was 100% sure I tried it with mex removed. :-O )
You may check this one.
I managed to make it work as expected.
<configuration>
...
<system.serviceModel>
...
<bindings>
<basicHttpBinding>
<binding>
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
...
</system.serviceModel>
...
</configuration>
just use your service bindings for mex too.
So change your current config :
<endpoint address="mex" binding="mexHttpBinding" name="mex" contract="IMetadataExchange"></endpoint>
to
<endpoint address="mex" binding="webHttpBinding" bindingConfiguration="default" name="mex" contract="IMetadataExchange"></endpoint>
That should solve the problem
Anonymous authentication can, and in some cases must be enabled for the service but not for the site.
So check that your site's "root" authentication has only Windows Authentication enabled. Then expand your site, select 'service' folder and make sure that your service has Windows and Anonymous Authentication enabled.
I had identical environment where this worked, only difference in these environments was the service's authentication. Problem in my case was not caused be selected providers (Ntlm or Negotiate) but the authentication settings for site and service.
At least I had identical error message with basic MSSQL Master Data Services web site & service and this was the solution. I did get the error when running just the service but the site worked almost ok, MDS Explorer did not work because service's authentication settings were wrong at first. Cause of this miss-configuration might be a bug in MDS Configuration Manager when creating new MDS site?
So in my case the problem was not to be fixed by doing any special editing to the web.config nor the ApplicationHost.config files, I didn't do any editing the config files. Just selected the correct authentication settings for the web site and it's service in IIS manager. I am not sure that this is the case in here, but maybe worth to try?
It worked for me when I remove 'mex' endpoint and also set clientCredentialType = 'Ntlm'
I was hosting my WCF inside SharePoint.
Yes, it looks like you need to remove the mex endpoint completely. Setting
<serviceMetadata httpGetEnabled="false"/>
alone did not work. Thanks!
Additional solution:
You just have to make sure that the Service name and contract are correct.
Hope it helps in some way.
It appears this MEX binding issue was fixed in .NET 4.0. Changing our server's App Pool .NET CLR version from 2.0 to 4.0 cleared up the issue.