Angular $http post returning empty data - angularjs

I'm managing to post to the server OK, I'd like to get the updated data and load it back into the same JSON object, but the data response is null.
$scope.saveDetails = function() {
$http({
method : 'POST',
url : '/service/rest/orders',
data : $scope.orderDetails
})
.success(function(data, status) {
$scope.orderDetails = data;
})
.error(function() {
alert('error');
});
}
Also worth mentioning, that the initial object is being passed from another controller via $rootscope and injected into the local scope.
$scope.orderDetails = $rootScope.newOrder;
Thanks for any help.

Your code looks fine, I would be checking the backend to make sure data is actually being sent. Another option would be to use the chrome inspector and check the response to make sure you are actually getting something back.

It turns out it was returning the whole object and the order was deeper down, I didn't see that in my console at first.
$scope.orderDetails = data.order;
Thanks for all replies.

In case anyone else runs into this, in my case I had a class with a data contract attribute applied:
[DataContract(Namespace = "http://somespace.com")]
And my class members had not been given the [DataMember] attribute. Web API was not returning back the data. I added the [DataMember] attribute and it fixed it.
[DataMember] public int NumberUpdated { get; set; }
[DataMember] public int NumberInserted { get; set; }
[DataMember] public List<ServicesListImport> InvalidRows {get; set;}

Related

ASP.Net Web Api, POST multiple objects

I have this AngularJS Http Call
$http({
method: "POST",
url: Helper.ApiUrl() + '/Api/Case/SendCase',
data: { obecttype1, obj2, obj3},
}).then(function mySuccess(response) {});
Ant this ASP.net Web Api method
[HttpPost]
[Route("Api/Path/SendCase")]
public int SendCase(object application)
{
string applicantName = ((Newtonsoft.Json.Linq.JObject)application)["applicant"].ToString();
obecttype1 obj = JsonConvert.DeserializeObject<obecttype1>(((Newtonsoft.Json.Linq.JObject)application)["obecttype1"].ToString());
.........................
return ID;
}
This works pretty well, but I feel it is a bit dirty because I am parsing my objects in my method, so my question is
Is the are way to send multiple objects as params in a POST method, I would prefer to avoid modifying my model, avoid creating a class for this
So my Api Method would look like this
public int SendCase(class1 obecttype1, class2 obj2, class3 obj3)
"Is the are way to send multiple objects as params in a POST method, I would prefer to avoid modifying my model, avoid creating a class for this"
By design HTTP Post can only have one body and web api will try to cast the body to the parameter defined in the method signature. So sending multiple objects in the body and trying to match these against multiple params in the method signature will not work. For that you need to define a class which holds the other classes and match the body signature.
public class postDTO
{
public class1 class1Data { get; set; }
public class2 class2Data { get; set; }
public class3 class3Data { get; set; }
}
//The api signature
public int SendCase(postDTO application)
If you still don't want to add the new class then I would use the JObject directly as the parameter as this
[HttpPost]
public int SendCase(JObject jsonData)
{
dynamic json = jsonData;
JObject class1DataJson = json.class1Data;
JObject class2DataJson = json.class2Data;
JObject class3DataJson = json.class3Data;
var class1Data = class1DataJson.ToObject<class1>();
var class2Data = class2DataJson.ToObject<class2>();
var class3Data = class3DataJson.ToObject<class3>();
}
1. Define models for the parameters
public class ClassType1
{
public int Num1 { get; set; }
public string Str1 { get; set; }
}
public class ClassType2
{
public double Test2 { get; set; }
}
2. Use the models as the parameters on the API controller method
// Sorry this example is setup on .Net Core 2.0 but I think the previous
// versions of Web Api would have similar/same behavior
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpPost]
public void Post(ClassType1 ct1, ClassType2 ct2)
{}
}
3. When posting, your objects inside the data {} have to have the keys that match the parameter name you defined on the Controller method
jQuery ajax
$.ajax({
method: 'post',
url: 'http://localhost:53101/api/values',
dataType: 'json',
data: {
// It takes key value pairs
ct1: {
num1: 1,
str1: 'some random string'
},
ct2: {
test2: 0.34
}
}
});
To summarize, yes you can post multiple objects back to the server, as long as
You define a key for each object and the key has to match the parameter name you define on the server method.
The object structure has to match.
-- update --
Just as a proof, here is the screenshot:
We have an app that uses DefaultHttpBatchHandler to accept multi-part POST requests. I believe it to be a bit clunky for many reasons but it is the built-in way to accept multiple objects on a single request in a structured fashion.
https://msdn.microsoft.com/en-us/library/system.web.http.batch.defaulthttpbatchhandler(v=vs.118).aspx
As for the script to create something, that I don't know about. Our callers that use this API are C# services that can create the multi-part requests using a simple client library we provide to help them do just that.

