How to call web api Controller method with two parameters using angularjs - asp.net-mvc-4

I am pretty new in angularjs and I've looked around to try to find some posts on this and there are many but none that address my specific question (that I could find).
It is as simple as that, I want to send two parameters through angularjs ($http POST) where my first parameter is a json of class object and second is int. What I tried :
var url = '../Request/'+ id;
$http({
method: 'POST',
url: url,
data: Data
}).success(function (data, status, headers, config) {
deferred.resolve(data);
}).error(function (data, status, headers, config) {
debug.error(data);
deferred.reject('An error occured while saving the request');
});
In my web api Controller I have :
[POST("Request/{id}")]
public bool SaveRequest(Data data, int id)
{
...
...
}
When I send only Data it works for me but when I tried to add Id and Data both it won't work. Please let me know what needs to be done for the same, Thanks.

Have you tried using [FromBody] attribute like this
[POST("Request/{id}")]
public bool SaveRequest([FromBody] Data data,[FromUrl] int id)
{
...
More info on parameter binding

Related

Nestjs: Cannot PUT, Cannot DELETE (404 not found)

I'm on a task to write a simple CRUD program for a users list, following a similar nestjs example. While GET, POST and GET by id works fine, PUT and DELETE does not work properly. I get 'User does not exist' however user exists in database.
Controller
#Controller('users')
export class UsersController {
constructor(private userService: UsersService) {}
.....
//Update a user's details
#Put('/update')
async updateUser(
#Res() res,
#Query('userid') userID,
#Body() createUserDto: CreateUserDto
) {
const user = await this.userService.updateUser(userID, createUserDto);
if (!user) throw new NotFoundException('User does not exist!');
return res.status(HttpStatus.OK).json({
message: 'User has been successfully updated',
user
})
}
//Delete a user
#ApiParam({ name: 'id' })
#Delete('/delete')
async deleteUser(#Res() res, #Query('userid') userID) {
const user = await this.userService.deleteUser(userID);
if (!user) throw new NotFoundException('Customer does not exist');
return res.status(HttpStatus.OK).json({
message: 'User has been deleted',
user
})
}
Service
// Edit user details
async updateUser(userID, createUserDto: CreateUserDto): Promise<User> {
const updatedUser = await this.userModel
.findByIdAndUpdate(userID, createUserDto, { new: true });
return updatedUser;
}
// Delete a customer
async deleteUser(userID): Promise<any> {
const deletedUser = await this.userModel
.findByIdAndRemove(userID);
return deletedUser;
}
I'm using swagger to perform my tests. I'm passing id as a parameter to find and update user.
Based on your code repository, you aren't using URL Parameters, but rather you are using Query Parameters. The difference in the two is how they are passed to the server and how they are told to the server to listen for them.
Query Parameters
With query parameters, you pass them to your server starting with a ? in the url, and concatenating each one after by using a &. An example could look something like http://localhost:3000?name=Test&id=a26408f3-69eb-4443-8af7-474b896a9e70. Notice that there are two Query parameters, one named name and one named id. In Nest, to get these parameters in your route handler, you would use the #Query() decorator. A sample class could look like
#Controller()
export class AppController {
#Get()
getHello(#Query() query: { name: string, id: string }) {
return `Hello ${name}, your ID is ${id}`;
}
}
Notice how with the url above, the route called is the base route (/), with the query parameters added on.
URL Parameters
URL parameters are a way to dynamically build your routes without needing to specify what each possible URL. This is useful for things like IDs that are dynamically generated. Taking a similar URL as above, the sample URL this time could look like http://localhost:3000/Test/a26408f3-69eb-4443-8af7-474b896a9e70. Notice how this time there is no ? or & and it just looks like a full URL. To specify URL Params in nest, you need to a a colon(:) before the param name in the resource declaration decorator, along with any other part of the path necessary. Then to access the URL Parameters, you need to use the #Param() decorator in the route handler, similar to how you would the #Query() decorator. The class sample for this would be
#Controller()
export class AppController {
#Get(':name/:id')
getHello(#Param() params: { name: string, id: string })
return `Hello ${name}, your ID is ${id}`;
}
}
Problem and Solution
You're currently calling off to http://localhost/users/update/<ID> acting as if you are using URL parameters, but in your route handler you are expecting #Query() to grab the id. Because of this, there is no handler to find /users/update/:id and so you are getting a 404 in return. You can either modify your server to listen for URL Parameters as described above, or you can modify the URL to send the request using Query Parameters instead of URL parameters.

Adding a WEB API method ruins my SWAGGER UI

This first method is fine. But when I add the second method the body of the SWAGGER UI is a bunch of html gibberish. And I creating the route the wrong way?
// GET api/checklist/1288
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
var model = _checkListService.Get(id);
return Ok(model);
}
// http://localhost:64783/api/checklist/GetDelinquentItems?id=1288
[Route("GetDelinquentItems")]
public async Task<IActionResult> GetDelinquentItems(int id)
{
var model = _checkListService.GetDelinquentItems(id);
return Ok(model);
}
That 'html gibberish' (indeed not the most elegant way to show an error) still contains some useful information. The first line says:
500 internal server error
and in the last three lines you can read:
Ambiguos HTTP method for action...CheckListController.GetDelinquentItems... Actions require explicit HttpMethod binding for Swagger
therefore another
[HttpGet("{id}")]
before the GetDelinquentItems() method should solve the problem.

Ajax call for JSON using EF Core is failing/aborting

I'm at a loss with why this isn't working...
I have a .NET Core app using EF Core, and I'm making an Ajax call via jQuery to my controller to retrieve some data from the database via EF Core. Debugging the call via my developer tools in the browser (IE/Chrome) results in a status of failed/aborted. Yet when I step through my method in my controller, the method seems to be able to retrieve the data from the database via EF Core just fine.
Here's my controller:
public ActionResult GetInfo(string term)
{
using (var dbContext = new DatabaseContext())
{
// use DbContext to get data from the database
var retrievedData = dbContext.TableName.Where(...);
return Json(retrievedData.Select(data => new {
id = data.id,
text = data.text
}));
}
}
And here's the jQuery:
$(#element).select2({
...
ajax: {
url: $(#element).attr("data-getinfo"),
dataType: 'json', // tried this with jsonp and application/JSON with no luck
contentType: 'application/json; charset=utf-8',
delay: 250,
data: function (params) {
return: { term: params.term};
},
processResults: function (data) {
return {
results: $.map(data, function (item) {
return {
id: item.id, text: item.text
}
})
}
},
},
....
});
The Ajax calls work with previous apps I've worked on, but they used MVC 5 and EF 6. This also works if I retrieve dummy data, IE instead of using EF Core to get the data, I return fake data built into the controller. What gives?
To clarify the root of your problem: You are querying your database and returning an IEnumerable as a JsonResult. But first, you need to understand one step before. Calling .Where returns an IQueryable. You can think of an IQueryable as if it is a TSQL command that was not yet execute on the database. Only calls that will enumerate the results will trigger the materialization of the query.
So you did this:
// .Where returns an IQueryable. You can "chain" more wheres later.
// the query will still not be executed
var retrievedData = dbContext.TableName.Where(...);
// This then returns an IEnumerable to the client.
// The Select will materialize (execute) the query
return Json(retrievedData.Select(data => new {
id = data.id,
text = data.text
}));
The problem with your code is: .Select returns an IEnumerable which enumerates the results. But, by the time the browser or whatever client you are dealing with starts to enumerate the results, your database connection is already closed, because you used using block around your dbContext (which is kind of correct.. see comments in the end).
So, to fix it, you need basically to enumerate the results yourself or not close the connection (let the framework close for you when the request is finished..). This minor change fix the problem:
// ToList() will enumerate all the results in memory
var retrievedData = dbContext.TableName.Where(...).ToList();
Other comments:
You don't need (also shouldn't) manage the creation of the dbContext by yourself. You can register it in the DI container and the framework will do the rest for you. You can take a look in the EF Core docs to have an idea on how it is done.
Not an ideal solution, but I got it working. I suspect it might have to do with how .NET Core or EF Core was returning data to the browser, but I can't say for sure yet.
I ended up using Json.NET for a workaround. Performance isn't bad (I tried a query with hundreds of records and it only took a couple of seconds at most), and I was already using it for an external API call.
public ActionResult GetInfo(string term)
{
using (var dbContext = new DatabaseContext())
{
// use DbContext to get data from the database
var retrievedData = dbContext.TableName.Where(...);
var initJson = Json(retrievedData.Select(data => new {
id = data.id,
text = data.text
}));
var serializedJson = Newtonsoft.Json.JsonConvert.SerializeObject(initJson);
var deserializedJson = Newtonsoft.Json.JsonConvert.DeserializeObject(serializedJson);
return Json(deserializedJson);
}
}

