I am using AngularJs and Resources module. I want to do a GET to obtain an object.. to do this GET I do not have to pass simply the ID to the server, but I should pass a complex object with different properties and values..
Here the code I am using:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
$scope.activationStatus =
new SeguiAttivazioneService
.seguiAttivazione()
.$get(
{
request: $scope.activationStatus
}, function () { });
}
};
On server side I have:
[HttpGet]
public IHttpActionResult GetActivationStatus(MyComplexObject request)
{
//I will do something here later...
return Ok();
}
The problem is that "request" arrive on server equals to NULL...
I have solved the problem passing two strings to the server... in this way:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
$scope.activationStatus =
new SeguiAttivazioneService
.seguiAttivazione()
.$get(
{
codiceFiscale: $scope.activationStatus.CodiceFiscale,
codiceRichiesta: $scope.activationStatus.CodiceRichiesta
}, function () { });
}
};
And server side:
[HttpGet]
public IHttpActionResult GetActivationStatus(string codiceFiscale, string codiceRichiesta)
{
return Ok();
}
In this way everything works... but I don't like this solution because I will have more than two input...
And this is a get, not a post (not a save, an update)...
How can I pass a complex object doing a GET?
Thank you...
It's best to use the POST method if you want to send data in the body of the request. While it's possible with Angular, some servers might ignore the body of GET requests.
This approach allows to send complex objects with arrays and sub objects:
Angular:
$http({
url: '/myApiUrl',
method: 'GET',
params: { param1: angular.toJson(myComplexObject, false) }
})
C#:
[HttpGet]
public string Get(string param1)
{
Type1 obj = new JavaScriptSerializer().Deserialize<Type1>(param1);
...
}
This is not an elegant solution but it works using HTTP GET:
$http.get(url + "?" + $.param(obj).replace(/%5b([^0-9].*?)%5d/gi, '.$1'))
It converts the complex object into a string with dot notation to define levels. Most of the server side frameworks like ASP.NET Core can bind it to complex objects.
This is an example of the string I send for a complex object:
StartDate=2021-06-11&EndDate=2021-06-11&TimeRange.TimeFrom.Time=07%3A00&TimeRange.TimeFrom.TimeFrame=AM&TimeRange.TimeTo.Time=10%3A00&TimeRange.TimeTo.TimeFrame=AM
Request body can only be sent by POST. With get you could at best URL Encode the OBJECT and then send it as query string params. But thats not the best solution to post some data to the server
Related
In JavaScript I have the following code:
var form = new FormData();
form.append("SomeParam", value);
...
Here when debugging I see value is null.
The service looks like this:
this.importNonSalaryPacketExcel = function (data) {
return $http(
{
url: ...,
method: "POST",
data: data,
headers: {
'Content-Type': undefined
},
transformRequest: angular.identity
});
};
Web API code looks like this:
[HttpPost]
[Route("api/front/file/importNonSalaryPacketExcel")]
public HttpResponseMessage ImportNonSalaryPacketExcel(ImportNonSalaryPacketExcelParam param)
And the object:
public class ImportNonSalaryPacketExcelParam
{
public string SomeParam { get; set; }
...
Every field is assigned correctly except this one and it is being set to "null" rather than to null.
Can you help me identify possible problem?
Ok, the first simple solution is to check if param is null in javascript and not adding it to forms data at all.
The second problem is that there is custom media formatter involved FormMultipartEncodedMediaTypeFormatter which does not handle this case. I have just downloaded the source of the formatter and added support for this kind of situations.
Hopefully someone can help with this. I building an ionic 2 app which is based on the newer Angular 2, I am familiar with previous versions of Angular, but still trying to figure this whole typescript.
I have my API setup with basic get querystrings (e.g domain.com?state=ca&city=somename)
export class TestPage {
public state: string ='ca';
public city: string = null;
constructor(private http: Http){}
public submit() {
let url = "http://localhost/api";
let payload = {"state": this.state, "city": this.city};
this.$http.get(url, payload).subscribe(result => {
//result
}, err => {
//do something with the error
}
)
}
}
When I execute this it pulls my API url fine and I can get a response back, however none of the querystrings are being sent in the request. Its just sending http://localhost/api. If I console.log the payload its fine.
Ultimately I am trying to get it to do https://localhost/api?state=ca&city=example
Looking at examples I can't really find anything straight-forward on this.
Is it not possible to take a payload on http with this newer version of Angular? The code above is just an example. I have many querystrings, which is why I was hoping to send a payload to it.
Any help or suggestion would be appreciated.
The Http.get method takes an object that implements RequestOptionsArgs as a second parameter.
The search field of that object can be used to set a string or a URLSearchParams object.
An example:
// Parameters obj-
let params: URLSearchParams = new URLSearchParams();
params.set('state', this.state);
params.set('city', this.city);
//Http request-
return this.http.get('http://localhost/api', {
search: params
}).subscribe(
(response) => this.onGetForecastResult(response.json()),
(error) => this.onGetForecastError(error.json()),
() => this.onGetForecastComplete()
);
Documentation: here
I'm using below code to post data to webapi controller but complex data objects are coming as null in the API controller.However, if i pass object at a time i'm seeing results meaning it is sending over the flat objects but not complex objects.Can anyone please guide me what wrong i'm doing here or is there any other way to do this??
below are the data objects and code snippet that i'm using:
Models:
var portfolio={
Accounts:{accountnumber:'',
SSN:'',
..almost 15 fields in this object},
Investments:{ID:'',
totalamount:'',
etc..here also we have more than 10 objects}
Foo: {F1:'',F2:'',F3:''...}
Foo1: {F11:'',F12:'',F13:''...}
}
Angular service:
var get=funtion(portfolio){
return $http.post('/api/values',
JSON.stringify(portfolio),
{
headers: {
'Content-Type': 'application/json'
}
}
)
}
webapi controller:
public class ValuesController : ApiController
{
[HttpPost]
public User Post([Frombody]portfolio model)
{
//logic here
}
}
Json is the http.post() default content type, so there is no need to neither specify that, nor stringify you object.
Assuming you are posting a valid json object, this should suffice:
var get = funtion(portfolio){
return $http.post('/api/values', portfolio);
}
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?
So I turned on network capture in my web browser to have a look at my ajax calls coming out of AngularJS. For every call made, there seems to be two results:
URL|Protocol|Method|Result|Type|Received|Taken
/p/jobs/03512dc8-6f25-49ea-bdff-0028ac2023cb|HTTP|GET|301|text/html|408 B|< 1 ms
/p/jobs/03512dc8-6f25-49ea-bdff-0028ac2023cb|HTTP|GET|200|application/json|0.79 KB|15 ms
It looks like it's attempting to request HTML first, getting a 301 and then requesting the JSON. How can I eliminate the request for HTML? I'm using $resource to do this but I'd also like to see an example for $http.
Also, the receiving framework is NancyFX for .NET. Perhaps there's a header I need to specify to make sure it always returns JSON? I've tried the "Accept" header but it seems to make no difference. It's as if Nancy is always trying to return a View first before switching to JSON.
Javascript code (translated slightly from TypeScript):
$resource(jobUrl, {}, { get: {method: "GET", isArray: false }});
Nancy code:
public class JobService : NancyModule
{
public static readonly string Prefix = "/p/jobs";
WebLogger logger;
public JobService(WebLogger logger)
: base(Prefix)
{
this.logger = logger;
Get[""] = _ => GetJobs();
Get["/{id}"] = _ => GetJob(_.id);
Get["/{id}/nodes"] = _ => GetNodes(_.id);
Get["/{id}/faults"] = _ => GetFaults(_.id);
}
Job GetJob(string id)
{
lock (logger)
{
if (logger.JobGuid != id)
{
Context.Response.StatusCode = HttpStatusCode.NotFound;
return null;
}
return MakeJob();
}
}
Some part of your code will be helpful, but lets try - you have put character / at the end of $resource definition. Angular has asked server for content for directory, server response with header 301 - redirect to file as Angular expects some data response than directory listing.