I am trying to update a single value of a record in the database using PUT request from java script to my WCF oData service. The code for the calling the service is
var upda = { stat: $("#com_status_txt").val() };
upda = JSON.stringify(upda);
console.log(upda);
$.ajax({
type: "PUT",
contentType: "application/json; charset=utf-8",
url: "http://localhost:65401/sdrservice.svc/issues('" + sessionStorage.currentIssue + "')/stat",
data: upda,
dataType: "json",
success: function (result) {
//Some code goes here...
},
error: function (xhr, textStatus, errorMessage) {
console.log(JSON.stringify(xhr));
}
});
where sessionStorage.currentIssue is my id for the issue and i need to update the stat field in table.
But when I run this service I receive following error.
{"readyState":4,"responseText":"{\"odata.error\":{\"code\":\"\",\"message\":
{\"lang\":\"en-US\",\"value\":\"An error occurred while processing this
request.\"},\"innererror\":{\"message\":\"A top-level property with name 'stat'
was found in the payload; however, property and collection payloads must always
have a top-level property with name value' .
\",\"type\":\"Microsoft.Data.OData.ODataException\",\"stacktrace\":\" at
Microsoft.Data.OData.JsonLight.ODataJsonLightPropertyAndValueDeserializer.
<>c__DisplayClassc.ReadTopLevelPropertyImplementation>b__5(PropertyParsingResult propertyParsingResult, String propertyName)\\r\\n at
Microsoft.Data.OData.JsonLight.ODataJsonLightDeserializer.ProcessProperty(Duplic
atePropertyNamesChecker duplicatePropertyNamesChecker, Func`2
readPropertyAnnotationValue, Action`2 handleProperty)\\r\\n at
Microsoft.Data.OData.JsonLight.ODataJsonLightPropertyAndValueDeserializer.ReadTo
pLevelPropertyImplementation(IEdmTypeReference expectedPropertyTypeReference, DuplicatePropertyName
Here the message A top-level property with name 'stat' was found in the payload; however, property and collection payloads must always have a top-level property with name value' is confusing when I am not passing any collection just a key/value pair. My json representation for data is
{"stat":"Query"}
Json representation is a problem here change it to
{ "value": "Query" }
Related
I'm using mobilefirst platform v7, and I send post request using the WLResourceRequest/sendFormParameters api, however, I can't get the submitted parameters from js adapter side...
belows are sample code:
var resourceRequest = new WLResourceRequest("adapters/businessAdapter/flightsearch", WLResourceRequest.POST);
var params={
"flightNum":'mu8899',
"departCity":'SHA',
"destCity" :'PEK'
};
resourceRequest.sendFormParameters(params).then(
callSuccess,
callFailure
);
js adapter code:
function flightsearch(params) {
WL.Logger.info("get params "+params);
var input = {
method : 'post',
returnedContentType : 'json',
path : 'restapi/api/flightsearch',
body :{
contentType: 'application/json; charset=utf-8',
content:params
},
headers: {"Accept":"application\/json"}
};
return WL.Server.invokeHttp(input);
}
The syntax you used is fine for Java adapters.
However, in the case of JavaScript adapters, procedure parameters are handled differently.
First, your adapter procedure should define the parameters that it expects:
function flightsearch(flightNum, departCity, destCity) {
///
}
Secondly, this procedure will be triggered using an HTTP GET or POST with a single parameter called params which needs to contain an array, representing all the procedure parameters in the correct order:
params:["mu8899","SHA","PEK"]
Now using JavaScript, this would translate to:
var resourceRequest = new WLResourceRequest("adapters/businessAdapter/flightsearch", WLResourceRequest.POST);
var params=[
'mu8899',
'SHA',
'PEK'
];
var newParams = {'params' : JSON.stringify(params)};
resourceRequest.sendFormParameters(newParams).then(
callSuccess,
callFailure
);
As you can see, we first build the JSON array (note, array not object) in the correct order, then we convert it to String and send it to the adapter with the parameter name 'params'.
In my asp.net mvc 4 application I do an ajax call to a controller method that has below signature:
[HttpPost]
public ActionResult DoSomething(string param1, string param2)
Currently my ajax call is working and I know how to pass multiple parameters, see below:
$.ajax({
url: "/DoSomething/",
data: { param1: "this is param1", param2: "this is param2" },
type: 'POST',
dataType: 'json'
});
But the problem here is that ajax call is totally dependant on the name of the parameters of the controller method, I mean, when passing parameters in the ajax call to the controller method, those parameters must be named the same as in the controller signature so is there any way to avoid name dependant? for example, without indicating parameter name in the ajax call and put them in order so the controller method knows that first parameter passed corresponds to the first parameter, second parameter passed to the second one and so on...
you can pass a array
[HttpPost]
public ActionResult DoSomething(string[] param)
$.ajax({
url: "/DoSomething/",
data: $.param({ param : ["this is param1","this is param2"] }),
type: 'POST',
dataType: 'json'
});
for more info check the docs here http://api.jquery.com/jquery.param/
what if you tried declaring the post function this way;
public ActionResult DoSomething(string args[])
/* I'm not sure which language you're using on the asp side,
* but the default array passed to a function is usually `args`
*/
and then you can use all passed parameters as they are in an array, and you can pass any amount of parameters?
Have you tried this? jQuery supports arrays as data.
$.ajax({
url: "/DoSomething/",
data: { params:[ "this is param1", "this is param2" ]},
type: 'POST',
dataType: 'json'
});
I've got a dnn module that I've created that has no problem retrieving data from the server using the WebAPI. However, when I try to perform an update, I continue to get errors no matter what I try. Viewing in Firebug, I can the data being posted:
!(http://www.virtual-essentials.com/personal/firebug1.png)
But, when I debug, I see nothing but default (null.setnull) values (bool = false, int = 0, string= empty).
Then, of course the response is no good and results in this:
!(http://www.virtual-essentials.com/personal/firebug2.png)
I've tried every combination of things I can think of, but cannot get this figured out and I'm going nuts.
Here is the ajax call:
//U//operation - update
self.updateTestimonial = function (objItem) {
var method = "UpdateTestimonial";
self.UpdatePublishStatus(objItem);
$.ajax({
type: "POST",
contentType: "application/json",
url: sf.getServiceRoot('VirtualEssentials/Testimonials') + "TestimonialWeb/" + method,
beforeSend: sf.setModuleHeaders,
data: ko.toJSON({ item: new TestimonialInfoDTO(objItem.TestimonialID(), objItem.IsPublished())}),
success: function (data) {
self.userAlertText(objItem.Testimonial() + ' changes have been saved');
//self.getTestimonials(); //get the new data after updates
},
error: function (xhr, status, error) {
self.userAlertText('OOPS! Error updating ' + objItem.Testimonial + '<br />' + (error));
//put the status back
self.UpdatePublishStatus(objItem);
}
});
};
Here is the WebAPI Controller call:
[HttpPost]
[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)]
public System.Net.Http.HttpResponseMessage UpdateTestimonial(TestimonialInfoDTO item)
{
try
{
Controller.TestimonialController objController = new Controller.TestimonialController();
objController.PublishTestimonial(item.TestimonialID, item.IsPublished);
}
catch (HttpResponseException ex)
{
return ex.Response;
}
}
Any help on this is sincerely appreciated!!
It never fails that you find a solution as soon as you ask for help. I pulled the source code for the core Journal module and saw that they were posting the post data a bit differently. I modified the json string that I was sending and it all went through. I thought since the parameter for the method was:
UpdateTestimonial(TestimonialInfoDTO item)
that it was expecting:
{"item":{"TestimonialID":14,"IsPublished":false}}
but, it turns out what it really wants is:
{"TestimonialID":14,"IsPublished":false}
Anyhow, here is what I did to make the changes; I just changed the way I built the data to post.
var data = new TestimonialInfoDTO(objItem.TestimonialID(), objItem.IsPublished());
$.ajax({
...
data: ko.toJSON(data),
I hope this helps someone. There isn't a lot of Dnn WebAPI documentation out at this point.
Thanks!
Briana
JavaScript
For example, I have the following JavaScript code (Dojo 1.6 is already loaded):
dojo.require("dojo.io.script")
// PART I
var jsonpArgs = {
url: "http://myapp.appspot.com/query",
content: {
id: "1234",
name: "Juan",
start_date: "2000-01-01",
callback: "recover"
}
};
// PART II
dojo.io.script.get(jsonpArgs).then(function(data) {
console.log(data);
});
// PART III
function recover(data) {
console.log(data);
}
Direct query from browser
I understand that my server will receive the query as though I typed the following into the address bar:
http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=recover
Expected response
If I directly queried my server using the browser address bar, I'll receive, in MIME type application/json and plaintext rendered in browser, something like this:
recover(
{
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
}
);
Problem
Now, looking back at Part II of the JavaScript, I'd execute the JSONP request with dojo.io.script.get(jsonpArgs). This returns a Deferred object, which I can take advantage of by chaining .then after it. Note that I defined the handler for the .then event to output that captured data to the console.
However, all I get in the console is an Event. I tried to search its data tree, but I could not find the data I expected.
Question
Where is the response for a JSONP request stored? How do I find it?
My server (which I control) only outputs a plaintext rendering of the data requested, wrapped in the callback function (here specified as recover), and specifies a application/json MIME type. Is there anything else I need to set up on my server, so that the response data is captured by the Deferred object?
Attempted solution
I can actually recover the response by defining the callback function (in this case recover in Part III of the JavaScript). However, in the Dojo tutorials, they just recovered the data using the Deferred (and .then) framework. How do I do it using Dojo Deferreds?
Update (using the Twitter example from Dojo tutorial)
Take for example this script from the Dojo tutorial, Getting Jiggy With JSONP. I edited it to log data to the console.
dojo.require("dojo.io.script");
dojo.io.script.get({
url: "http://search.twitter.com/search.json",
callbackParamName: "callback",
content: {q: "#dojo"}
}).then(function(data){
//we're only interested in data.results, so strip it off and return it
console.log(data); // I get an Object, not an Event, but no Twitter data when browsing the results property
console.log(data.results) // I get an array of Objects
return data.results;
});
For console.log(data), I get an Object, not an Event as illustrated by my case. Since the example implies that the data resides in data.results, I also try to browse this tree, but I don't see my expected data from Twitter. I'm at a loss.
For console.log(data.results), I get an array of Objects. If I query Twitter directly, this is what I'd get in plaintext. Each Object contains the usual tweet meta-data like username, time, user portrait, and the tweet itself. Easy enough.
This one hits me right on the head. The handler for the .then chain, an anonymous function, receives only one argument data. But why is it that the results property in console.log(data) and the returned object I get from console.log(data.results) are different?
I got it.
Manual callback implementation
function recover(data) {
console.log(data);
}
var jsonpArgs = {
url: "http://myapp.appspot.com/query",
content: {
id: "1234",
name: "Juan",
start_date: "2000-01-01",
callback: "recover"
};
dojo.io.script.get(jsonpArgs);
This is the request that my server will receive:
http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=recover
In this case, I'll expect the following output from my server:
recover({
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
});
Three things to note:
Server will expect callback in the query URL string. callback is implemented as a property of jsonpArgs.
Because I specified callback=recover, my server will attach recover( + the_data_I_need + ), returns the whole string to the browser, and browser will execute recover(the_data_I_need). This means...
That I'll have to define, for example, function recover(one_argument_only) {doAnythingYouWantWith(one_argument_only)}
The problem with this approach is that I cannot take advantage of Deferred chaining using .then. For example:
dojo.io.script.get(jsonpArgs).then(function(response_from_server) {
console.log(response_from_server);
})
This will give me an Event, with no trace of the expected response at all.
Taking advantage of Dojo's implementation of JSONP requests
var jsonpArgs = {
url: "http://myapp.appspot.com/query",
callbackParamName: "callback",
content: {
id: "1234",
name: "Juan",
start_date: "2000-01-01"
};
dojo.io.script.get(jsonpArgs);
This is the request that my server will receive:
http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=some_function_name_generated_by_dojo
In this case, I'll expect the following output from my server:
some_function_name_generated_by_dojo({
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
});
Things to note:
Note the property of jsonpArgs, callbackParamName. The value of this property must be the name of the variable (in the query URL string) expected by the server. If my server expects callbackfoo, then callbackParamName: "callbackfoo". In my case, my server expects the name callback, therefore callbackParamName: "callback".
In the previous example, I specified in the query URL callback=recover and proceeded to implement function recover(...) {...}. This time, I do not need to worry about it. Dojo will insert its own preferred function callback=some_function_name_generated_by_dojo.
I imagine some_function_name_generated_by_dojo to be defined as:
Definition:
function some_function_name_generated_by_dojo(response_from_server) {
return response_from_server;
}
Of course the definition is not that simple, but the advantage of this approach is that I can take advantage of Dojo's Deferred framework. See the code below, which is identical to the previous example:
dojo.io.script.get(jsonpArgs).then(function(response_from_server) {
console.log(response_from_server);
})
This will give me the exact data I need:
{
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
}
(ExtJS 4.0.7)
I'm using Model.save() to PUT an update to a server. Everything works fine and the server returns a simple JSON response {success: true} (HTTP status 200). Model.save() throws the following error, however:
Uncaught TypeError: Cannot read property 'data' of undefined
Here's where this is happening in the ExtJS code (src/data/Model.js):
save: function(options) {
...
callback = function(operation) {
if (operation.wasSuccessful()) {
record = operation.getRecords()[0]; <-- getRecords() return an empty array
me.set(record.data); <-- record is undefined, so .data causes error
...
}
I've figured out this is happening because Model.save() expects the server to respond with JSON for the entire object that was just updated (or created).
Does anyone know of a clever way to make Model.save() work when the server responds with a simple success message?
I was able to come up with a work-around by using a custom proxy for the model, and overriding the update function:
Ext.define('kpc.util.CustomRestProxy', {
extend: 'Ext.data.proxy.Rest',
alias: 'proxy.kpc.util.CustomRestProxy',
type: 'rest',
reader : {
root: 'data',
type: 'json',
messageProperty: 'message'
},
// Model.save() will call this function, passing in its own callback
update: function(operation, callback, scope) {
// Wrap the callback from Model.save() with our own logic
var mycallback = function(oper) {
// Delete the resultSet from the operation before letting
// Model.save's callback use it; this will
oper.resultSet = undefined;
callback(op);
};
return this.doRequest(operation, mycallback, scope);
}
});
In a nutshell, when my proxy is asked to do an update it makes sure operation.resultSet == undefined. This changes the return value for operation.getRecords() (which you can see in the code sample from my question). Here's what that function looks like (src/data/Operation.js):
getRecords: function() {
var resultSet = this.getResultSet();
return (resultSet === undefined ? this.records : resultSet.records);
}
By ensuring that resultSet == undefined, operation.getRecords returns the model's current data instead of the empty result set (since the server isn't returning a result, only a simple success message). So when the callback defined in save() runs, the model sets its data to its current data.
I investigate this problem and found truly simple answer. Your result must be like this:
{
success: true,
items: { id: '', otherOpt: '' }
}
And items property MUST be equal Model->Reader->root property (children in tree for example).
If you want to use items instead children you can use defaultRootProperty property in Store and configure your nested collections as you want.
PS
Object in items property must be fully defined because it replaces actual record in store.