Having trouble making a OAuth 1.0a signed request to the Tumblr API using HelloJS

I'm trying to interface with the Tumblr API to pull a list of followers. I'm brand new the whole OAuth thing, so I was trying to model my calls off the demos at https://adodson.com/hello.js/demos/tumblr.html . Unfortunately, the example they give only requires the API key for identification (https://www.tumblr.com/docs/en/api/v2#posts) where as getting the followers needs a signed OAuth request (https://www.tumblr.com/docs/en/api/v2#followers).
The call I'm using is:
function getFollowers(blog){
hello('tumblr').api('blog/'+blog+'/followers/').then(function(r){
console.log("r", r);
//Bellow here not really relevant
var a = r.data.map(function(item){
return "<h2>"+item.title+"</h2>"+item.body_abstract;
});
document.getElementById('blogs').innerHTML = a.join('');
});
}
This generates the request url from the proxy:
https://auth-server.herokuapp.com/proxy?path=https%3A%2F%2Fapi.tumblr.com%2Fv2%2Fblog%2Fnmlapp.tumblr.com%2Ffollowers%2F%3Fapi_key%3DREDACTED08u%26callback%3D_hellojs_9kvqxi31&access_token=&then=redirect&method=get&suppress_response_codes=truee
and Tumblr's API returns
_hellojs_9kvqxi31({"meta":{"status":401,"msg":"Not Authorized"},"response":[]});
I can see that the login call has all of the OAuth info in the Query String Parameters field, and the one I'm trying to make does not, but I'm not sure what the right way to include that through helloJS is.
Got it, the function had to be wrapped in the login method. This was shown in the other example, but the way that it called parameters from the api object had me confused.
function doTheThing(network){
hello( network ).login({force:false}).then( function(r){
hello('tumblr').api('followers').then(function(r){
console.log("r", r);
var a = r.data.map(function(item){
return "<h2>"+item.title+"</h2>"+item.body_abstract;
});
document.getElementById('blogs').innerHTML = a.join('');
});
});
}
//...
tumblr:{
get: {
//...
//This next part needs to be generated dynamically, but you get the idea
'followers': 'blog/BLOGNAME.tumblr.com/followers',
}
callback(p.path);
}
},
post: {
//...
'followers': function(p, callback) {
p.path = 'followers';
query(p, callback);
}
},

