WCF over SSL - 404 error
Okay, I must be missing something utterly simple here, because I've been googling for days, and looking at dozens of answers there, and here on SO, and i just CANNOT get this to work, no matter what i've tried. The service works perfectly fine when called over plain HTTP.
Here's our setup... we have a domain, http://www.mydomain.com . We have an SSL certificate installed on that domain from thawte, just as we would if we were securing an e-commerce site. That all works fine, and i can go to https://www.mydomain.com and it works right. I'm running VS2008, .NET 3.5 site on Windows Server 2003 R2.
Now, I added a Silverlight-enabled WCF service to my site, which i want to communicate with over SSL. If i browse to https://www.mydomain.com/myservice.svc, it shows me the WSDL-descriptive "You have created a service" page as expected, which shows to create your client using
svcutil.exe https:// ...
EDIT: I realized the url shown for the svcutil in the wsdl file was actually pointing to the physical box name of the web server, not the proper domain. So i went through the steps shown in this blog posting to update the SecureBinding of the website in IIS using the adsutil script. Now the wsdl file shows the correct SSL address, but i still get the same error.
Now i went and tried to hook my Silverlight app up to it, and it does not work, returning an exception in the result from the async calls, stating "The remote server returned an error: NotFound. A number of the blogs i've read talked about narrowing it down to Silverlight issues by creating a test Windows application, and trying to reference it from that. Well, I did that and even in a regular windows application trying to a开发者_开发百科ccess the service over SSL i get an exception stating:
System.ServiceModel.EndpointNotFoundException:
There was no endpoint listening at https://www.mydomain.com/mysubdir/myservice.svc that could accept the message.
This is often caused by an incorrect address or SOAP action.
See InnerException, if present, for more details. --->
System.Net.WebException: The remote server returned an error: (404) Not Found.
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
This despite the fact that i explicitly added the service reference to the Windows app using the HTTPS scheme and it properly gets all the methods and shows them in Intellisense in the editor.
Note that this is a service which does NOT require explicit log in on the user's part. I am going to be sending custom headers in my SOAP envelopes to verify that the requests are coming from our app, and I just want to keep predators from sniffing the line and picking out the custom headers.
Now to the code, where i must just have some stupid little setting wrong, because from all i've read, this should be a fairly straightforward exercise.
First, my service's code-behind class is decorated with the following attributes:
<ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any)>
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)>
The ServiceModel section of my web.config on the server looks like so:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBinding">
<security mode="Transport">
<transport clientCredentialType ="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="standingsBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<baseAddressPrefixFilters>
<add prefix="http://www.mydomain.com:80"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<services>
<service behaviorConfiguration="standingsBehavior" name="lijslwebdata">
<endpoint address="" binding="basicHttpBinding" contract="lijslwebdata"/>
<!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>-->
</service>
</services>
</system.serviceModel>
And the ServiceModel section of the app.config in my Windows application looks like the following:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_lijslwebdata" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00"
sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" messageEncoding="Text"
textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192"
maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://www.mydomain.com/mysubdir/myservice.svc"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_lijslwebdata"
contract="xdata.lijslwebdata" name="BasicHttpBinding_lijslwebdata" />
</client>
</system.serviceModel>
I had this same issue on my end. Your post helped me figure out what the issue was. here is my service model section. I discovered that the keys were the httpsGetEnabled then setting the bindingconfiguration I hope this helps.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="RequestImageBehavior">
<serviceMetadata **httpsGetEnabled**="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<dataContractSerializer maxItemsInObjectGraph="1073741824" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="RequestImageBehavior" name="RequestImage">
<endpoint address=""
binding="wsHttpBinding"
**bindingConfiguration**="HttpsBinding"
contract="IRequestImage">
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<bindings>
**<wsHttpBinding>
<binding name="HttpsBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>**
</bindings>
</system.serviceModel>
I was dealing with this recently, and want to add a tweak. If you follow the above instructions, you'll be able to get the service to work with HTTPS, but not simultaneously work on both HTTP and HTTPS. To do that, you need to have two endpoint configuration nodes, one for each protocol as follows:
<service name="MyCompany.MyService" >
<endpoint address="" behaviorConfiguration="AspNetAjaxBehavior"
binding="webHttpBinding" contract="MyCompany.MyService" bindingConfiguration="sslBinding" />
<endpoint address="" behaviorConfiguration="AspNetAjaxBehavior"
binding="webHttpBinding" contract="MyCompany.MyService" />
</service>
(taken from my codebase, adjust behaviorConfiguration and binding as appropriate)
I just spent a few hours on this and it turned out my problem was the service name
<services>
<service name="TimberMill.Web.Data.LogReceiverService">
<endpoint binding="basicHttpBinding" bindingConfiguration="basicBinding"
contract="NLog.LogReceiverService.ILogReceiverServer" />
</service>
</services>
had to exactly match the similar entry in my *.svc file.
<%@ ServiceHost
Language="C#"
Debug="true"
Service="TimberMill.Web.Data.LogReceiverService, TimberMill.Web"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf"
CodeBehind="LogReceiverService.svc.cs"
%>
I'm not sure if it was related to my use of Autofac. It all was working fine under plain HTTP. Failed under HTTPS though.
Well I think so, I don't want to disturb anything now by testing in more detail lest I anger the WCF-Config gods and my config breaks again. YMMV.
In my case non of these answers helped.
Instead, I needed to add a duplicate <binding>
section that has no name
attribute set.
Here is the dump of the appropriate section of my service's web.config file:
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<serviceMetadata
httpsGetEnabled="true"
httpsGetUrl="RemoteSyncService.svc"
httpGetBindingConfiguration="bindingConfig" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="">
<serviceMetadata
httpsGetEnabled="true"
httpsGetUrl="RemoteSyncService.svc" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="bindingConfig" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binding>
<!-- Add binding with EMPTY/MISSING name, see https://forums.iis.net/t/1178173.aspx -->
<binding maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>
I do hope this might be helpful for someone, some day.
I had the same issue and spent one day to resolve this issue. Finally below configuration worked me for HTTPS access.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBinding">
</binding>
<binding name="basicHttpsBinding">
<security mode="Transport">
<transport clientCredentialType ="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="standingsBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<baseAddressPrefixFilters>
<add prefix="http://www.mydomain.com/"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<services>
<service behaviorConfiguration="standingsBehavior" name="lijslwebdata">
<endpoint address="" binding="basicHttpBinding" contract="lijslwebdata"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<service behaviorConfiguration="standingsBehavior" name="sslwebdata">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpsBinding" contract="sslwebdata"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
Everything seems to be quite valid, no glaring mistakes at all...
Just one observation/question: where is your *.svc file located??
In the error message, I see:
https://www.mydomain.com/myservice.svc
Is your *.svc file really in the top-level virtual directory of your site?
Typically, the *.svc file is inside a virtual directory on IIS and thus the address would be something like:
https://www.mydomain.com/YourVirtualDirectory/myservice.svc
Of course, you can deploy an ASP.NET app and a WCF service *.svc file to the root of your IIS - but it's not very common, in my experience.
Just a thingie to check.....
Marc
Okay, I apparently fixed the issue, and I have absolutely no idea why/how.
Here's what I did.
- I added a BRAND NEW EMPTY Silverlight-enabled WCF service
- I then updated the web.config to reflect both services
- I then literally just copied and pasted everything about the first service into the second service, except the name.
Why this fixed it, I have absolutely NO idea.
FWIW for anyone, here is my new web.config ServiceModel section with the second service in it...
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBinding">
</binding>
<binding name="basicHttpsBinding">
<security mode="Transport">
<transport clientCredentialType ="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="standingsBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<baseAddressPrefixFilters>
<add prefix="http://www.mydomain.com/"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<services>
<service behaviorConfiguration="standingsBehavior" name="lijslwebdata">
<endpoint address="" binding="basicHttpBinding" contract="lijslwebdata"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
<service behaviorConfiguration="standingsBehavior" name="sslwebdata">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpsBinding" contract="sslwebdata"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
Several of the answers led me into reconfigure my web.config to contain two endpoints. I ended up with this following Web.config.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBinding">
</binding>
<binding name="basicHttpsBinding">
<security mode="Transport">
<transport clientCredentialType ="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="standingsBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
<baseAddressPrefixFilters>
<add prefix="http://www.myhost.com"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<services>
<service behaviorConfiguration="standingsBehavior" name="NameSpace.ClassName">
<endpoint address="" binding="basicHttpBinding" contract="NameSpace.ContractInterfaceName"/>
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpsBinding" contract="NameSpace.ContractInterfaceName"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
It didn't work for you before because you named your basicHttpBinding
configuration basicHttpBinding
but did not reference that configuration in your <service>
tag with the bindingConfiguration="basicHttpBinding"
In your changes that did work by adding another service configuration you then did reference the binding configuration that contains the <security>
node hence causing it work.
Just another thing to check if you're encountering the same 404 error as OP. I fiddled with lots of things, but finally the solution came down to merely adding the namespace to my service web.config.
So plain old ServiceFoo and IServiceFoo did NOT work:
<services>
<service behaviorConfiguration="quuxBehavior" name="ServiceFoo">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpsBinding" contract="IServiceFoo"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
But adding the namespace (ProjectBar) DID work:
<services>
<service behaviorConfiguration="quuxBehavior" name="ProjectBar.ServiceFoo">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpsBinding" contract="ProjectBar.IServiceFoo"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
精彩评论