JQuery AJAX get not working correctly? - asp.net-mvc-2

I have a partial view with this jquery script:
$("#btnGetEmpInfo").click(function () {
var selectedItem = $('#EmployeeId').val();
var focusItem = $('#EmployeeId')
alert("Starting");
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
url: "<%= Url.Action("getEmpInfo", "NewEmployee")%>?sData=" + selectedItem,
data: "{}",
success: function(data) {
if (data.length > 0) {
alert("Yeah!");
} else {
alert("No data returned!");
}
}
});
alert("Back!");
});
Then in my controller I have:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getEmpInfo(string sData)
{
return new JsonResult { Data = "test" };
}
I can breakpoint in the controller and it is hitting, but the only "Alerts" I get are the "Starting" and "Back". Why would the data not be returned or at least hit saying no data returned?
Thanks in advance for any and all help.
Geo...

You probably might want to improve this ajax call like this:
$.ajax({
type: 'GET',
url: '<%= Url.Action("getEmpInfo", "NewEmployee")%>',
data: { sData: selectedItem },
success: function(data) {
// Warning: your controller action doesn't return an array
// so don't expect a .length property here. See below
alert(data.Data);
}
});
and have your controller action accept GET requests:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult getEmpInfo(string sData)
{
return Json(new { Data = "test" }, JsonRequestBehavior.AllowGet);
}
OK, now that we have fixed the error let me elaborate. In your code you were using an application/json content type to format your request string. Unfortunately in ASP.NET MVC 2 there is nothing out of the box that is capable of making sense of JSON requests (unless you wrote a custom json value provider factory). Then using string concatenation to append the sData parameter to the URL without ever URL encoding it meaning that your code would break at the very moment the user enters some special character such as & in the EmployeeId textbox.

Try adding the 'beforeSend', 'error' and 'complete' callbacks to get more info in your javascript debugger. http://api.jquery.com/jQuery.ajax/
Are you using a javascript debugger? (firebug, ie9 dev-tools, chrome dev-tools are decent ones 3 that come to mind)

Related

DotNetNuke Service API Authorization throwing 401 Unauthorized code