Dojo datagrid jsonrest response headers

I'd like to use custom headers to provide some more information about the response data. Is it possible to get the headers in a response from a dojo datagrid hooked up to a jsonRest object via an object store (dojo 1.7)? I see this is possible when you are making the XHR request, but in this case it is being made by the grid.
The API provides an event for a response error which returns the response object:
on(this.grid, 'FetchError', function (response, req) {
var header = response.xhr.getAllResponseHeaders();
});
using this I am successfully able to access my custom response headers. However, there doesn't appear to be a way to get the response object when the request is successful. I have been using the undocumented private event _onFetchComplete with aspect after, however, this does not allow access to the response object, just the response values
aspect.after(this.grid, '_onFetchComplete', function (response, request)
{
///unable to get headers, response is the returned values
}, true);
Edit:
I managed to get something working, but I suspect it is very over engineered and someone with a better understanding could come up with a simpler solution. I ended up adding aspect around to allow me to get hold of the deferred object in the rest store which is returned to the object store. Here I added a new function to the deffered to return the headers. I then hooked in to the onFetch of the object store using dojo hitch (because I needed the results in the current scope). It seems messy to me
aspect.around(restStore, "query", function (original) {
return function (method, args) {
var def = original.call(this, method, args);
def.headers = deferred1.then(function () {
var hd = def.ioArgs.xhr.getResponseHeader("myHeader");
return hd;
});
return def;
};
});
aspect.after(objectStore, 'onFetch', lang.hitch(this, function (response) {
response.headers.then(lang.hitch(this, function (evt) {
var headerResult = evt;
}));
}), true);
Is there a better way?
I solved this today after reading this post, thought I'd feed back.
dojo/store/JsonRest solves it also but my code ended up slightly different.
var MyStore = declare(JsonRest, {
query: function () {
var results = this.inherited(arguments);
console.log('Results: ', results);
results.response.then(function (res) {
var myheader = res.xhr.getResponseHeader('My-Header');
doSomethingWith(myheader);
});
return results;
}
});
So you override the normal query() function, let it execute and return its promise, and attach your own listener to its 'response' member resolving, in which you can access the xhr object that has the headers. This ought to let you interpret the JsonRest result while fitting nicely into the chain of the query() all invokers.
One word of warning, this code is modified for posting here, and actually inherited from another intermediary class that also overrode query(), but the basics here are pretty sound.
If what you want is to get info from the server, also a custom key-value in the cookie can be a solution, that was my case, first I was looking for a custom response header but I couldn't make it work so I did the cookie way getting the info after the grid data is fetched:
dojo.connect(grid, "_onFetchComplete", function (){
doSomethingWith(dojo.cookie("My-Key"));
});
This is useful for example to present a SUM(field) for all rows in a paginated datagrid, and not only those included in the current page. In the server you can fetch the COUNT and the SUM, the COUNT will be sent in the Content-Range header and the SUM can be sent in the cookie.