WCF service returning 404 on method requests - c#

I have a WCF service page running only WebGets/WebInvokes over SSL - it works fine on my local machine (self signed cert). On production, however, I can reach service.svc (and it gives me the message about how to consume) but service.svc/AnyRequest returns a 404. Both environments are hosted in IIS 7.5.
I've enabled tracing and the service isn't even picking up any of the method requests (e.g. service.svc/SomeRequest), however it is processing service.svc just fine. It's also listening at https://computername.domain.net/path/service.svc - is this normal? Should it normally be pointing to https://publicfacing.com/path/service.svc?
Also note that the production server is hosting multiple sites within IIS.
Below is the system.serviceModel section of my web.config. The SSLBehave was suggested from here.
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"></transport>
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SSLBehave">
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="https" port="443"/>
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="UserManagement.ajaxAspNetAjaxBehavior">
<webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service name="UserManagement.ajax" behaviorConfiguration="SSLBehave">
<endpoint address="" behaviorConfiguration="UserManagement.ajaxAspNetAjaxBehavior"
binding="webHttpBinding" bindingConfiguration="TransportSecurity" contract="UserManagement.ajax" />
</service>
</services>
</system.serviceModel>

The first thing I do whenever I hit a 404 with a newly-developed WCF Web Service is checking the handler mapping required to interpret this type of call, because it's often the cause of the issue. There are several ways to work around the problem, many of which require a manual execution of the ServiceModelReg.exe console command: these are undoubtedly valid procedures but might also not work – or create additional problems – if your development machine has a particularly complex configuration. The resolution method I propose below is slightly longer to pull off, but has the advantage of solving the problem more safely and securely.
Open the Server Manager interface for machine management, usually present in both the Task Bar and the Start menu.
Go to the Dashboard (or Control Panel) and select Add Role or Feature to open the Wizard.
Select the Role-based or Feature-based installation type and the server you want to work on, that is, your local / local server.
Go to the Features section: Once there, expand the .NET Framework 3.5 Features node and / or the .NET Framework 4.5 Features node, depending on what you have installed: if you have both, you should perform the following step twice (for each one of them).
Expand the WCF Services section (if available), then select HTTP Activation (see screenshot below).
Continue until you complete the Wizard, then click Install.
Once the installation is complete, you should be able to run your WCF Service without incurring in the 404 error ever again.
For additional info regarding this specific issue and how to fix it, you can also read this post on my blog.

I would start by checking a number of things;
Permissions on the hosted directory?
.Net version is correct?
Have you added the certificate to the site?
Try putting an image in the same path, can you navigate to that (rule out the odd occasional path mappings)
Good luck!

You can implement transport level security using WsHttp bindings. See this article; in your bindings try this biding instead:
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
The article mentions you should tie up the bindings with the end points.

I had the same problem. From what I read, WCF isnt NT Authenticated authorization (or HTTPContext compatible) by default.
I had to add this to my config file for the WCF service web.config in the section:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
Which you did, plus this:
And on the actual service class definiation I had to add:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DataService : IDataDeliveryServiceContract
This fixed my problem.

Perhaps in your RouteConfig.cs file add this line:
routes.IgnoreRoute("{resource}.svc/{*pathInfo}");
So long as your .svc file is in the root of the application.

As you mentioned you can access your service by .svc extension service.svc but not in REST format service.svc/AnyRequest, the problem must be in routing integration.
add this to your web.config
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
<handlers>
<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd"/>
</handlers>
</system.webServer>
In the IIS 6 The cause of this error must be Check that file exists setting of svc extention, make sure "Check that file exists is unchecked". For more information see IIS Hosted Service Fails.

To help others that find themselves stuck with this - It may be that your service name is not the fully qualified name, which it must be.

The following setting in web.config fixed a WCF .svc 404 on a HTTPS web site :
<webHttpBinding>
<!-- https -->
<security mode="Transport">
<transport clientCredentialType = "None" proxyCredentialType="None"/>
</security>
</binding>
</webHttpBinding>

I tried the above solutions, installing WCF Services, ensuring that there were proper permissions in the API directory and several other things.
While some of those were issues there was one issue for me that isn't mentioned above.
If Request Filtering is enabled for the entire server or the given site, make sure that .svc is a trusted file name extension, otherwise it will be blocked. Go to IIS > Request Filtering. Click on Edit Feature Settings. Check to see if "allow unlisted file extensions" is checked. If so, make sure that there is an entry in the list for .svc. Otherwise IIS will block the file from being served.

