In a larger project I am having trouble getting a WCF service method to consume a JSON parameter. So I produced a smaller test case and the behaviour is echoed. If I debug the service I can see the parameter value is null at the service call. Fiddler confirms that the JSON is being sent and JsonLint confirms it is valid.
Code below with annotations from debugging.
[ServiceContract]
public interface IWCFService
{
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "getstring")]
string GetString();
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "getplayer")]
//[WebGet(BodyStyle = WebMessageBodyStyle.WrappedRequest,
// ResponseFormat = WebMessageFormat.Json,
// UriTemplate = "getplayers")]
Player GetPlayer();
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "getplayers")]
List<Player> GetPlayers();
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.Wrapped,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json,
UriTemplate = "totalscore")]
string TotalScore(Player player);
}
... and its implementation
public class WCFService : IWCFService
{
public string GetString()
{
return "hello from GetString";
}
public Player GetPlayer()
{
return new Player()
{
Name = "Simon",
Score = 1000,
Club = new Club()
{
Name = "Tigers",
Town = "Glenelg"
}
};
}
public List<Player> GetPlayers()
{
return new List<Player>()
{
new Player()
{
Name = "Simon",
Score = 1000 ,
Club=new Club()
{
Name="Tigers",
Town = "Glenelg"
}
},
new Player()
{
Name = "Fred", Score = 50,
Club=new Club()
{
Name="Blues",
Town="Sturt"
}
}
};
}
public string TotalScore(Player player)
{
return player.Score.ToString();
}
}
Calling any of the first three methods works correctly (but no parameters as you'll note). Calling the last method (TotalScore) with this client code ...
function SendPlayerForTotal() {
var json = '{ "player":{"Name":"' + $("#Name").val() + '"'
+ ',"Score":"' + $("#Score").val() + '"'
+ ',"Club":"' + $("#Club").val() + '"}}';
$.ajax(
{
type: "POST",
contentType: "application/json; charset=utf-8",
url: "http://localhost/wcfservice/wcfservice.svc/json/TotalScore",
data: json,
dataType: "json",
success: function (data) { alert(data); },
error: function () { alert("Not Done"); }
});
}
... results in ...
There was an error while trying to deserialize parameter http://tempuri.org/:player. The InnerException message was 'Expecting state 'Element'.. Encountered 'Text' with name '', namespace ''. '.
I have tried sending an unwrapped version of the JSON ...
{"Name":"Simon","Score":"100","Club":"Rigby"}
but at the service the parameter is null, and no formatter exceptions.
This is the system.serviceModel branch of the service web.config:
<system.serviceModel>
<services>
<service name="WCFService.WCFService" behaviorConfiguration="WCFService.DefaultBehavior">
<endpoint address="json" binding="webHttpBinding" contract="WCFService.IWCFService" behaviorConfiguration="jsonBehavior"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCFService.DefaultBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
And here is the Player DataContract.
[DataContract(Name = "Player")]
public class Player
{
private string _name;
private int _score;
private Club _club;
[DataMember]
public string Name { get { return _name; } set { _name = value; } }
[DataMember]
public int Score { get { return _score; } set { _score = value; } }
[DataMember]
public Club Club { get { return _club; } set { _club = value; } }
}
Any help greatly appreciated and if any other info is required, please let me know.
Many thanks.
You encode the input parameter player
of the method TotalScore
in the wrong way.
I recommend you to use JSON.stringify
function from json2.js to convert any JavaScript objects to JSON.
var myPlayer = {
Name: "Simon",
Score: 1000,
Club: {
Name: "Tigers",
Town: "Glenelg"
}
};
$.ajax({
type: "POST",
url: "/wcfservice/wcfservice.svc/json/TotalScore",
data: JSON.stringify({player:myPlayer}), // for BodyStyle equal to
// WebMessageBodyStyle.Wrapped or
// WebMessageBodyStyle.WrappedRequest
// data: JSON.stringify(myPlayer), // for no BodyStyle attribute
// or WebMessageBodyStyle.WrappedResponse
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data, textStatus, xhr) {
alert(data.TotalScoreResult); // for BodyStyle = WebMessageBodyStyle.Wrapped
// or WebMessageBodyStyle.WrappedResponse
// alert(data); // for BodyStyle = WebMessageBodyStyle.WrappedRequest
// or for no BodyStyle attributes
},
error: function (xhr, textStatus, ex) {
alert("Not Done");
}
});
If you change the BodyStyle = WebMessageBodyStyle.Wrapped
attribute of the TotalScore
method to BodyStyle = WebMessageBodyStyle.WrappedRequest
you can change the alert(data.TotalScoreResult)
in the success
handle to alert(data)
.