I am having a bit of difficulty figuring out why I am getting 401 Unauthorized status from service framework. At the moment I have it setup to allow everyone to do as they please but that because when I try to enable authorisation I get 401 error code.
//[SupportedModules("Boards")]
//[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]
[AllowAnonymous]
public class BoardsServiceController : DnnApiController
{ ... }
The strange thing is I have another module which is more than happy to work away with DnnModuleAuthorize
[SupportedModules("Assignments")]
[DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)]
public class AsgnsServiceController : DnnApiController
{ ... }
In both cases I have checked to make sure the user has permissions to view the page on which the module lives.
I have cross referenced both projects and everything seems to be spot on. Yet one is working away just fine and the other one returns 401.
Any suggestions?
Update
For Assignments module I am mostly using jQuery style of ajax request just because I haven't got around to revising the module. So a typical GET request would look something like this:
$.ajax({
type: "GET",
url: sf.getServiceRoot( "Assignments" ) + "AsgnsService/GetAssignments",
data: data,
beforeSend: sf.setModuleHeaders
}).done( function ( items ) {
//removed for brevity
}).fail( function ( xhr, result, status ) {
//removed for brevity
});
As for Boards module the code structure is slightly different due knockout implementation. There is a dedicated ServiceCaller but it all boils down to the same ajax call to the server except that instead of having full blown ajax call defined as above it looks much neater.
var that = this;
that.serviceCaller = new dnn.boards.ServiceCaller($, this.moduleId, 'BoardsService');
var success = function (model) {
if (typeof model !== "undefined" && model != null) {
viewModel = new boardViewModel(model.colLists);
ko.bindingHandlers.sortable.beforeMove = viewModel.verifyAssignments;
ko.bindingHandlers.sortable.afterMove = viewModel.updateLastAction;
// normally, we apply moduleScope as a second parameter
ko.applyBindings(viewModel, settings.moduleScope);
}
//console.log('success', model);
};
var failure = function (response, status) {
console.log('request failure: ' + status);
};
var params = {
BoardId: this.boardId
};
that.serviceCaller.get('GetBoardLists', params, success, failure);
And the ServiceCaller ajax function itself looks like this:
function (httpMethod, method, params, success, failure, synchronous) {
var options = {
url: that.getRoot() + method,
beforeSend: that.services.setModuleHeaders,
type: httpMethod,
async: synchronous == false,
success: function (d) {
if (typeof (success) != 'undefined') {
success(d || {});
}
},
error: function (xhr, textStatus, errorThrown) {
if (typeof (failure) != 'undefined') {
var message = undefined;
if (xhr.getResponseHeader('Content-Type').indexOf('application/json') == 0) {
try {
message = $.parseJSON(xhr.responseText).Message;
} catch (e) {
}
}
failure(xhr, message || errorThrown);
}
}
};
if (httpMethod == 'GET') {
options.data = params;
} else {
options.contentType = 'application/json; charset=utf-8';
options.data = ko.toJSON(params);
options.dataType = 'json';
}
$.ajax(options);
};
This would be the two GET requests from two different modules where one is happy and the other throws a status 401 when I enable the same annotations.
Does this provide any clues?
Update
Now in saying all of the above if one takes a look at the original Boards module code base one will notice [DnnAuthorize] annotation attached to every function.
During module revision I removed all instances of [DnnAuthorize] annotation and replaced it with two of my own on the service class itself.
When I add [DnnAuthorize] as annotation on service class itself things work as expected. So why [SupportedModules("Boards")] and [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.View)] combination doesn't !?
I am not sure but working with the WebAPI you have to register the Service Framework anti forgery stuff
ServicesFramework.Instance.RequestAjaxAntiForgerySupport();
This is part of asking the API to work with a specific module.

Dart : i can't POST data in HTTP Message Body using HttpRequest.send() method

In my Rest server, i can't read the data contained in the HTTP Message Body when the call comme from script writing in Dart.
When calling the same webservice with ajax, there is no problem. In both case the data send with the URL (pcParamUrl=yopla) can be read in the server side.
i think the problem come from "processData: false" in ajax, i don't know how to set this key in HttpRequest Dart object.
I am trying to convert this ajax call (javascript) :
var url = "http://127.0.0.1:8980/TestDartService/rest/TestDartService/Test?pcParamUrl=yopla";
$.ajax({url: url,
type: "POST",
processData: false,
contentType: "application/json",
data: JSON.stringify({ request: {pcParamBody: "yepYep"} }),
success: function(data, status) { alert(data.response.pcRetour); },
error: function(status) { alert("erreur"); }
});
to this one using Dart:
HttpRequest request = new HttpRequest();
request.onReadyStateChange.listen((_) {
if (request.readyState == HttpRequest.DONE && request.status == 200 || request.status == 0)) {
print(request.responseText);
}
});
var url = "http://127.0.0.1:8980/TestDartService/rest/TestDartService/Test?pcParamUrl=yopla";
request.open("POST", url, async: false);
request.setRequestHeader("content-Type", "application/json");
String jsonData = JSON.encode('{ request: { pcParamBody: "yepYep" } }'); // etc...
request.send(jsonData);
thanks for your help and sorry for my bad english
(moved from the Question:)
The problem is the format of the data being passed to JSON.encode; it should be an object; or you could skip the encoding altogether:
String jsonData = JSON.encode('{request: {pcParamBody: "yepYep"}}'); // BAD
String jsonData = JSON.encode({"request": {"pcParamBody": "yepYep"}}'); // GOOD
String jsonData = '{request: {pcParamBody: "yepYep"}}'; // ALSO GOOD

zend form dispatch a validator onblur an element

Is that possible?
I already wrote a simple validator that is triggered when the form is submitted.
Can I use the same validator, but it must be triggered right after the input field has been left.
is it possible?
pablo
It would be possible, here is one way to go about it.
Add a Javascript onblur event to the form element
The onblur call sends an ajax request containing that one field and its value to a ZF action
The action calls the validator on that element, or uses Zend_Form::isValidPartial to check the populated element
Return a JSON response indicating valid/invalid and optional error message
On ajax complete, read the JSON response and update HTML to reflect the result of validation
Hope that helps.
This is part of working example:
Backend:
class UserController extends Zend_Controller_Action
{
/* ... */
public function validateAction()
{
if ($this->_request->isXmlHttpRequest()) {
$values = $this->_request->getParam('values');
$form = new Form_User();
$isValid = true;
if (!$form->isValidPartial($values)) {
$isValid = $form->getMessages();
}
$this->_helper->json(array('errors' => $isValid));
}
}
/* ... */
}
Frontend, (just ajax call part) should be attached on event:
$.ajax({
type: "POST",
url: "/user/validate/",
data: {
'values': $('#my-form-id').serialize()
},
dataType: "json",
beforeSend:function(){
},
success: function(response){
var result = response.errors;
if (result == true) {
// given fields are valid
// do some extra stuff here
} else {
// invalid
// do some extra stuff here
}
}
}
});