Related

Could not find default endpoint element that references contract

I have a ASP .NET MVC app that I want to be able to connect to SOAP API.
I have created a wrapper project were I have my common methods that are working with the API. I have created this wrapper because the file generated by tool is so huge the project build would take ages.
From api doc site:
The tool then generates a single file named EconomicWebService.cs with the proxy code. This file can then be included directly in a project (this can slow down your Visual Studio as it is a rather big file) or built into a dll that can be referenced from your project)
I have referenced this wrapper as dll in my class library (middle layer) that is referenced into my MVC application.
Sadly it is not working, and I am getting this error:
Could not find default endpoint element that references contract 'S2s.Economic.WebService.EconomicWebServiceSoap' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.
Webconfig
<system.web>
.....
</system.web>
<runtime>
...
</runtime>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="EconomicWebServiceSoap">
<security mode="Transport" />
</binding>
<binding name="EconomicWebServiceSoap1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://api.e-conomic.com/secure/api1/economicwebservice.asmx"
binding="basicHttpBinding" bindingConfiguration="EconomicWebServiceSoap"
contract="PTS.S2s.Economic.WebService.EconomicWebServiceSoap"
name="EconomicWebServiceSoap" />
</client>
</system.serviceModel>
</configuration>
I have managed to find a workarround with manual endpoint setup in the code.
EndpointAddress endpoint = new EndpointAddress( "https://api.e-conomic.com/secure/api1/economicwebservice.asmx" );

Visual Studio - Adding two web references

I'm using VS2012 and have successfully added a service reference to a web service, lets call it Web Service A. I can connect and interact with that webservice, it all works ok.
There's another version of the webservice (Web Service B) that I need to connect to, it's essentially the same but one is used for live and the other for testing. The URLs are different so I thought I could add a second reference without an issue.
However, when I do add Web Service B everything appears to work fine (web.config is modified etc.) but all my existing code that interacts with Web service A breaks, visual studio acts like it doesn't know what classes I'm trying to instantiate.
Can I have two very similar web references (different URLs) that I can easily switch between by changing the code? I would have thought I could but maybe not?
When you add a Service or Web Reference, along with all the code that VS create, the important bit is this thing in the web.config (or App.Config):
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="TempConvertSoap" />
</basicHttpBinding>
<customBinding>
<binding name="TempConvertSoap12">
<textMessageEncoding messageVersion="Soap12" />
<httpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://www.w3schools.com/webservices/tempconvert.asmx"
binding="basicHttpBinding" bindingConfiguration="TempConvertSoap"
contract="ServiceReferenceA.TempConvertSoap" name="TempConvertSoap" />
<endpoint address="http://www.w3schools.com/webservices/tempconvert.asmx"
binding="customBinding" bindingConfiguration="TempConvertSoap12"
contract="ServiceReferenceA.TempConvertSoap" name="TempConvertSoap12" />
</client>
</system.serviceModel>
The example is from the Temperature Convesion service in w3schools.
In your scenario, you only need to add a single web reference and then, to connect to the other one, change this section, in particular the endpoint -> address attribute; as long as the webservice are IDENTICAL, it will work without problems.
As a bonus, being part of the web.config or app.config, you could use config tranforms to replace this with the proper address when building your Release.
If one is for live and another for test, I would add web.config transformations and then run your code under a 'test' configuration.
More info on web.config transforms here:
http://msdn.microsoft.com/en-us/library/dd465326(v=vs.110).aspx

WCF-Ajax enabled Web service. Service is not defined when deployed