Passing complex object from angular service to MVC controller

I am trying to pass complex object from angular service to MVC controller. Below is the code-:
Angular Controller
$scope.saveData = function () {
var resultData = new Object();
resultData.Name = $scope.Name;
resultData.Address = new Object();
resultData.Address = $scope.Address;
resultData.Address.Contact = $scope.Address.Contact;
var promiseOrganization = AngularService.saveResult(resultData);
promiseOrganization.then(function (result)
{
alert("Saved successfully.");
}
)
}
Angular Service
this.saveResult = function (resultData) {
return $http.post("/Form/SaveData/" + resultData);
}
MVC Controller
[System.Web.Http.HttpPost]
public string SaveData([FromBody] resultData data)
{
//operation to perform
return "Data Reached";
}
When I try passing complex object from Angular service to mvc controller. It gives me null i.e. object becomes null.
Please suggest.
When using the $http.post method you need to pass the data object as the second paramenter. You can read up on it here
So your angular code should look like
$http.post("/Form/SaveData/", data);
You then need a server side representation of the data you are passing the WebApi controller
public class MyCustomObject
{
public string Name { get; set; }
public MyCustomAddress Address { get; set; }
}
public class MyCustomAddress
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Contact { get; set; }
}
You need to update your WebApi controller code to use the new server side class as the parameter. Note that I am not using the [FromBody] attribute as this link explains you only need to use the [FromBody] attribute when you want to force Web API to read a simple type from the request body(your type is a complex type)
To force Web API to read a simple type from the request body, add the [FromBody] attribute to the parameter
Updated WebApi Controller code without the [FromBody] attribute:
[System.Web.Http.HttpPost]
public string SaveData(MyCustomObject data)
{
//operation to perform
return "Data Reached";
}
Change your post function to something like this,
$http.post('/Form/SaveData/', resultData)
.success(function (data, status, headers, config) {
})
.error(function (data, status, headers, config) {
});
You are wrong in your post command. It should be:
$http.post("/Form/SaveData/",{resultData: resultData});
The problem is you need to add the following header -> 'Content-Type': 'application/x-www-form-urlencoded'
$http.post('/Form/SaveData/', resultData, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}});

Passing Object in get Request to WebAPI 2

selectedLocation is always null on the Server
I am using Angular , what is the proper way of passing object to get method
This is Class that is defined on Server, which is being passed as parameter in get request
public class Location
{
public string LocationName { get; set; }
public string MFGName { get; set; }
}
This is the method in WebAPI that is being called.
[HttpGet]
[ActionName("RenewToken")]
[AllowAnonymous]
[ResponseType(typeof(string))]
public async Task<IHttpActionResult> RenewToken(Location selectedlocation)
{
}
The Captured Request looks like this(In google Chrome Developers Tool)
http://localhost:58146/api/Account/RenewToken?selectedlocation=%7B%22LocationName%22:%22Guad%22,%22MFGName%22:%22Flex%22%7D
What am i doing wrong ?
Okay so from what i got from this
Why do we have to specify FromBody and FromUri in ASP.NET Web-API?
when the parameter of the method is a complex type is looks in the body of the request
since you're using GET the data gets put into the uri instead of the body
couple options you could do are
public async Task<IHttpActionResult> RenewToken(string LocationName, string MFGName)
{
}
you could always change your verb to a post or something that accepts data in teh body
You might try changing your get in angular to something like
$http({
method: "GET",
url: "/api/Account/RenewToken",
params: {
LocationName: "Guad",
MFGName: "Flex"
}
})
which will parameterize the data