Backbone.js Model different url for create and update?

lets say I have a Backbone Model and I create an instance of a model like this:
var User = Backbone.Model.extend({ ... });
var John = new User({ name : 'John', age : 33 });
I wonder if it is possible when I use John.save() to target /user/create when I use John.save() on second time (update/PUT) to target /user/update when I use John.fetch() to target /user/get and when I use John.remove() to target /user/remove
I know that I could define John.url each time before I trigger any method but I'm wondering if it could be happen automatically some how without overriding any Backbone method.
I know that I could use one url like /user/handle and handle the request based on request method (GET/POST/PUT/DELETE) but I'm just wondering if there is a way to have different url per action in Backbone.
Thanks!
Methods .fetch(), .save() and .destroy() on Backbone.Model are checking if the model has .sync() defined and if yes it will get called otherwise Backbone.sync() will get called (see the last lines of the linked source code).
So one of the solutions is to implement .sync() method.
Example:
var User = Backbone.Model.extend({
// ...
methodToURL: {
'read': '/user/get',
'create': '/user/create',
'update': '/user/update',
'delete': '/user/remove'
},
sync: function(method, model, options) {
options = options || {};
options.url = model.methodToURL[method.toLowerCase()];
return Backbone.sync.apply(this, arguments);
}
}
To abstract dzejkej's solution one level further, you might wrap the Backbone.sync function to query the model for method-specific URLs.
function setDefaultUrlOptionByMethod(syncFunc)
return function sync (method, model, options) {
options = options || {};
if (!options.url)
options.url = _.result(model, method + 'Url'); // Let Backbone.sync handle model.url fallback value
return syncFunc.call(this, method, model, options);
}
}
Then you could define the model with:
var User = Backbone.Model.extend({
sync: setDefaultUrlOptionByMethod(Backbone.sync),
readUrl: '/user/get',
createUrl: '/user/create',
updateUrl: '/user/update',
deleteUrl: '/user/delete'
});
Are you dealing with a REST implementation that isn't to spec or needs some kind of workaround?
Instead, consider using the emulateHTTP option found here:
http://documentcloud.github.com/backbone/#Sync
Otherwise, you'll probably just need to override the default Backbone.sync method and you'll be good to go if you want to get real crazy with that... but I don't suggest that. It'd be best to just use a true RESTful interface.
No you can't do this by default with backbone. What you could to is to add to the model that will change the model url on every event the model trigger. But then you have always the problem that bckbone will use POST add the first time the model was saved and PUT for every call afterward. So you need to override the save() method or Backbone.sync as well.
After all it seems not a good idea to do this cause it break the REST pattern Backbone is build on.
I got inspired by this solution, where you just create your own ajax call for the methods that are not for fetching the model. Here is a trimmed down version of it:
var Backbone = require("backbone");
var $ = require("jquery");
var _ = require("underscore");
function _request(url, method, data, callback) {
$.ajax({
url: url,
contentType: "application/json",
dataType: "json",
type: method,
data: JSON.stringify( data ),
success: function (response) {
if ( !response.error ) {
if ( callback && _.isFunction(callback.success) ) {
callback.success(response);
}
} else {
if ( callback && _.isFunction(callback.error) ) {
callback.error(response);
}
}
},
error: function(mod, response){
if ( callback && _.isFunction(callback.error) ) {
callback.error(response);
}
}
});
}
var User = Backbone.Model.extend({
initialize: function() {
_.bindAll(this, "login", "logout", "signup");
},
login: function (data, callback) {
_request("api/auth/login", "POST", data, callback);
},
logout: function (callback) {
if (this.isLoggedIn()) {
_request("api/auth/logout", "GET", null, callback);
}
},
signup: function (data, callback) {
_request(url, "POST", data, callback);
},
url: "api/auth/user"
});
module.exports = User;
And then you can use it like this:
var user = new User();
// user signup
user.signup(data, {
success: function (response) {
// signup success
}
});
// user login
user.login(data, {
success: function (response) {
// login success
}
});
// user logout
user.login({
success: function (response) {
// logout success
}
});
// fetch user details
user.fetch({
success: function () {
// logged in, go to home
window.location.hash = "";
},
error: function () {
// logged out, go to signin
window.location.hash = "signin";
}
});

