I am trying to convert my wcf services to a restful architecture. I started by converting a service called ConnectToApplication which checks user permission for authentification purposes in order to support POST requests. While trying Ajax to query the service using the following javascript code:
var formData={"userName":"admin", "password":"act;2016#","ApplicationName":"actior"}
$.ajax({
url : "http://localhost:10220/AdministrationService/ConnectToApplication",
type: "POST",
data: formData,
success: function (data) {
alert('success');
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("Status: " + textStatus); alert("Error: " + errorThrown);
}
});
I got an HTTP 400(Bad request) with the following error:
The server encountered an error processing the request. The exception
message is 'The incoming message has an unexpected message format
'Raw'. The expected message formats for the operation are 'Xml';
'Json'. This can be because a WebContentTypeMapper has not been
configured on the binding. See the documentation of
WebContentTypeMapper for more details.'. See server logs for more
details. The exception stack trace is:
at
System.ServiceModel.Dispatcher.DemultiplexingDispatchMessageFormatter.DeserializeRequest(Message
message, Object[] parameters) at
System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest(Message
message, Object[] parameters) at
System.ServiceModel.Dispatcher.CompositeDispatchFormatter.DeserializeRequest(Message
message, Object[] parameters) at
System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&
rpc) at
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc&
rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean
isOperationContextSet)
Here is my metadata for endpoint configuration:
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, UriTemplate = "ConnectToApplication/")]
UserPermessionDTO ConnectToApplication(string userName, string password, string ApplicationName);
Here is my WCF configuration:
<services>
<service name="ActiorServeurConsoleApp.AdministrationService" behaviorConfiguration="serviceBehavior">
<endpoint address="" binding="webHttpBinding" contract="ActiorServeurConsoleApp.IAdministrationService"
behaviorConfiguration="web">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:10220/AdministrationService/" />
</baseAddresses>
</host>
</service>
<services>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
You can try to set the content type for the post as
contentType: "application/json; charset=utf-8",
Also you can look at tools like fiddler and possibly postman to check you types and also test your service.
Related
I have a webservice in the same domain of my site. I have an ajax call to consult that webservice and works fine from IE but from Chrome and Firefox, I cannot make it work.
My ajax call is:
$.ajax({
type: 'POST',
async: false
data: xml,
url: url,
dataType: "xml",
success: function (data, textStatus, XmlHttpRequest) {
//On sucess action
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
//On error action
},
headers: {
"Content-Type": "text/xml; charset=utf-8",
"SOAPAction": soapAction,
"Content-Length": xml.length + 1
}
});
But from chrome and firefox I receive:
XMLHttpRequest cannot load https://mydomain:83/<webservice>/<webservice>.asmx. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://mydomain' is therefore not allowed access. The response had HTTP status code 500.
I add to the webconfig:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="https://mydomain"/>
<add name="Access-Control-Allow-Origin" value="http://mydomain"/>
<add name="Access-Control-Allow-Credentials" value="true"/>
</customHeaders>
</httpProtocol>
But no luck. Any idea what am I missing?
I gave up to soon. In my particular case, this do the trick for Chrome and Firefox
<add name="Access-Control-Allow-Origin" value="https://mydomain" />
<add name="Access-Control-Allow-Headers" value="Content-Type, SOAPAction" />
<add name="Access-Control-Allow-Methods" value="GET, POST" />
I want to pass JSON object to WCF service using AJAX from clientside.Everything works fine in Internet Explorer,but not in firefox.
In Firefox i'm getting a 405:Method not allowed
This is where i'm passing json data (from Client script) to a WCF service...
$(document).ready(function () {
var Author = '{ "Id": "A01", "Name": "Ravinder" }';
$.ajax({
type: "POST",
data: JSON.stringify(Author),
contentType: "application/json; charset=utf-8",
datatype: "json",
url: "http://localhost:53905/Service1.svc/AuthorPostByJson",
success: function (data) {
alert("success");
},
error: function (xmlhttprequest, textstatus, errorthrown) {
alert(" failed ");
console.log("error: " + errorthrown);
}
});//end of $.ajax
});
My WCF service is like ...
[OperationContract]
[WebInvoke(Method = "POST",
UriTemplate = "AuthorPostByJson",
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
List<Book> GetBooksByAuthor_JSON(Author author);
My web.config file ....
<system.serviceModel>
<services>
<service behaviorConfiguration="Platform.WebRestful.Service1Behavior"
name="Platform.WebRestful.Service1">
<endpoint address="" binding="basicHttpBinding" contract="Platform.WebRestful.IService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
<service behaviorConfiguration="Platform.WebRestful.BookServiceHostRestfulBehavior"
name="Platform.WebRestful.BookServiceHostRestful">
<endpoint address="" binding="webHttpBinding" contract="Platform.WebRestful.IBookServiceHostRestful">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Platform.WebRestful.Service1Behavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
<behavior name="Platform.WebRestful.BookServiceHostRestfulBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Finally i found answer in some article. They said across any Cross-Domain(site) HTTP requests, first browser will send ‘OPTIONS’ Request called as “Preflight Request”...
“preflighted” requests first send an HTTP OPTIONS request header to the resource on the other domain, in order to determine whether the actual request is safe to send and this request expects appropriate headers saying that service is allowing to access
the service as a Response
To achieve this we have two solutions...
1) WCF Custom behaviors
2) Modifying the Global.asax file’s Application_BeginRequest event.
I followed the second one...
Solution is to add a Global.asax file to the WCf service project and add the
following code in that,then it perfectly works across any browser...
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
I am attempting to call a wcf rest service via ajax construct using jquery, however i am getting a bad request error when doing so from the jquery. Also, I try to browse directly to the service and receive a blank page. I have done WCF service calls before in the past and cannot figure out what is wrong here. Thanks in advance to all that reply. When browsing directly to the service I see no results. Here is the jquery ajax code that makes the call:
$.ajax({
type: "GET",
dataType: "json",
contentType: "application/json; charset=utf-8",
url: "http://localhost:57452/mobile/WCFService/ContactService.svc/hello",
success: function (result) {
alert('success');
},
error: function (result) {
alert(result.status + ' ' + result.statusText);
}
});
Here is the service interface:
[ServiceContract]
public interface IContactService
{
[OperationContract]
[WebGet(
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "hello")]
string SaySomething();
}
Here is the service class:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ContactService : IContactService
{
public string SaySomething()
{
// Add your operation implementation here
return "Hello!";
}
}
Here is the configuration for the service in the web.config file:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<behaviors>
<serviceBehaviors>
<behavior name="SomeNameSpace.mobile.WCFService.ContactServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="LeeCounty_ASP.mobile.WCFService.ContactServiceBehavior"
name="SomeNameSpace.mobile.WCFService.ContactService">
<endpoint address="" binding="wsHttpBinding" contract="SomeNameSpace.mobile.WCFService.IContactService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
I found the issue. It appears that when adding a wcf service, the default bindings added to the config file did not add the webHttpBinding. Found the solution from this link, http://www.codeproject.com/Articles/132809/Calling-WCF-Services-using-jQuery
I have a WCF service that needs to be called via SOAP (working) and via JSON (not working).
My C# code:
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(ResponseFormat=WebMessageFormat.Json)]
string Foo();
}
public class Service1 : IService1
{
public string Foo()
{
return "woohooo";
}
}
And here's my config:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="Service1">
<endpoint address="soap" binding="basicHttpBinding" contract="DummyService.IService1"/>
<endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="DummyService.IService1"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript/>
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
And here's my Javascript:
$.getJSON("/Service1.svc/Foo")
.success(function (result) {
alert("success! " + result);
})
.fail(function (result) {
console.log("failed!");
console.log(result);
});
The response I get is "400 Bad Request". What am I doing wrong? I've followed the advice in REST / SOAP endpoints for a WCF service, but it still-a-no-worksies. :-) Help!
Try including the endpoint address in the service URL. Something like:
$.getJSON("/Service1.svc/json/Foo")
Also, you should enable WCF tracing to see what error is being returned. You will need the Service Trace Viewer to view the log information.
UPDATE:
Below is an example using your code that works.
The configuration file contains
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
<services>
<service behaviorConfiguration="jsonServiceBehavior" name="DummyService.Service1">
<endpoint address="soap" binding="basicHttpBinding" contract="DummyService.IService1"/>
<endpoint address="json"
behaviorConfiguration="jsonBehavior"
binding="webHttpBinding" contract="DummyService.IService1"/>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="jsonServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
I created an empty web project and added the following HTML page to test the service.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$.getJSON("/Service1.svc/json/Foo")
.success(function (result) {
alert("success! " + result);
})
.fail(function (result) {
console.log("failed!");
console.log(result);
});
});
</script>
</head>
<body>
</body>
</html>
And my Service1.svc has the following:
<%# ServiceHost Language="C#" Service="DummyService.Service1" %>
I'm thinking it's because the URL you are using is an absolute URL, not a relative one.
If you are running this in the ASP.NET debugger, the service would be available on the following address:
http://localhost:52200/Web/Service1.svc
Because you are preceeding the URL with a forward slash, the service query is actually being sent to
http://localhost:52200/Service1.svc
So you need to pass in the appropriate relative address. If your service and the script file are in the same directory, change it to:
$.getJSON("./Service1.svc/Foo")
Try taking out the <webHttp /> element from the endpoint behavior.
I have a web service that is invoked by Ajax, and it doesn't have this element.
When I tried putting the element in, it stopped working.
(Admittedly, this was to do with not recognizing the date formats, so it's not an exact match for your problem).
(My third answer. I know that ONE of these answers is going to be right :-)
Try setting aspNetCompatibilityEnabled to true on the serviceHostingEnvironment.
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
This is just a guess. When I turn this off on my implementation the call still arrives, but HttpContext.Current returns NULL.
I'm having issues passing JSON to the Weight method. I keep getting HTTP/1.1 415 Cannot process the message because the content type 'application/x-www-form-urlencoded; charset=UTF-8' was not the expected type 'text/xml; charset=utf-8'.
I think I have a problem with either my contract or web.config. All my research turns up empty. I'll be calling this service from a Web Part using jQuery's $.ajax.
Interface:
namespace XXX.SharePoint.WebServices
{
[ServiceContract]
public interface ICalculators
{
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json
)]
Single Weight(Single Width, Single Diameter, Single Size, Single Factor);
}
}
web.config:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="XXX.SharePoint.WebServices.CustomServiceBehaviour"
name="XXX.SharePoint.WebServices.Calculators">
<endpoint address=""
binding="basicHttpBinding"
contract="XXX.SharePoint.WebServices.ICalculators" >
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://moss2010/"></add>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="XXX.SharePoint.WebServices.CustomServiceBehaviour">
<!-- 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>
</system.serviceModel>
</configuration>
As always, thanks in advance!
Here's a full working example of a WCF service hosted in IIS:
[ServiceContract]
public interface ICalculators
{
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json
)]
float Weight(float width, float diameter, float size, float factor);
}
public class Calculators : ICalculators
{
public float Weight(float width, float diameter, float size, float factor)
{
return 10f;
}
}
calculators.svc:
<%#
ServiceHost
Language="C#"
Debug="true"
Service="XXX.SharePoint.WebServices.Calculators"
Factory="System.ServiceModel.Activation.WebServiceHostFactory"
CodeBehind="Calculators.svc.cs"
%>
web.config:
<system.serviceModel>
<services>
<service
behaviorConfiguration="XXX.SharePoint.WebServices.CustomServiceBehaviour"
name="XXX.SharePoint.WebServices.Calculators">
<endpoint
address=""
binding="webHttpBinding"
contract="XXX.SharePoint.WebServices.ICalculators"
/>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="XXX.SharePoint.WebServices.CustomServiceBehaviour">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Consumption using jQuery in the same ASP.NET application:
$.ajax({
url: '/calculators.svc/Weight',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ Width: 1.2, Diameter: 2.3, Size: 3.4, Factor: 4.5 }),
success: function (result) {
alert(result.WeightResult);
}
});
Notice the usage of webHttpBinding instead of basicHttpBinding (SOAP) in web.config as well as the special WebServiceHostFactory used in the .svc file.
You're sending a request which uses the forms/url-encoded content type (the default for jQuery.ajax when the value of the data member is an object), which is not supported by default by WCF. You can either change it to send JSON as suggested by Darin Dimitrov, change your service operation to take a Stream as a parameter and parse the input yourself, or extend WCF to support forms/url-encoded data. I've posted a sample in another question (at RESTful WCF web service POST problem) which does the latter.
Also, the preview for "jQuery support" from http://wcf.codeplex.com has some code which supports that content type as well.