I am creating a client-side script to send a dictionary object type to the web api method using $http as follows:
$scope.SearchPolicyDetails = function (data) {
var searchPolicy = new Array();
searchPolicy["InsuredName"] = data.InsuredName;
searchPolicy["PostalCode"] = data.PostalCode;
searchPolicy["LOB"] = data.LOB;
searchPolicy["AgencyName"] = data.AgencyName;
searchPolicy["Symbol"] = data.Symbol;
searchPolicy["PolicyNum"] = data.PolicyNum;
searchPolicy["MCO"] = data.MCO;
searchPolicy["expireswithin"] = data.expireswithin;
searchPolicy["SortFields"] = data.SortFields;
searchPolicy["SortOrder"] = data.SortOrder;
$http({
url: "http://localhost:53054/api/GetPoliciesBySearch",
dataType: 'json',
data: searchPolicy,
headers: {
"Content-Type": "application/json"
}
}).success(function (response) {
$scope.value = response;
})
};
and I have this WebAPI method:
public List<Dictionary<string,string>> GetPoliciesBySearch(Dictionary<string,string> policySearch)
{
return SpecializedHandler.GetAllPolicies(policySearch).IterativeResource;
}
But I am not receiving the object to the method.
I am seeing this error in the chrome console :
I think your code and UI are in different projects, might be you have not configured CORS in web.config or WebApiConfig.cs. You can follow this URL
https://msdn.microsoft.com/en-us/magazine/dn532203.aspx
Instead of using a dictionary in your API action you need to define a class and use that.
class PolicyRequest
{
public string InsuredName { get; set; }
public string PostalCode { get; set; }
public string LOB { get; set; }
...
}
searchPolicy["InsuredName"] = searchPolicy.InsuredName. This is not an array but a json object with attributes like InsuredName and so. to make it into an array. You can do :
var searchPolicy = [];
searchPolicy.push(data.InsuredName);
Looks like there are multiple things to consider here:
First: The object being created clientside isn't going to translate to a List<Dictionary<string, string>> so for this to work as we would like we will have to make some alterations. Consider:
var searchPolicy = {};
searchPolicy['InsuredName'] = data.InsuredName;
searchPolicy['PostalCode'] = data.PostalCode;
//etc (see below for another crucial piece)
Second: The code calling inside of the $http isn't targeting any particular method (see the docs). Consider something along the lines of:
$http({
url: "http://localhost:53054/api/GetPoliciesBySearch",
dataType: 'json',
method: 'POST',
data: JSON.stringify(searchPolicy),
headers: {
"Content-Type": "application/json"
}
}).then(successHandler, errorHandler);
//try to avoid the deprecated success / error functions
function successHandler(response){
$scope.value = response;
}
function errorHandler(response){
//I strongly consider this for debugging
console.log(response);
}
Third: Consider accepting a standard Dictionary<string, string> in the WebAPI controller since the new object shouldn't be a list of dictionaries but rather a flat dictionary. (this answer may provide more context)
Finally: It looks like routing might be confused judging from the error messages; ensure that there is a route setup in the WebApiConfig.cs similar to:
RouteTable.Routes.MapHttpRoute("GetPoliciesBySearch",
"api/getpoliciesbysearch",
defaults: new
{
controller = "{your controller name here}",
action = "GetPoliciesBySearch"
});
Related
I am using Newtonsoft.Json to deserialize a JSON object to a model. One of the strings in my object is:
mQvhIBYwGVtLQYtoSgUsHBxcvRcRiOpb94zqwYPF8Cz1scPia1pR4BgGZ2ThPv+NhXGlLFK/ZbHy/b3YzjKwBw==
I am finding that after RequestFolioDetailModel requestFolioDetailModel = JsonConvert.DeserializeObject(criteria); within the controller the value of User.SessionId is removing the '+' and saving the value with a space instead of the '+'.
Just to add this is a MVC Application. I do a Ajax call to the controller passing through a criteria and then serialise it into an object. See code snippets below:
Code
Javascript function:
function GetNotesForCustomer() {
var data = {
FolioId: gModel.SearchPageModel.Body.VfolFolioId,
User: {
SessionId: 'mQvhIBYwGVtLQYtoSgUsHBxcvRcRiOpb94zqwYPF8Cz1scPia1pR4BgGZ2ThPv+NhXGlLFK/ZbHy/b3YzjKwBw=='
},
Note: {
Voided: '0'
}
};
$.ajax({
url: gBaseUrl + 'Home/SearchCustomerNotes',
type: 'post',
cache: false,
async: true,
data: "criteria=" + JSON.stringify(data),
beforeSend: function () {
//Do Something
}, complete: function () {
//Do Something
},
error: function (result) {
//Do Something
},
success: function (result) {
//Do Something
}
});
}
Controller:
[Route("Home/SearchCustomerNotes/{criteria?}")]
public ActionResult SearchCustomerNotes(string criteria)
{
ActionResult actionResult;
RequestFolioDetailModel requestFolioDetailModel = JsonConvert.DeserializeObject<RequestFolioDetailModel>(criteria);
// do something with request Folio Detail Model
return actionResult;
}
Models:
public class RequestFolioDetailModel
{
public string FolioId {get; set;}
public RequestUserModel User {get; set;}
public RequestNoteModel Note {get; set;}
public RequestFolioDetailModel()
{
User = new RequestUserModel();
Note = new RequestNoteModel();
}
}
}
public class RequestUserModel
{
public string Login {get; set;}
public string Password {get; set;}
public string SessionId {get; set;}
public RequestUserModel()
{
Login = string.Empty;
Password = string.Empty;
SessionId = string.Empty;
}
}
How do I stop it from doing this as I need the + to stay in?
The problem is that you are passing your JSON from client to server as application/x-www-form-urlencoded content (the default content type for jQuery.ajax), but you are not URL encoding it.
The application/x-www-form-urlencoded content type requires the body of the request to contain URL encoded key-value pairs separated by & characters, just like in a URL query string. When the MVC server sees this content type, it applies a URL decode operation on each pair in the body, which will cause + characters to turn into spaces if the data is not properly encoded.
The quick fix, of course, is to encode your JSON string on the client side just after stringifying it:
$.ajax({
url: gBaseUrl + 'Home/SearchCustomerNotes',
type: 'post',
cache: false,
async: true,
data: "criteria=" + encodeURIComponent(JSON.stringify(data)),
...
});
However, since your data is actually JSON, a better solution is to actually send it as application/json content and take advantage of the built-in deserialization that the MVC framework provides. To do this, you need to make a couple of adjustments to your code on both client and server. On the client side, add a contentType specifier to your ajax call specifying the data is application/json. Then, remove the criteria= part from the data string. You do not need to do any URL encoding with this content type. Here is what the client side code would look like:
$.ajax({
url: gBaseUrl + 'Home/SearchCustomerNotes',
type: 'post',
cache: false,
async: true,
contentType: "application/json",
data: JSON.stringify(data),
...
});
On the server side, change your method to accept a RequestFolioDetailModel object directly. You can remove the DeserializeObject call from the body of the method, since the MVC framework will take care of deserializing the object for you. And of course, you need to adjust your Route attribute to remove the criteria part. You may also want to add HttpPost to it while you're at it.
[HttpPost, Route("Home/SearchCustomerNotes")]
public ActionResult SearchCustomerNotes(RequestFolioDetailModel requestFolioDetailModel)
{
// do something with request Folio Detail Model
...
}
Currently I can to create models regularly (by going SettingProfile/Create)
But when I try to use AJAX to send data wrapped in settingProfile JS object it returns HTTP 500 Internal Server Error error, I believe problem is in the data type. What would be correct way of calling Create method in AJAX?
My code:
Model:
public class SettingProfile
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Name { get; set; }
public long? UserId { get; set; }
public string Url { get; set; }
}
View (JS):
function saveSettingProfile() {
var name = prompt("Please enter profile name", "");
var url = $("form").serialize(); // Not AJAX url, its a variable in model
var settingProfile = {
Name: name,
Url: url
};
jQuery.ajax({
url: "#Url.Action("Create", "SettingProfile")",
contentType: "application/json; charset=utf-8",
dataType: "json",
method: "POST",
data: settingProfile
}).done(function (response) {
alert("Profile saved successfully");
}).fail(function () {
alert("Could not save profile");
});
}
Controller:
[HttpPost]
//[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Name,Url")] SettingProfile settingProfile)
{
settingProfile.UserId = 8; // TODO: get user id from session
if (ModelState.IsValid)
{
db.SettingProfiles.Add(settingProfile);
db.SaveChanges();
return Json(new { success = true });
}
return Json(new { success = false });
}
500 error means, your server code is crashing. It could be of many reasons. One thing i noticed (which might cause a 500 error) is the way you are sending data.
You specified the contentType as "application/json" .But you are sending the javascript object as it is. So your request payload will be sent as something like
Name=SomeNameValue&Url=SomeUrlValue And with your current server code, the model binder cannot map it to an object of SettingProfile.
The solution is to send the stringified version of your javascript object. You may use the JSON.stringify method to do so.
jQuery.ajax({
url: "#Url.Action("Create", "SettingProfile")",
contentType: "application/json; charset=utf-8",
method: "POST",
data: JSON.stringify(settingProfile)
}).done(function (response) {
alert("Profile saved successfully");
};
Now your client code will send a request payload like
{"Name":"SomeName","Url":"SomeUrl"}
and model binder will be able to map it properly.
If it is simple data, you can simply not mention a custom contentType and send the js object as it is. jQuery will use the default contentType value which is "application/x-www-form-urlencoded" and model binding will work.
So the below code will work fine.
jQuery.ajax({
url: "#Url.Action("Create", "SettingProfile")",
method: "POST",
data:settingProfile
})
You may also check the browser's network tab and see the response coming back from the server for that ajax call. If an exception happens, you can see the details there.
I am using Web Api.
I have an object of type A. when I return a list of type A to my client and then pass the list of type A back using a Post method the JSON serialisation and deserialisation is done automatically form me.
Because I want to pass multiple parameters using my POST method I have created a wrapper object with properties for each of the parameters I want to pass in. The JSON ser / DeSer is taken care of for this wrapper object, but how do I deserialise the JSON that represents my list of Type A within the wrapper object?
Thanks.
Added Code:
public class ConfigurationUpdateMessage
{
public string IpAddress { get; set; }
public List<object> Configurations { get; set; }
}
The Post method
public string PutUpdateConfigurations(ConfigurationUpdateMessage configMessage)
{}
Client Code
$scope.UpdateConfigs = function () {
$.ajax({
url: 'api/configurations',
dataType: "json",
type: "PUT",
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ IpAddress: "127.0.0.1", Configurations: $scope.configs }),
async: true,
processData: false,
cache: false,
success: function (data) {
},
error: function (xhr) {
}
});
};
PRE: Can you post some code?
If your wrapper object contains properties which match the types of the serialized objects the model binder should automatically deserialize them into the matching properties. Unless there's something wrong with the structure of the JSON you're POSTing.
You should create your same wrapper type on server-side.
For example:
public class OperationDTO
{
public string Parameter1 { get; set; }
public int Parameter2 { get; set; }
public IEnumerable<A> MyList { get; set; } //List<A> will also work too
}
Your Web Api action should look like this:
[HttpPost]
public IHttpActionResult Operation([FromBody] OperationDTO)
{
//...
}
I have seen similar case to mine answered but I have specific need that always differed from others problem.
I am sending json data from my html page to the MVC Web API. Unfortunately the data I am receiving is ALWAYS null (I have tried a lot of different things here). The thing is I really need to received the data as json (string), because my data is very complex and cannot be simply deserialized by the Web API (I have my own custom deserializer that does it).
Heres the code!
First, the web api controller that will receive the ajax post request
public class ActivityController : ApiController
{
// POST api/activity
public string Post([FromBody]string json)
{
}
}
Then, the ajax request itself
$.ajax("/api/activity", {
contentType: "application/json",
data: { json: ko.mapping.toJSON(fusionedModel) },
type: "POST",
success: function (result) {
...
}
});
As far as the data is concerned, it is rendered well (I've used that same request with MVC (not Web Api) and the server was receiving the string perfectly... now for some reason, in my web api controller, the "json" param is ALWAYS null. As I said before, it is IMPORTANT that I receive the data as a json string.
EDIT : I found that my question is a duplicate of this one : POST JSON with MVC 4 API Controller
But I really don't like the answer... having to create an object just to encapsulate the string is very dirty...
I recommend you avoid using standard body parameter binding as that mechanism assumes that you are trying to deserialize the body into a CLR object. Try this,
public class ActivityController : ApiController
{
// POST api/activity
public async Task<HttpResponseMessage> Post(HttpRequestMessage request)
{
var jsonString = await request.Content.ReadAsStringAsync();
return new HttpResponseMessage();
}
}
If you really want to use parameter binding, you can do this.
public HttpResponseMessage Post(JToken jToken)
{
return new HttpResponseMessage()
{
Content = new StringContent(jToken.ToString())
};
}
Please try to use the [HttpPost] Attribute that can be located on System.Web.Http;
public class ActivityController : ApiController
{
// POST api/activity
[HttpPost]
public string Post([FromBody]string json)
{
}
}
I could be wrong here, but it looks like you haven't included your action in the post URL. Try changing
$.ajax("/api/activity", {
contentType: "application/json",
data: { json: ko.mapping.toJSON(fusionedModel) },
type: "POST",
success: function (result) {
...
}
});
To
$.ajax("/api/activity/POST", {
contentType: "application/json",
data: { json: ko.mapping.toJSON(fusionedModel) },
type: "POST",
success: function (result) {
...
}
});
I am having problems passing a javascript array to an MVC3 controller, not sure what I am doing wrong but this code does work with standard WCF service.
$(function () {
$("button").click(function () {
Poster();
});
});
function Poster() {
var data = [];
data.push(new WidgetProperty("test1", "value1"));
alert(data.length);
$.post("Home/Test", {test : data});
}
function WidgetProperty(name, value) {
this.Name = name;
this.Value = value;
}
and controller is
[HttpPost]
public ActionResult Test(WidgetProperty[] test)
{
return View("About");
}
public class WidgetProperty
{
public string Name { get; set; }
public string Value { get; set; }
}
Any ideas why the object that comes to the controller has null values for the properties? Checked with fiddler and it appears it passing the correct values.
Thanks!
You should use JSON.stringify() on your data before you post it, and since you know the data type is JSON, it is best to specify that the data being posted is JSON.
$.post("Home/Test", {test : JSON.stringify(data) }, "json");
Live DEMO
Edit:
I researched this a little more and it seems that you need to include contentType: "application/json" in order for this to work in mvc3:
$.ajax({
type: "POST",
url: "Home/Test",
data: JSON.stringify(data),
success: function(data){},
dataType: "json",
contentType: "application/json"
});