Sending parameters in AJAX call

This has been asked before by others, but I have not been able to use their answers.
I am trying to sending some data by doing the following:
function addForumPost() {
var title = jQuery('#forumTitle').val();
var message = htmlEncode(jQuery('#message').htmlarea("toHtmlString"));
var tagNames = addTags();
var dataPost = $.toJSON({ title: 'testingsadf', message: message, tagNames: tagNames });
jQuery.ajax({
type: "POST",
url: "/Create",
data: dataPost,
dataType: "json",
success: function (result) {
}
});
}
I have checked, and doubled checked that the input contains data, but I only receive the data from the message parameter in my controller. The other two values are null. As you can see in the the example above, I have even assigned some static text to the title parameter, but I still only receive data for the message parameter.
The controller looks like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(string title, string message, List<string> tagNames)
{
....
}
Your error is very simple. If you have an action which returns JsonResult then it means not that you have to send also JSON encoded input parameters to the method. Just remove the usage of $.toJSON() and use the object as a value of data parameter of jQuery.ajax (see the answer of Darin for example).
If you call ASMX Web Service instead of ASP.NET MVC action you have to use contentType: "application/json; charset=utf-8" and convert the values of all web-method parameters to JSON but in a little other way (see How do I build a JSON object to send to an AJAX WebService?). But ASP.NET MVC hat no such requirement. MVC converts the input parameters which you send with respect of Parse method (int.Parse, DateTime.Parse and so on) and not deserialize from JSON. So if you search for code examples look exactly which technology are used on the backend: ASP.NET MVC, ASMX web serveces or WFC.
Try setting the traditional parameter starting from jQuery 1.4. This works for me:
var title = 'title';
var message = 'message';
var tagNames = ['tag1', 'tag2'];
jQuery.ajax({
type: 'POST',
url: '/Home/Create',
data: { title: title, message: message, tagNames: tagNames },
dataType: 'json',
traditional: true,
success: function (result) {
}
});
With this action:
[HttpPost]
public ActionResult Create(
string title,
string message,
IEnumerable<string> tagNames
)
{
return Json(new
{
Title = title,
Message = message,
TagNames = tagNames
});
}
You don't have to post json for the type of action you described.
You don't have to manually assemble the fields into a map. Use .serializeArray()
var postData = $('.myform').serializeArray()