Self Hosted WCF Service throws Error Message "405 Method not allowed" - c#

I have a Self Hosted WCF Service, which looks like this:
[ServiceContract]
public interface IService {
[OperationContract]
[WebGet]
List<Data> GetData();
//...and much more Methods
}
My App.config looks like this:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<behaviors>
<serviceBehaviors>
<behavior name="MetaInformation">
<serviceMetadata httpGetEnabled="true"
httpGetUrl="http://localhost:8500/MetaInfo"
httpsGetBinding="" />
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="EndpointBehavior">
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MetaInformation" name="Library.WcfService.ServiceModel">
<endpoint address="http://localhost:8500/Service"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBindingSettings"
contract="Library.WcfService.IService"
bindingName="BasicHttpBindingSettings"
behaviorConfiguration="EndpointBehavior"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBindingSettings"
closeTimeout="00:50:00"
openTimeout="00:50:00"
sendTimeout="00:50:00"
maxBufferSize="524288"
transferMode="Streamed"
maxReceivedMessageSize="2147483647"
maxBufferPoolSize="2147483647"
messageEncoding="Text">
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
<system.web>
<httpRuntime maxRequestLength="102400"/>
</system.web>
When I run this Server and the Client Applications on my local machine, it's working fine.
But when i try to run the Server Application on another PC, I cannot add a Service Reference at the Client because I get this:
405 Method not allowed Metadata contains a reference that can not be resolved : "http://192.168.178.54:8500/MetaInfo". It was not a
listening to http://192.168.178.54:8500/MetaInfo endpoint present who
could accept the message. This is often caused by an incorrect
address or SOAP action
I tried almost everything I found at the internet but nothing worked.
Switching to IIS or using an other Protocol should be a plan B, i want to keep it self hosted with http.
Please can somebody help me I'm desperate with this Problem.

your operation contract is decorated with [WebGet] attribute, which means you're trying to expose your service as a REST. But your service is using basicHttpBinding as means of building the communication channel which isn't supported because the content type for this binding is soap+xml. You'll need to use WebHttpBinding in this case which is the only binding that supports restful implementation of WCF Services and supports both Xml and Json data types.

Related

Set WCF Service endpoints at server side web config for https

