IIS: WCF service with https and GET -> HTTP 400 Error - c#

I am trying to create a WCF Service for https binding. The service was working with http before. I changed the binding (with certificate) and now I configure the web.config - but I always get error code "400 - Bad Request".
The web service is called with:
https://servername:444/FolderService.svc/FolderExists/1234
https://servername:444/FolderService.svc/Test
This is my service interface:
[ServiceContract]
public interface IFolderService
{
[OperationContract]
[WebGet(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "/FolderExists/{accountnumber}")]
bool FolderExists(string accountnumber);
[OperationContract]
[WebGet(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "/Test")]
string Test();
}
And this is my web.config:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="myService.FolderService">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="myService.IFolderService"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpsGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I tried so many different configuration without success. Does anyone have an idea (or a working example)?
Thanks in advance!

You are trying to access your methods in a RESTful manner via a URL. However, what you have wrong in your web.config is that you are using BasicHttpBinding which is for SOAP web services and not RESTful web services.
WebGet and WebInvoke are the necessary attributes to add to your operations as you have already done.
However, the correct binding for the endpoint is WebHttpBinding and the behavior you need to apply to the endpoint is the WebHttpBehavior.
Sample Abbreviated Configuration:
<service>
<endpoint behaviorConfiguration="webBehavior"
binding="webHttpBinding"
contract="myService.IFolderService"
bindingConfiguration="secureHttpBinding" />
</service>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>

Related

Secure a Wcf json web service without Window authentication

I'd like to secure a web service. I have to avoid window authentication because the hosting company will cause me some problems
How is it possible ? The best option for me if to configure the user / password (or just the password. it would be enought for that web service) into the web.config file.
I imagine I can add a special parameter but it seems ugly
My configuration is :
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>
<services>
<service name="ct.WebServices.WsCT">
<endpoint address="" behaviorConfiguration="ct.WebServices.Service1AspNetAjaxBehavior" binding="webHttpBinding" contract="ct.WebServices.WsCT"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="ct.WebServices.Service1AspNetAjaxBehavior">
<webHttp faultExceptionEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding>
<readerQuotas maxStringContentLength="1000000"/>
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
The web service is used by android device
The code is :
namespace ct.WebServices
{
[ServiceContract(Namespace = "")]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class WsCT
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = "/modif")]
public IList<Ws.Modification> GetModifs() { return null; }
}
}

Calling a service method with serialised objects

