customerLogin is object that I want to send to my service.
I do not want to use query string and do not want parameters separately.
Below is the code:
var config = {
customerLogin : { // object I intend to send
'EmailID': $scope.existingCustomer.email,
'PhoneNumber': $scope.existingCustomer.phoneNumber,
'Passkey': $scope.existingCustomer.password
}
}
$http.get(existingCustomerUrlConstant, config).
In webapi, i have below code:
[HttpGet]
// customerLogin object i want to receive here
public CustomerLogin GetCustomer(CustomerLogin customerLogin)
{
GetCustomerDAL getCustomerDAL = new GetCustomerDAL(customerLogin);
return customerLogin;
}
customerLogin is null here.
How can i receive object here from Angular service call?
Using POST method is the right call. As I stated in the comment.
Related
I am just learning on how to use Web API with angular but I am having a few issues on retrieving data and I would appreciate it if someone could help me.
I have a controller called GetUserController with the following methods.
public class GetUserController : ApiController
{
[HttpGet]
public string GetUserName()
{
var user = "John Doe"
return user;
}
[HttpGet]
public string GetUserName2()
{
string user = "Jane Doe";
return user;
}
}
//Angular side of things
function getUser() {
return $http.get('/api/GetUser').then(function (data) {
return data;
});
}
The above code works fine and and returns the first user from the controller . however when I try to get the second by using the below angular code:
function getUser() {
return $http.get('/api/GetUser/GetUserName2').then(function (data) {
return data;
});
}
This does not work for some reason it says it can't find the GetUserName2 method. Am I missing something ? Please help?
EDIT: The error i'm getting is : Multiple actions were found that match the request
As #shammelburg has pointed out, this is as a result of Web.API not being able to match your request to a controller/method.
It's not so much that it's not RESTful, and has nothing to do with the verb you are using... it's just that an appropriate route map was not found.
Per the accepted answer, you can add another generic route map to enable the method of access you are attempting, however a more specific option exists using attribute routing:-
public class GetUserController : ApiController
{
[Route("api/getuser")]
[HttpGet]
public string GetUserName()
{
var user = "John Doe"
return user;
}
[Route("api/getuser/getusername2")]
[HttpGet]
public string GetUserName2()
{
string user = "Jane Doe";
return user;
}
}
And to enable the use of attribute routes, add this to your WebApiConfig class:-
config.MapHttpAttributeRoutes();
This method allows you to setup specific custom mappings of URLs to controllers/methods at the individual method level, without having to make a global route map that may conflict with something else in your application at a later date.
You can find more info on attribute routing here
Whilst the above will resolve the specific issue you are having, there would in practice be a different way to implement the example you gave:-
public class GetUserController : ApiController
{
[Route("api/user/{id}")]
[HttpGet]
public string GetUserName(int id)
{
// this would be replaced with some sort of data lookup...
var user = "unknown";
if (id == 1) {
user = "John Doe";
} else if (id == 2) {
user = "Jane Doe";
} // and so on...
return user;
}
}
In the above, the URL api/user/x where x is a number, e.g. api/user/1 will match the GetUserName method of the GetUserController and pass the number as an argument to the method.
This would be accessed using something like this in Angular:-
function getUser(id) {
return $http.get('/api/user/' + id).then(function (data) {
return data;
});
}
This is caused because it is not a true RESTful call which use HTTP verbs, GET, POST, PUT, DELETE.
The way to get your code to work is by altering your WebApiConfig.cs file.
From:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
To:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
As you can see we've added the {action} to the routeTemplate which makes this very much like a MVC Controller.
This allows you to call your API methods (GetUserName & GetUserName2) name like you are trying to do in your angular $http function.
Example:
return $http.get('/api/GetUser/GetUserName')
return $http.get('/api/GetUser/GetUserName2')
I have 2 classes on Server side.. MyClass1 and MyClass2..
Im creating a JSON object..
var myclass1 = {name:'xyz', id:16};
var myclass2 = {name:'abc', id:17}
and using restangular..
Restangular.one('some url').customPUT({var1:myclass1 , var2:myclass2 });
Im using spring framework to create my REST Services
#RequestMapping(value = "/someurl", method = RequestMethod.PUT) <br>
#ResponseBody
public void someMethod(#RequestBody MyClass1 var1, #RequestBody MyClass2 var2) {
//some code
}
This is the scenario...
But I had read a post on stackOverflow that for 1 request body we can pass (put request) only 1 object.. If so then what is the alternate way...
I can send MyClass2 object through request param (there is an annotation #RequestParam)
ex. Restangular.one('some url').customPUT({var1:myclass1 }, {}, {var2:myclass2 }, {});
But again this gets appended to my URL and i dont want to change my URL..
Please help. Thnx..
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?
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
I need to take in a collection of MyObject on my webApi controller:
[RoutePrefix("api/DoStuffApi")]
public class DoStuffApiController : ApiController
{
[Route("Update/")]
public HttpStatusCode Update(IEnumerable<MyObject> requests)
{
//DO STUFF
}
}
I would need to use the FromBody parameter attribute to get the list normally:
[Route("Update/")]
public HttpStatusCode Update([FromBody] IEnumerable<MyObject> requests)
{
//DO STUFF
}
Is this better than taking in an object with a collection on it?
[Route("Update/")]
public HttpStatusCode Update(MyRequestObject request)
{
//DO STUFF
}
public class MyRequestObject
{
public IEnumerable<MyObject> requests {get;set;}
}
On the second example I can create a JavaScript object or an Angular module that matches the parameter and pass it into the post call on angular.
.factory('setSomething', [
'$http',
function($http) {
return {
var data = new objectsToUpdate(); //my custom object with an array in it
set: function (customerId) {
return $http.post('api/DoStuffApi/Update/', data);
}
}
}
]);
I cannot find any information on how to do this type of thing. The route attributes follow this article.
This just really depends on what your object you want to post looks like. Do you need to send any other data than the array in the POST? If not then using the former solution would be better since otherwise you are just writing useless additional code for you to maintain. So using the former example would be cleaner.
If however you have more data in your post along with the array you should put it all in a special model class in the controller like you do in your second example..
To have angular POST it correctly so the API model binds to the IEnumerable in the first example, you would simply post the array itself instead of having it inside an object.
function($http) {
return {
var data = new objectsToUpdate(); //my custom object with an array in it
set: function (customerId) {
return $http.post('api/DoStuffApi/Update/', data.nameOfArray); // Don't post the object, just the array
}
}
}
This should bind to the IEnumerable just fine if the fields in the model and the array have the same names.