Reputation: 5696
I have a simple Web Service method defined as:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string MyWebMethod(string foo, string bar)
{
// DataContractJsonSerializer to deserialize foo and bar to
// their respective FooClass and BarClass objects.
return "{\"Message\":\"Everything is a-ok!\"}";
}
I'll call it from the client via:
var myParams = { "foo":{"name":"Bob Smith", "age":50},"bar":{"color":"blue","size":"large","quantity":2} };
$.ajax({
type: 'POST',
url: 'https://mydomain.com/WebServices/TestSvc.asmx/MyWebMethod',
data: JSON.stringify(myParams),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (response, status) {
alert('Yay!');
},
error: function (xhr, err) {
alert('Boo-urns!');
}
});
However, this yields the following error (a breakpoint on the first line in MyWebMethod() is never hit):
{"Message":"No parameterless constructor defined for type of \u0027System.String\u0027.","StackTrace":" at System.Web.Script.Serialization.ObjectConverter.ConvertDictionaryToObject(IDictionary
2 dictionary, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeInternal(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n at System.Web.Script.Serialization.ObjectConverter.ConvertObjectToTypeMain(Object o, Type type, JavaScriptSerializer serializer, Boolean throwOnError, Object& convertedObject)\r\n at System.Web.Script.Services.WebServiceMethodData.StrongTypeParameters(IDictionary
2 rawParams)\r\n at System.Web.Script.Services.RestHandler.InvokeMethod(HttpContext context, WebServiceMethodData methodData, IDictionary`2 rawParams)\r\n at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)","ExceptionType":"System.MissingMethodException"}
I'd like to pass in two string parameters and use DataContractJsonSerializer to write new Foo and Bar objects. Am I missing something?
Upvotes: 3
Views: 4485
Reputation: 924
For the code in the service, you need to use object instead of string for "foo" and "bar". And then use Newtonsoft.Json's function to parse convert this object to Json object and then build the strong typed object.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string MyWebMethod(object foo, object bar)
{
// DataContractJsonSerializer to deserialize foo and bar to
// their respective FooClass and BarClass objects.
//parse object to JObject using NewtonJson
JObject jsonFoo = JObject.Parse(JsonConvert.SerializeObject(foo));
JObject jsonBar = JObject.Parse(JsonConvert.SerializeObject(bar));
Foo fo = new Foo(jsonFoo);
Bar ba = new Bar(jsonBar);
return "{\"Message\":\"Everything is a-ok!\"}";
}
public class Foo{
public Foo(JObject jsonFoo){
if (json["prop1"] != null) prop1= json["prop1"].Value<long>();
if (json["prop2"] != null) prop2= (string)json["prop2"];
if (json["prop3"] != null) prop3= (string)json["prop3"];
}
}
Upvotes: 2
Reputation: 493
I know this is a some what old thread, but addition comments/insight can be helpful (not only to the OP, but to others who find this thread looking for answers).
The OP states that his server-side webmethod receives two strings, foo and bar. His client-side jquery .ajax(...) call creates his two parameters in an object ( { foo: ..., bar: ... } ) and properly JSON.stringify's that object. The problem seems to be that client side, foo and bar are objects themselves with foo having two properties (name and age) and bar having three properties (color, size and quantity). Yet the server-side webmethod is expecting its foo and bar parameters to be strings, not objects. I believe the correct way to resolve this is to create Foo and Bar classes server side and have the server-side webmethod recieve foo and bar as Foo and Bar objects instead of strings. Something like:
public enum Sizes
{
Small = 1,
Medium = 2,
Large = 3
}
public class Foo
{
public string name { get; set; }
public int age { get; set; }
}
public class Boo
{
public string color { get; set; }
public Sizes size { get; set; }
public int quantity { get; set; }
}
...
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string MyWebMethod(Foo foo, Bar bar)
{
// foo and bar will already BE deserialized as long as their signatures
// are compatible between their client-side and server-side representations.
// Bar.size as an enum here server-side should even work with its
// client-side representation being a string as long the string contains
// the name of one of the Sizes enum elements.
return "{\"Message\":\"Everything is a-ok!\"}";
}
Disclaimer: I typed that code from scratch, so there may be some type-o's. :)
Upvotes: 1
Reputation: 122
you need to formulate a "request" element in your json string, then just pass it to data element without using JSON.stringify. See code.
var myParams = "{request: \'{\"foo\":{\"name\":\"Bob Smith\", \"age\":50},\"bar\":{\"color\":\"blue\",\"size\":\"large\",\"quantity\":2}}\' }";
$.ajax({
type: 'POST',
url: 'https://mydomain.com/WebServices/TestSvc.asmx/MyWebMethod',
data: myParams,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (response, status) {
alert('Yay!');
},
error: function (xhr, err) {
alert('Boo-urns!');
}
});
Upvotes: 0
Reputation: 3218
I know this sounds nuts but try setting your web method's response format to XML (ResponseFormat.Xml). For some reason this worked for me.
Upvotes: 0
Reputation: 49185
Shouldn't the signature of your service method be something like
public string MyWebMethod(Foo foo, Bar bar)
But of course, as I understand, ASMX service uses JavaScriptSerializer. You should use WCF service with webHttpBinding to use DataContractJsonSerializer.
Upvotes: 0