I have a WCF service with a post method. This takes a single entity.
[OperationContract, FaultContract(typeof(ServiceError))]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped]
Entity SaveEntity(Entity entity);
I have a file with an xml serialised representation of these objects. I need to be able to post this xml to the service directly without deserialising it at the client side (architecture issues, we don't have the references).
Is it possible to do this by constructing a request with something like the HttpClient?
var client = new HttpClient(HttpClient:);
client.PostAsync("http://localhost:55217/MyService.svc/SaveEntity", new HttpContent
{
Headers = new System.Net.Http.Headers.HttpContentHeaders
{
// can I put my serialised xml here?
}
}
Here's the config:
<system.serviceModel>
<services>
<service behaviorConfiguration="Default" name="MyService">
<endpoint address="" binding="webHttpBinding" contract="IMyService" behaviorConfiguration="webBehavior" bindingConfiguration="fullMessageSize" />
<endpoint address="ws" binding="wsHttpBinding" contract="IMyService" bindingConfiguration="fullMessageSize" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="fullMessageSize" maxReceivedMessageSize="104857600" />
</webHttpBinding>
<wsHttpBinding>
<binding name="fullMessageSize" maxReceivedMessageSize="104857600" />
</wsHttpBinding>
</bindings>
</system.serviceModel>
Why not create an intermediate service?
[OperationContract, FaultContract(typeof(ServiceError))]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped]
Entity SaveEntity(XElement entitySerialized)
{
var entity = Deserialize(entitySerialized);
var realService = new MyServiceClient();
return realService.SaveEntity(entity);
}
The intermediate service can have the references required for serialization.
You could consider creating a service-to-service endpoint for use between the intermediate service and the real service. That endpoint could use one of the faster bindings like netTcpBinding, that you might not want to use with your clients.

WCF REST method and non-REST method

I have a WCF Service that I need one of my methods accept HTTP POST request and the other one must be non-REST. Consider the code below:
[OperationContract]
long[] Send(string body, List<string> phoneNumbers);
[OperationContract]
[WebInvoke(Method="POST", BodyStyle = WebMessageBodyStyle.WrappedRequest)]
long[] SendByPost(string body, string phoneNumbers);
But I don't know why the error below is raised:
Operation 'Send' of contract 'IService' specifies multiple request
body parameters to be serialized without any wrapper elements. At most
one body parameter can be serialized without wrapper elements. Either
remove the extra body parameters or set the BodyStyle property on the
WebGetAttribute/WebInvokeAttribute to Wrapped.
How can I solve this issue?
First of all, to send multiple parameters in a url, you can use GET method instead of POST.
[OperationContract]
[WebInvoke(Method="POST", BodyStyle = WebMessageBodyStyle.WrappedRequest)]
long[] SendByGet(string body, string phoneNumbers);
Either change it into this:
[OperationContract]
[WebGet(UriTemplate = "/body={body}?phoneNumbers={phoneNumbers}"]
long[] SendByPost(string body, string phoneNumbers);
Or if you want to use POST.
[OperationContract]
[WebInvoke(Method="POST", BodyStyle = WebMessageBodyStyle.WrappedRequest,
UriTemplate = "MyUrl", RequestFormat = WebMessageFormat.Json
, ResponseFormat = WebMessageFormat.Json)]
long[] SendByPost(Info info);
And here is your Info class:
[DataContract]
Class Info
{
[DataMember]
public string Body {get; set;}
[DataMember]
public string PhoneNumbers{get; set;}
}
You have two methods and you want to expose one of them to REST and the other to another binding, right?
For this, you need to create more than one interface for your wcf service ([ServiceContract]).
Take, for example, this Web.config:
<system.serviceModel>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment minFreeMemoryPercentageToActivateService="1" aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true" />
<bindings>
<webHttpBinding>
<binding name="RestBinding" maxBufferSize="1048576" maxReceivedMessageSize="1048576" maxBufferPoolSize="1048576">
<readerQuotas maxDepth="2147483647" maxStringContentLength="1048576" maxArrayLength="1048576" maxBytesPerRead="1048576" maxNameTableCharCount="1048576"/>
</binding>
</webHttpBinding>
<basicHttpBinding>
<binding name="SoapBinding" maxReceivedMessageSize="20000000" messageEncoding="Text" maxBufferSize="20000000" maxBufferPoolSize="20000000" closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00"/>
</basicHttpBinding>
<wsHttpBinding>
<binding name="SecureHttpBinding" messageEncoding="Mtom" closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00" maxBufferPoolSize="20000000" maxReceivedMessageSize="20000000">
<readerQuotas maxDepth="32" maxStringContentLength="20000000" maxArrayLength="20000000"/>
<security mode="None">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</wsHttpBinding>
<customBinding>
<binding name="RawReceiveCapable">
<webMessageEncoding webContentTypeMapperType="WCFService.RawContentTypeMapper, WCFService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<httpTransport manualAddressing="true" maxReceivedMessageSize="524288000" transferMode="Buffered" /><!--transferMode="Streamed"-->
</binding>
</customBinding>
</bindings>
<services>
<service name="WCFService.Service" behaviorConfiguration="WCFService.ServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:5000"/>
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="SOAP" binding="basicHttpBinding" bindingConfiguration="SoapBinding" contract="WCFService.IService1" name="SOAP_XML"/>
<endpoint address="" binding="webHttpBinding" bindingConfiguration="RestBinding" contract="WCFService.IService2" behaviorConfiguration="EndpointJSONBehavior"/>
<endpoint address="MTOM" binding="wsHttpBinding" bindingConfiguration="SecureHttpBinding" contract="WCFService.IService1" name="SOAP_MTOM"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCFService.ServiceBehavior">
<!-- To avoid disclosing metadata information, set the values below to false 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 httpHelpPageEnabled="true" includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="EndpointXMLBehavior">
<webHttp defaultBodyStyle="Wrapped" defaultOutgoingResponseFormat="Xml"/>
</behavior>
<behavior name="EndpointJSONBehavior">
<webHttp defaultBodyStyle="Wrapped" defaultOutgoingResponseFormat="Json"/>
</behavior>
<behavior name="EndpointRawBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
You can see here two ServiceContracts: IService1 and IService2.
To run methods defined in IService1 you need to use soap encapsulation.
Methods exposed by IService2 can be called RESTfully and easily without soap
encapsulation.
For your SendByPost() method to be RESTful you need to put it in IService2 and put the other method in a different ServiceContract (like IService1).

WCF Rest service not displaying methods on test client

I am writing a WCF Rest service to return a JSON message. I've been trying to use an example I found on the internet as a guide. Any time I fire up the test client, none of my methods are displayed. Navigating to the Uri while the service is running yields me a "page cannot be displayed" page. Not exactly too sure where to go from here. Any help would be appreciated.
Web Config:
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingWithJasonP"
crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
</bindings>
<services>
<service name="WcfRestLicense.LicenseService"
behaviorConfiguration="WebServiceBehavior">
<endpoint behaviorConfiguration="jsonBehavior"
binding="webHttpBinding"
bindingConfiguration="webHttpBindingWithJasonP"
contract="WcfRestLicense.ILicenseService" />
<endpoint contract="IMetadataExchange"
binding="mexHttpBinding"
address="mex" />
</service>
</services>
<!--<client />-->
<behaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="WebServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add
scheme="http"
binding="webHttpBinding"
bindingConfiguration="webHttpBindingWithJasonP" />
</protocolMapping>
<serviceHostingEnvironment
aspNetCompatibilityEnabled="false"
multipleSiteBindingsEnabled="true" />
Service method:
public IQueryable<customer> GetCustomerById(string customerId)
{
int custId = Convert.ToInt32(customerId);
return _context.customers.Where(c => c.cust_id == custId);
}
Interface:
[ServiceContract]
public interface ILicenseService
{
[OperationContract]
[WebGet(UriTemplate = "customer/{customerId}/",
RequestFormat= WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare)]
IQueryable<customer> GetCustomerById(string customerId);
}
If by test client you're talking about the WcfTestClient, then it won't work with RESTful services; it's designed to work with SOAP based web services. You can test RESTful services in a browser by passing in the appropriate URI, something like this:
http://<location of your service>/service/1
Where the number 1 would be a customer ID. This is a rough example as a) I don't do a lot with RESTful services and b) I'm not sure what your actual address is.
As far as getting a 404 when you go to the Uri, it sounds like you're looking for the help page. You can enable that in your config file:
<bindings>
<webHttpBinding>
<binding name="webHttpBindingWithJasonP"
crossDomainScriptAccessEnabled="true"
enableHelp="true" />
</webHttpBinding>
</bindings>

Make a WCF Service Accept JSON Data from jQuery.AJAX()

I have been searching around for hours and trying different things to get this to work. I have tried so many articles on stackoverflow and either I am too stupid to get things working or I have some unique and odd configuration that is preventing me from experiencing joy.
I create the WCF service outlined by this tutorial:
http://www.codeproject.com/Articles/97204/Implementing-a-Basic-Hello-World-WCF-Service
It is super basic and has one method and all I want it to do is allow me to consume it with jQuery.AJAX() using json.
I have it hosted in IIS and it works. I can access the WSDL without issues.
I try to consume it with the following code:
$.ajax({
dataType: 'json',
type: 'POST',
contentType: "application/json",
url: "//localhost:546/HelloWorldService.svc/GetMessage",
data: {
name: "Joe"
}
}).done(function(msg){
console.log(msg);
$("#result").append(msg);
});
I always get errors. Based on what I have tried I get 500 errors, 402 errors, errors about incorrect content... All the errors.
I have tried implementing solutions from the following articles. They range from having me change the web.config endpoints (I know I HAVE to change them but nothing I have tried so far works in terms of adding a JSON endpoint) to adding things like
[WebInvoke(Method = "POST", UriTemplate = "json/PostSalesOrderData", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
to the interface.
Here are some of the articles I have looked at and tried to smash into my solution to get it working without much success.
Javascript JSON and WCF webservice on Phonegap Android
HTTP/1.1 415 Cannot process the message because the content type 'application/json; charset=utf-8' was not the expected type 'text/xml; charset=utf-8'
WCF Services with JSON, JSONP and SOAP End Points
Two endpoint (soap ,json) and one service method
WCF REST Service not accepting JSON in .Net 4
I also went through this tutorial and tried to use what he had to say to get my solution working. Still nothing!
http://www.primordialcode.com/blog/post/passing-json-serialized-objects-wcf-service-jquery
This is how my interface looks
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract]
[WebInvoke(UriTemplate = "GetMessage", Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
String GetMessage(String name);
}
Can anyone help me experience joy?
Thanks in advance for even looking at my question. If you need more information or I have not provided enough let me know so I can help you help me!
I must be missing something stupid... I know it is not this hard.
EDIT:
Working Web.Config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="false" targetFramework="4.0" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="WebHTTPEndpointBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="MyWebServiceBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/>
</webHttpBinding>
</bindings>
<services>
<service name="MyWCFServices.HelloWorldService"
behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address="" binding="webHttpBinding" bindingConfiguration="MyWebServiceBinding" behaviorConfiguration="WebHTTPEndpointBehavior"
contract="MyWCFServices.IHelloWorldService"/>
<endpoint contract="IMetadataExchange"
binding="mexHttpBinding" address="mex"/>
</service>
</services>
</system.serviceModel>
</configuration>
change this line
data: {
name: "Joe"
}
to
data: JSON.stringify({name: 'Joe'});
EDIT:
Do this to your service. Add WebHttp binding in the config.
<behaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
Hope you know where to add this. If not let me know and I will try to provide some inputs.
EDIT:
Following up on my comment,
<behavior name="myBehaviorName">
<webHttp />
</behavior>
<service name="MyWCFServices.HelloWorldService"
behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address="" binding="webHttpBinding"
contract="MyWCFServices.IHelloWorldService" behaviorConfiguration="myBehaviorName"/>
<endpoint contract="IMetadataExchange"
binding="mexHttpBinding" address="mex"/>
</service>
I'm coming in late, but you still have some issues you'll need to resolve to get it to work. You need to change the binding for your endpoint to support the HTTP operations.
<bindings>
<webHttpBinding>
<binding name="MyWebServiceBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"/>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="WebHTTPEndpointBehavior">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="MyWCFServices.HelloWorldService"
behaviorConfiguration="MyServiceTypeBehaviors">
<endpoint address="" binding="webHttpBinding" bindingConfiguration="MyWebServiceBinding" behaviorConfiguration="WebHTTPEndpointBehavior"
contract="MyWCFServices.IHelloWorldService"/>
<endpoint contract="IMetadataExchange"
binding="mexHttpBinding" address="mex"/>
</service>
</services>
The maxBufferSize and maxReceivedMessageSize is optional.
EDIT: Oops, forgot to add your behaviorConfiguration in.

Categories