I am stuck in very odd situation and do not know how to solve this issue.
I have very simple WCF service working very fine with http BUT now I want to move it to https.
The issue is Server where it needs to be hosted. Server IIS have an alias name "server-test.local" (not "localhost") with http. Its is accessible locally with this alias name. And its mapped to a Domain name with https (example, https://rmt.XXXXXXX.com).
When I deploy my WCF to that server and check WSDL file, it has mapping of the local alias name instead of public domain name.
it is showing http://server-test.local/WCFService/Service.svc (WRONG)
I want mapping like https://rmt.XXXXXXXX.com/WCFService/Service.svc (CORRECT)
Service web.config
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<pages controlRenderingCompatibilityVersion="4.0"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 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="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer> <modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
When I add service reference to app. It adds following endpoint which is not conrrect.
Client App.config (endpoint)
<endpoint address="http://server-test.local/WCFService/Service.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IProcessing"
contract="WCFService.IService" name="BasicHttpBinding_IProcessing" />
I am able to access the url and WSDL file through browser but not able to consume any Service methods. I am getting error "There is no endpoint which can accept the message."
I think I am missing something obvious here. Please suggest me changes.
You can try to change some simple steps in the web.config file, you can refer to this post for details.
1.Enable transport level security in the web.config file of the service:
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
2.Use the bindingConfiguration tag to specify the binding name and the behaviorConfiguration tag to configure the behavior, and then specify the address of the managed service. The code is as follows:
<service name="***" behaviorConfiguration="***">
<endpoint address= https://rmt.XXXXXXXX.com/WCFService/Service.svc
binding="basicHttpBinding"
bindingConfiguration="???"
contract="WCFService.IService"/>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>

Unable to access the WCF Service metadata when custom validator is introduced

I have a web service(using wsHttpBinding and SSL) developed in Visual Studio 2017. Whenever i introduce the following line, the Web Service just fails and it goes into the "faulted" state.
<authentication certificateValidationMode="Custom" customCertificateValidatorType="SampleProject.SampleService.AuthenticationCertificateValidator, SampleProject.SampleService"/>
The error message when attempting to "Add Service Reference" on the client side i recieve the following error:
There was an error downloading 'https://localhost/SampleService/service'.
The request failed with HTTP status 404: Not Found.
Metadata contains a reference that cannot be resolved:
'https://localhost/SampleService/service'.
There was no endpoint listening at https://localhost/SampleService/service
that could accept the message. This is often caused by an incorrect address
or SOAP action. See InnerException, if present, for more details.
The remote server returned an error: (404) Not Found.
If the service is defined in the current solution, try building the
solution and adding the service reference again.
Here is the code relating to the validator.
public class AuthenticationCertificateValidator : X509CertificateValidator
{
string allowedIssuerName;
public AuthenticationCertificateValidator(string allowedIssuerName)
{
if (allowedIssuerName == null)
{
throw new ArgumentNullException("allowedIssuerName");
}
this.allowedIssuerName = allowedIssuerName;
}
public override void Validate(X509Certificate2 certificate)
{
// Check that there is a certificate.
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
// Check that the certificate issuer matches the configured issuer.
if (allowedIssuerName != certificate.IssuerName.Name)
{
throw new SecurityTokenValidationException
("Certificate was not issued by a trusted issuer");
}
}
}
However the service works fine when i only have the "ChainTrust" line enabled as shown below:
<!--certificateValidationMode="Custom"
customCertificateValidatorType
="SampleProject.SampleService.AuthenticationCertificateValidator,
SampleProject.SampleService"/>-->
<authentication certificateValidationMode="ChainTrust" />
Ideally i want my service and client to use ChainTrust and also use the custom validator class if that's possible?
Therefore what am i doing wrong regarding configuration? Am i missing something from the config file?
Here is the full Service config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="SampleProject.SampleService.SampleService"
behaviorConfiguration="SampleService_Behavior">
<endpoint
address="https://localhost/SampleService/service"
binding="wsHttpBinding"
bindingConfiguration="SampleService_Binding"
contract="SampleProject.SampleService.ISampleService" />
<endpoint
address="https://localhost/SampleService/service/mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="SampleService_Binding"
maxReceivedMessageSize="2147483647"
maxBufferPoolSize="2147483647" >
<readerQuotas
maxDepth="2147483647"
maxStringContentLength="2147483646"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SampleService_Behavior">
<!--Service metadata is needed for when you have an mex endpoint exposed-->
<serviceMetadata httpsGetEnabled="true" httpsGetUrl="https://localhost/SampleService/service/mex"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
<!--The serviceCredentials behavior defines a service certificate
which is used by the service to authenticate itself to its
clients and to provide message protection. -->
<serviceCredentials>
<serviceCertificate
findValue="SampleServer"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
<clientCertificate>
<!--<authentication certificateValidationMode="ChainTrust" />-->
<authentication
certificateValidationMode="Custom"
customCertificateValidatorType
="SampleProject.SampleService.AuthenticationCertificateValidator,
SampleProject.SampleService"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehaviour">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
if someone could assist me that would be much appreciated.

EndpointNotFoundException on call to operation of running RESTful WCF service

I have a really strange problem with one of my WCF services. I'm pretty sure that most people who have experimented with WCF services have had an EndpointNotFoundException thrown when an endpoint had not been set up correctly in one of their configuration files. From the EndpointNotFoundException class page on MSDN:
The exception that is thrown when a remote endpoint could not be found or reached.
Further on, it continues:
The endpoint may not be found or reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
This does not reflect my situation. So it seems that receiving an EndpointNotFoundException when working with WCF is not unusual, but this Exception is not thrown when first trying to access the service... instead, it is thrown only when trying to call one of the operations of the service:
using (ExportConfirmationServiceClient client = new ExportConfirmationServiceClient(
"WebHttpBinding_IExportConfirmationService")) // <-- Exception is NOT thrown here
{
...
component releaseConfirmation = DeserializeTestXmlFile(filePath);
client.AddExportConfirmation("5051275066302", releaseConfirmation);
// Exception is thrown on call to service operation on line above
...
}
Interestingly, the Exception message also includes the name of the operation in the mentioned file path:
There was no endpoint listening at http://domain/Folder/ServiceName.svc/OperationName that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
The inner Exception has the following message:
The remote server returned an error: (404) Not Found.
This is particularly confusing for me as I can successfully browse to the service URL and see the default You have created a service page:
Also, if I navigate to the path in the Exception message, I see an Endpoint not found message on the page:
However, if I navigate to any operation page of one of my other, working WCF services, I get a standard 400 Bad Request error from the browser, even though the operation works fine. So it would seem to me as if this original EndpointNotFoundException could be a red herring... I'm really not sure though, as I've not spent much time working with WCF.
I'll show my web.config (server side) here just in case anyone needs to see it:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="Midas.WebConfirmations.ExportConfirmationServiceBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webHttp">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
<services>
<service name="Midas.WebConfirmations.ExportConfirmationService" behaviorConfiguration="Midas.WebConfirmations.ExportConfirmationServiceBehaviour">
<endpoint address="" binding="webHttpBinding" contract="Midas.WebConfirmations.IExportConfirmationService" behaviorConfiguration="webHttp" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
This is the client App.config (bear in mind that this references two WCF services):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IDataService" 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="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
<webHttpBinding>
<binding name="WebHttpBinding_IExportConfirmationService" allowCookies="true" maxReceivedMessageSize="20000000" maxBufferSize="20000000" maxBufferPoolSize="20000000">
<readerQuotas maxDepth="32" maxArrayLength="200000000" maxStringContentLength="200000000"/>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Midas.WebConfirmations.ExportConfirmationServiceBehaviour">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webEndpointBehavior">
<webHttp defaultBodyStyle="Wrapped" defaultOutgoingResponseFormat="Xml" helpEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://devbucket.ministryofsound.mos.local/MidasWebServices/DataService.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IDataService" contract="Midas.WebServiceClients.IDataService" name="BasicHttpBinding_IDataService" />
<endpoint address="http://devbucket.ministryofsound.mos.local/MidasWebConfirmations/ExportConfirmationService.svc" binding="webHttpBinding" bindingConfiguration="WebHttpBinding_IExportConfirmationService" behaviorConfiguration="webEndpointBehavior" contract="IExportConfirmationService" name="WebHttpBinding_IExportConfirmationService" />
</client>
</system.serviceModel>
</configuration>
So if any of the great minds that frequent Stack Overflow could shed some light on this problem for me, I'd greatly appreciate it.
UPDATE >>>
In response to the first few comments, I suspected that the problem could be caused by an Exception being thrown from the server side code, so I simplified the operation code dramatically... now all it does is this, but I still get the same error:
public void AddExportConfirmation(string upc, component ingestionFeedback)
{
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.OK;
}
Also, I did set up tracing, but it only worked on the client side, so it only told me what I already knew. I will have a look at the link you provided #BigDaddy, in case it shows how to set up tracing on the server side.
In response to Tewr, I generated the service client using svcutil.exe, but I also tried adding a service reference and letting Visual Studio create the reference for me... both methods resulted in the same error. Also, I have been updating the service references all day, as I've been making changes. The includeExceptionDetailInFaults="true" setting didn't make any difference, but I'll try adding a dummy operation to the service and try to view it in the browser.
UPDATE 2 >>>
Ok, so I added a simple getter method to the service and updated the references all round like #Tewr suggested. This has just made me more confused... the method:
[XmlSerializerFormat()]
[OperationContract]
[WebGet()]
string GetString();
The implementation just returns a string and I see that value when I access the service in a web browser:
However, I still get the same error from code, even when calling this same new operation... what does that mean?
UPDATE 3 >>>
After taking the advice from the comments, I set up a Service Trace on the service again... I still couldn't get the one working on the server, but on the client, it did output a trace file. In that file, I see an InvalidOperationException with the following message:
Envelope Version 'EnvelopeNone (http://schemas.microsoft.com/ws/2005/05/envelope/none)' does not support adding Message Headers.
I'm just researching this now, so if you know what this error is about, please let me know.
The problem with WCF is that it is so complex, the Exceptions cover so many different errors each and the Exception messages are so vague. From my limited experience, it seems like an error message will say one thing, but it will often be wholly, or partly irrelevant to your actual problem. So I basically kept fixing errors, which unlocked new Exceptions (and I still haven't come to the end of them yet!), but for the purpose of this question, there is an answer.
So it turned out that the original EndpointNotFoundException was actually thrown because there was an unhandled Exception in the AddExportConfirmation service method implementation. Once I had simplified the code (as in the first question update), that particular Exception went away and was replaced with the next one.

Configure WCF Client to consume a WCF Service using HTTP GET

I have a WCF Service which allows only HTTP GET requests:
[WebInvoke(Method="GET", ResponseFormat=WebMessageFormat.Json)]
public string GetAppData()
The service is exposed using webHttpBinding
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="AppSvcBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
I have my client whose config looks like
<system.serviceModel>
<client>
<endpoint address="http://localhost/AppService/Service.svc"
binding="webHttpBinding"
bindingConfiguration="webHttpBindingConfig"
contract="AppSvc.IService"
behaviorConfiguration="AppSvcBehavior"
name="AppSvcClient">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
</client>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="AppSvcBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
My client code is a simple
ServiceClient client = new ServiceClient("AppSvcClient");
String result = client.GetAppData();
On executing this code I get the error:
The remote server returned an unexpected response: (405) Method Not Allowed.
I checked with fiddler and found that my client is sending a POST message whereas the service expects a GET hence the error.
I wish to know how to configure the client so that is sends GET request to the service.
Use WebGet instead of WebInvoke
Edit
Start by changing your method to this:
[WebInvoke(Method="GET", ResponseFormat=WebMessageFormat.Json,UriTemplate = "/")]
public string GetAppData()
Make sure that webhttpbinding is specified on the server side.
This fixes it on the server side.
Take a backup of your client code.
On the client side delete the service reference. Make sure that all config is removed.
Then add the service reference again. Now it shoud be OK.
I had a similar problem where the generated proxy service interface on the client was missing the WebGet attribute on my methods.
I added the attribute manually and it resolved the problem.
So it seems like the best current solution is to extract the service interfaces into a separate assembly and then share this assembly between the server and its clients.
The automatic proxy generator seems to be buggy.

WCF custom certificate validation with BasicHttpBinding

I have a WCF application hosted on IIS 6 that needs to
Have 2-way SSL authentication
Validate client certificate content with some client host information
Validate client certificate is issued by the valid subCA.
I was able to do 1) successfully. I am trying to achieve 2) and 3) by following this - basically creating a class that inherits X509CertificateValidator and overriding the Validate method with my own validation implementation(step 2 and 3). I followed the MSDN instructions exactly however, it seem that the Validate method is not being called. I purposely throw a SecurityAccessDeniedException in the overidden Validate method and no exception is thrown when I tried to access the service via my browser. I can still access my website with any client certificate.
I also read this thread but it didn't really help. Any help would be greatly appreciated!
Here's my configuration:
<system.serviceModel>
<services>
<service behaviorConfiguration="SimpleServiceBehavior"
name="SampleNameSpace.SampleClass">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="NewBinding0"
contract="SampleNameSpace.ISampleClass" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SimpleServiceBehavior">
<serviceMetadata httpsGetEnabled="true" policyVersion="Default" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="Custom" customCertificateValidatorType="SampleNameSpace.MyX509CertificateValidator, SampleAssembly"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="NewBinding0">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
You can also try to override certificate validation with this ServerCertificateValidationCallback
We are using it with WCF HttpBinding in such way:
System.Net.ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, policyErrors) =>
{
var isValid = false;
// some checking logic
return isValid;
};

Categories