I have an Ajax enabled web service within my website.
The service sits in a WebServices folder within the Root of the website, the folder also contains it's own Web.config (as the bindings for the Ajax web.config conflict the configs on another layer of my site).
I have added the web service to the scriptmanager in my master page and used JQuery to call the service within a page.
This is all working fine running locally in IIS 7 (Vista).
However when I publish the Website (locally to file system as we have to copy the files manually to our test environment) then copy the files to our test environment (running IIs 7.5 on Windows Server 2008 R2), the web service doesn't work and I get a Javascript error saying "Service is not defined".
If I browse to the service then I can view the wsdl with no problems however if I try and view service.svc/js (the same url the page is looking for) then I recieve a 404 not found error.
I've done a lot of Googling on the subject and while there are loads of suggested Web.config fixes, I have tried multiple combinations and so far nothing seems to be working.
The service it's self is very basic.
[ServiceContract(Namespace = "MyService")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class MyService
{
[OperationContract]
public JSONObject DoWork()
{
...Do some logic
return JSONObject;
}
}
JSONObject is a class I created that just holds some properties to be sent to the page. As I said this is all working hosted in IIS locally.
---EDIT
Here's the Web.Config that sits in the same directory as the web service:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="default" />
</webHttpBinding>
</bindings>
<services>
<service name="MyWebsite.WebServices.MyService"
behaviorConfiguration="MyWebsite.WebServices.MyServiceBehavior" >
<endpoint address="" behaviorConfiguration="MyWebsite.WebServices.MyServiceAspNetAjaxBehavior" binding="webHttpBinding" contract="MyWebsite.WebServices.MyService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyWebsite.WebServices.MyServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="MyWebsite.WebServices.MyServiceAspNetAjaxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I also have the following section in my root web.config:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
I’ve managed to track down the issue.
It comes down to patching. The following article mentions an update to fix the issue in IIS 7.5 and Windows 7 but the patch is also applicable to Vista and Windows Server 2008.
http://support.microsoft.com/kb/2520479
There is a second option to fix the issue which involves reordering the Handlers in the IIS applicationHost.config file on the machine affected, I have tried this and it does in fact solve the issue.
The second option is described in the article above.

Setting up NTLM Authentication with WCF to Sharepoint Web Services

I have been having a lot of difficulty setting up my WCF service to talk to Sharepoint Web services, specifically I am trying to use the Lists.asmx and Copy.asmx services.
I got it working using an http link to sharepoint for development, but now we need to switch to an HTTPS link. I got the web reference setup and updated for this link, but when it tries to call a service (ex: GetListItems) it errors out with the following error:
The request failed with HTTP status 401: Unauthorized.
I then tried to see what type of authentication our Sharepoint Server uses, which turns out to be NTLM. I then tried to configure out web.config file for this. Here is the entire web.config file:
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="InventoryService.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
</sectionGroup>
</configSections>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true" targetFramework="4.0">
</compilation>
<!--
The <authentication> section enables configuration
of the security authentication mode used by
ASP.NET to identify an incoming user.
-->
<authentication mode="Windows"/>
<!--
The <customErrors> section enables configuration
of what to do if/when an unhandled error occurs
during the execution of a request. Specifically,
it enables developers to configure html error pages
to be displayed in place of a error stack trace.
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
-->
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID"/></system.web>
<!--
The system.webServer section is required for running ASP.NET AJAX under Internet
Information Services 7.0. It is not necessary for previous version of IIS.
-->
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="NewBinding0">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" proxyCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="InventoryService.Service1Behavior"
name="InventoryService.InventoryService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="NewBinding0"
contract="InventoryService.IInventoryService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="InventoryService.Service1Behavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- 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 includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<applicationSettings>
<InventoryService.Properties.Settings>
<setting name="InventoryService_WSCopy_Copy" serializeAs="String">
<value>http://site/_vti_bin/Copy.asmx</value>
</setting>
<setting name="InventoryService_SharepointLists_Lists" serializeAs="String">
<value>https://site/_vti_bin/Lists.asmx</value>
</setting>
</InventoryService.Properties.Settings>
</applicationSettings>
</configuration>
If anyone has a clue if I setup this config file correctly for NTLM, that would be really helpful.
If this is setup correctly, then I guess I will move on to the next question about if I setup the credentials correctly:
inventoryList = new SharepointLists.Lists();
inventoryList.Url = "https://fullsiteurl/_vti_bin/Lists.asmx";
inventoryList.Credentials = new System.Net.NetworkCredential("user", "pass", "domain");
If someone could go over this, that would also be very helpful.
Again I know that the config file is pretty long and I highly appreciate it if you go through it let me know if I setup NTLM authentication correctly.
If all this checks out ok, then I have no idea where to start on getting the HTTPS link with sharepoint working (The existing HTTP link to sharepoint is still accessible for the time being, until I can get the service working with the HTTPS link).
Make sure the specified user has access to the ASMX with the browser.
Make sure the user has (at minimum) Read permission to the target library.
Also, make sure the user has the Use Remote Interfaces premission (WSS 3.0: Site settings, Advanced permissions, Settings - Permission Levels, choose corresponding permission level).
Also, if you are using MOSS 2007, SOAP access can be disabled in the central admin.
I don't have Sharepoint 2010 available at the moment so I cannot check, but I expect the settings to be corresponding.
Edit:
If everything works great under normal HTTP, I would look at the way that HTTPS was enabled.
Take a look at this site "How to enable SSL on a SharePoint 2010 web application", especially the second part (about 1/3rd of the page, regarding adding an alternate access mapping).
Hope this helps.
You are getting this error because you have not specifed that the mexHttpBinding also use use the 'NewBinding0' binding configuration. What is happening is that prior to your actual WCF service call, WCF is attempting to obtain some information about the service. This request will fail if it does not transport any client credential information to the service since it is secured and you will recieve the 401 response from the server (Not Authorized). Make sure that your mexHttpBinding also sends up the NTLM credentials.
You could alternatively remove the mexHttpBinding

Changing WCF Service reference URL based on environment

I have a web application that uses a number of WCF Services. I deploy my web application in various environments (dev, UAT, production etc). The URL of each WCF Service is different for each environment. I am using .NET 3.5 andbasicHttpBindings
The web application uses a framework to support machine-specific settings in my web.config file. When instantiating an instance of a WCF Service client I call a function that creates the instance of the WCF Service client using the constructor overload that takes the arguments:
System.ServiceModel.Channels.Binding binding,
System.ServiceModel.EndpointAddress remoteAddress
In essence the <system.serviceModel><bindings><basicHttpBinding><binding> configuration in web.config has been replicated in C# code.
This approach works well.
However, I now have to enhance this approach to work with a WCF service that uses an X509 certificate. This means that I have to replicate the following additional settings in web.config in C# code:
<!-- inside the binding section -->
<security mode="Message">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
<behaviors>
<endpointBehaviors>
<behavior name="MyServiceBehaviour">
<clientCredentials>
<clientCertificate storeLocation="LocalMachine" storeName="My"
x509FindType="FindByThumbprint" findValue="1234abcd" />
<serviceCertificate>
<defaultCertificate storeLocation="LocalMachine" storeName="My"
x509FindType="FindByThumbprint" findValue="5678efgh" />
<authentication trustedStoreLocation="LocalMachine"
certificateValidationMode="None" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
I am having some difficulty figuring out how to code this configuration in C#.
Two questions
Can anyone recommend a better approach for managing WCF Service reference URLs across multiple environments?
Alternatively, any suggestions on how to replicate the above web.config section in C# will be welcomed
One possible approach would be to "externalize" certain parts of your <system.serviceModel> configuration into external files, one per environment.
E.g. we have "bindings.dev.config" and "bindings.test.config", which we then reference in our main web.config like this:
<system.serviceModel>
<bindings configSource="bindings.dev.config" />
</system.serviceModel>
That way, all you need to change from DEV to PROD is this one line of config XML.
Basically, in .NET 2.0 config, any configuration element can be "externalized". You cannot however externalize configGroups (such as "system.serviceModel") directly - you have to be on the "configuration element" level.
Marc
EDIT: OK, so NO config edit changes to switch between environments.....
In that case, you probably have to dream up a naming scheme, e.g. name your bindings, behaviors and endpoints in such a way, that you can distinguish them at runtime.
Something like:
<bindings>
<binding name="Default_DEV">
.....
</binding>
<binding name="Default_PROD">
.....
</binding>
</bindings>
that way, you could build up the name of the element you want (e.g. binding "Default_PROD") from your code and the environment you're running in, and then grab the according config from the config file which contains all the config settings for all environments.
The following code replicates the configuration in my original question:
myClient.ClientCredentials.ClientCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindByThumbprint,
"1234abcd");
myClient.ClientCredentials.ServiceCertificate.SetDefaultCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindByThumbprint,
"5678efgh");
myClient.ClientCredentials.ServiceCertificate.Authentication.TrustedStoreLocation = StoreLocation.LocalMachine;
myClient.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
In the production code the two thumbprint values are stored in appSettings in the web.config file.
We don't use web.config files at all, we specify everything programmatically and load all configuration from a centralized database.

Categories