Web Api 2 with two method with the same HTTP verb an angularjs resources

I have this controller:
public class SeguiAttivazioneController : ApiController
{
[HttpGet]
public IHttpActionResult DoWork1()
{
...
return Ok();
}
[HttpGet]
public IHttpActionResult DoWork2()
{
...
return Ok();
}
[HttpGet] //I would like to have a search with GET verb, but I cannot validate my ModelState with dataAnnotation
public IHttpActionResult AnotherSearch(string filter1, string filter2, ...)
{
if (ModelState.IsValid)
{
...
return Ok();
}
return BadRequest(ModelState);
}
[HttpPost]
public IHttpActionResult DoSearch(SearchFilter filters)
{
if (ModelState.IsValid)
{
...
return Ok();
}
return BadRequest(ModelState);
}
[HttpPost]
public IHttpActionResult SubmitForm(FormData data)
{
...
return Ok();
}
}
As you can see I have two methods with same HttpVerbs (2 for GET and 2 for POST)... I don't know if I am violating REST principles... If so, I would like to avoid...
In this moment I am using AngularJs + NgResources to call my Controller..
public_area
.factory("SeguiAttivazioneService", function ($resource) {
//return {
// seguiAttivazione: $resource("/api/SeguiAttivazione/", null,
// {
// 'get2': { method: 'GET', url: '/api/SeguiAttivazione/GetActivationStatus2' }
// })
//};
return {
seguiAttivazione: $resource("/api/SeguiAttivazione/")
};
});
I am trying to do a GET:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
var request =
new SeguiAttivazioneService
.seguiAttivazione()
.$get({ }, getActivationStatusSuccess, getActivationStatusError);
}
};
But (correctly) I obtain an "Internal Server Error 500", because I have to GET method. How Can I solve this problem? (I suppose I will have same problem with POST too)
Thank you
UPDATE
Here the class of the filters
public class SearchFilter
{
[Required(ErrorMessage="")]
public string CodiceFiscale { get; set; }
[Required(ErrorMessage = "")]
[RegularExpression(#"^(?:\d{11,16})|(?:[a-zA-Z]{6}[a-zA-Z0-9]{2}[a-zA-Z][a-zA-Z0-9]{2}[a-zA-Z][a-zA-Z0-9]{3}[a-zA-Z])$", ErrorMessage = "Codice Fiscale o Partita IVA non validi")]
public string CodiceRichiesta { get; set; }
}
With this class I can use data Annotation to validate my model... If I do a GET Method I cannot use data annotation validation anymore...
Here is some explanation about a the REST Endpoints.
In REST we are manipulating ressources. As collections or individual.
Classics endpoint would be :
GET /rest/houses DATA : none -> will return a collection of houses
GET /rest/houses/{id} DATA : none -> will return the house find by its {id}
POST /rest/houses DATA : {"street":"3 bdv NY-city"} -> will create a new house object with the given data
PUT /rest/houses/{id} DATA : { "id":"{id}", "street":"4 bvd NY-city"} -> will update the whole house ressource find by its {id}
PATCH /rest/houses/{id} DATA : { "street":"4bvd NY-city" } -> will update the given fields of the house ressource find by its {id}
DELETE /rest/houses/{id} DATA : none -> will delete the house ressource find by its id.
There is too much things to know about restfull API that i can't give you all the keys. But try to find some good articles on the subjects such as :
http://www.restapitutorial.com/index.html
Not sure if this answer your question, but i hope it'll help you.
EDIT 1 :
Since i have to add some point about a restfull way to give some complicated action i'll give you the restfull url way to go.
In a restful world (extremely rare) you know only one entry point of your rest API let say this :
GET /rest/
This uri will respond you will all the services that the api can provide
Exemple :
{
"resources":"/rest/ressources",
"apiInfo" : "/rest/api/info"
}
To get your ressources informations you'll follow the link
GET response.resources
I may respond something like :
{
"houses":"/rest/ressources/houses/",
"cars" :"/rest/ressources/cars"
}
Now we want the houses
GET response.houses
Response :
{
"fields":[{
"constructionYear","street"
}],
"search":"/rest/houses"
"create":"/rest/houses"
}
etc... And at this place you can add some non restful endpoints. In a restful way. This action will be hold by a restful resource. Somes API that are using this kind of great Restful.
Standard Rest API :
https://developers.soundcloud.com/docs/api/reference#users
Restful API :
https://www.salesforce.com/us/developer/docs/api_rest/
The question is that the Web API infrastructure must have a way to choose one of the possible methods.
One way is changing the Web API route configuration, including an /{action}/ segment. If you do so it will work exactly like MVC, and you have to always include the action name.
The other way is making the received parameters different in each method, so that the Web API infrastructure can discover which method you're trying to invoke. You can read this answer I've written today for a similar question: How can I add multiple Get actions with different input params when working RESTFUL?.
As a final comment in that answer I say that the parameters can be also discerned by using route contraints.
The first solution of having to include the action name in all invocation is not RESTful, but do you need or prefer it to be RESTful for any particular reason?

how to perform a save operation with breeze and angular without using EF context

Within my project I am trying to perform a save operation that updates my Breeze model as well as passes the updated object to my webAPI. In this project I am not using EF context as the project has been modeled to work with other interfaces. So within my webAPI class I have the following:
[BreezeController]
public class ReportLibraryApiController : ApiController
{
readonly long userid = 1;//testing
readonly IReportLibraryManager manager = new ReportLibraryManager();//interface
//method for share
[Route("reportlibrary/SetReportShare/")]
[HttpPost]
public DTOs.Report SetReportShare(JObject report )
{
//within here I plan to unwrap the JSobject and pull out the necessary
//fields that I need
DTOs.Report updatedreport=null;
//manager.ShareReport(updatedreport.ReportId);
//manager.UnShareReport(updatedreport.ReportId);
return updatedreport;
}
}
The Report Object looks like this
public class Report
{
public Int64 ReportId { get; set; }
public string ReportName { get; set; }
public string ReportDescription { get; set; }
public DateTime? ReportDateCreated { get; set; }
public string ReportOwner { get; set; }
public IEnumerable<ReportLabel> ReportLabels { get; set; }
public bool IsShared { get; set; }
public bool IsFavorite { get; set; }
}
From my angular service I am trying to call the save operation as:
app.factory('reportLibraryService', function(breeze, model){
var serviceName = "reportlibrary/";
var ds = new breeze.DataService({
serviceName: serviceName,
hasServerMetadata: false,
useJsonp: true,
});
var manager = new breeze.EntityManager({ dataService: ds });
model.initialize(manager.metadataStore);
function returnResults(data){ return data.results}
function setReportShare(report) {
var option = new breeze.SaveOptions({ resourceName: 'SetReportShare' })
return manager.saveChanges(null, option).then(returnResults)
};
}
I realize the return results may not be correct but at this point I am just trying to call the save operation in the API. When I run the code everything executes but the save/setting of the share does not fire. A secondary question is I'm still not clear on how the breeze model is updated? Am I supposed to issue a new query from the api and pass that back or is there a way to update the cached object. I'm new to breeze (obviously) and trying to figure out where to look.All the examples I have seen thus far use EF context to perform these actions. However in my case I don't have that option.
Should breeze be making the call or since I am not using EF should I be using $http directive to push the object up. then return a new object to breeze for binding? (that seems a little heavy to me and now how it is designed to work).
I'd appreciate any guidance, or information or how to figure this out.
Edited for more information...
Here is a little more detail based on some of the questions posted by Ward to my original question:
where is your metadata that you code says is not on the server?
The solution I am working on does not expose the EF context this far our. As a result interfaces have been created that handle the queries etc within the project. As a result I don't have the ability to use EF. Very similar to the Edmunds sample. I created a meta definition in the web project which references a report object I have defined. This class is much different from what is returned from the DB but it represents what the UI needs. I created two models
report.cs
public class Report
{
public Int64 ReportId { get; set; }
public string ReportName { get; set; }
public string ReportDescription { get; set; }
public DateTime? ReportDateCreated { get; set; }
public string ReportOwner { get; set; }
public IEnumerable<ReportLabel> ReportLabels { get; set; }
public bool IsShared { get; set; }
public bool IsFavorite { get; set; }
}
model.js
app.factory('model', function () {
var DT = breeze.DataType;
return {
initialize: initialize
}
function initialize(metadataStore) {
metadataStore.addEntityType({
shortName: "Report",
namespace: "Inform.UI.DTOs",
dataProperties: {
reportId: { dataType: DT.Int64, isPartOfKey: true },
reportName: { dataType: DT.String },
reportDescription: { dataType: DT.String },
reportDateCreated: { dataType: DT.String },
reportOwner: { dataType: DT.String },
reportLabels: { dataType: DT.Undefined },
isShared: { dataType: DT.Bool },
isFavorite: { dataType: DT.Bool }
},
navigationProperties: {
labels: {
entityTypeName: "Label:#Inform.UI.DTOs", isScalar: false,
associationName: "Report_Labels"
}
}
});
metadataStore.addEntityType({
shortName: "ReportLabel",
namespace: "Inform.UI.DTOs",
dataProperties: {
labelId: { dataType: DT.Int64, isPartOfKey: true },
reportId: { dataType: DT.Int64 },
labelName: { dataType: DT.String },
isPublic: { dataType: DT.Bool },
reports: { dataType: DT.Undefined }
},
navigationProperties: {
labels: {
entityTypeName: "Report:#Inform.UI.DTOs", isScalar: false,
associationName: "Report_Labels", foreignKeyNames: ["reportId"]
}
}
});
}
})
why are you configuring useJsonp = true ... and then POSTing to the SetReportShare endpoint?
The dataservice was originally defined for GET requests for querying/returning results to the client. I reused the dataservice and tacked on the POST event. Based on your comment though I assume this is a no-no. In looking at the project I am working within the same domain (and always will be) so I don't really think I need jsonp as part of the dataservice definition. Am I wrong in thinking that?
I gather from your question that I should have a separate dataservice for POST's and a separate one for GET's
why is it returning the DTOs.Report type when you can tell by looking at the standard Breeze SaveChanges method that it returns a SaveResult?
This was a typo on my part. The save Result was originally defined as just a JObject. My intent is to return (if necessary) an updated Report object. However I am unsure of the best practice here. If the client (breeze) is updating the cache object. Why do I need to return the report object. Would it not be better to just return a success fail result or boolean of some sort vs. returning an entire report object?
why is your client-side saveChanges callback treating the response as if it came from a query?
This is very simple as you stated, I have no idea what I am doing. I am certainly diving into the deep end as I don't have a choice right now... My question here is when you perform a CRUD operation are these not wrapped in a promise as when performing a query? Or is the promise only important for queries?
Thank you again-
-cheers
You're jumping into the deep end w/o knowing how to swim.
You haven't explained why you're going exotic. That's OK but you want to ease into it. I strongly recommend that you start with the "happy" path - Web API, EF, SQL Server - and then unwind them slowly as you start to understand what's going on.
If you can't do that, at least look at the NoDb sample which doesn't use EF or SQL Server (see the TodoRepository).
You absolutely can do what you're striving to do ... once you know how ... or find someone who does.
At this point, you've created nothing but questions. For example,
where is your metadata that you code says is not on the server?
why are you configuring useJsonp = true ... and then POSTing to the SetReportShare endpoint?
why is it returning the DTOs.Report type when you can tell by looking at the standard Breeze SaveChanges method that it returns a SaveResult?
why is your client-side saveChanges callback treating the response as if it came from a query?
As for your questions:
the breeze model is updated automatically when the save completes
no, you don't issue a new query from the api
yes, you can (and usually do) return the server-updated object back in the SaveResult.
$http (a method not a directive) is used by Breeze itself to communicate to the server; using it directly isn't going to change anything.
Not sure any of my answers help. But I do think you'll be fine if you take it from the top and work deliberately forward from one thing you understand to the next.

Resources