Hi I have this code to run my api method
export class MessageService {
constructor(private http: Http) {
}
addMessage(textToSend: string) {
return this.http.post("/api/SendMessage", textToSend); //<- Everytime i have some text in textToSend and this is ok
}
}
And after in my Api my param is equals to null
[HttpPost]
[Route("/api/SendMessage")]
public void SendMessage(string msg) //null value
{
//some code
}
Your controller action is accepting a query parameter, not a router parameter or model.
If you want to accept a route parameter, you need to add it to the route.
If you want to pass a model or value in the body, you must mark the parameter with [FromBody] attribute.
[HttpPost]
[Route("/api/SendMessage")]
public void SendMessage([FromBody]string msg)
{
MessageBox MsgBox = new MessageBox();
MsgBox.AddMsgToMsgBox(msg);
}
If you don't define anything, the controller expects the parameter to be passed as query /api/SendMessage?msg=someMessage (which you shouldn't do in a REST service, as it's not very "RESTful"
Possible solution 1:
addMessage(textToSend: string) {
let body = JSON.stringify({ textToSend });
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post("/api/SendMessage/", body, options);
}
// Server side -1
[HttpPost]
[Route("/api/SendMessage")]
public void SendMessage([FromBody]IDictionary<string, string> msg)
{
var textToSend = msg["textToSend"];
}
// Or create a model and use it
//Server side -2
public class Model
{
public string textToSend { get; set; }
}
public void SendMessage([FromBody]Model model)
Possible solution 2:
addMessage(textToSend: string) {
return this.http.post("/api/SendMessage/" + textToSend);
}
[HttpPost]
[Route("/api/SendMessage/textToSend")]
public void SendMessage(string textToSend)
{
//some code
}
try
addMessage(textToSend: string) {
return this.http.post("/api/SendMessage", msg); //<- Everytime i have some text in textToSend and this is ok
}
changed the name of the variable to match the one you are expecting in the controller
Related
I have an ASP.NET MVC Controller defined like so:
[HttpPost]
public string uploadQAImage(FileUploadClass fileUploadClass, HttpPostedFile image)
{
}
And this what the class FileUploadClass looks like.
public class FileUploadClass
{
public string job { get; set; }
public string createdBy { get; set; }
public string itemId { get; set; }
}
What I am trying to do with Alamofire in iOS is call this Controller, I have tried using parameters:
func saveQAPhotos(_ cellHolder: PhotoClass, completion: #escaping (_ result: Dictionary<String, Any>) -> Void)
{
let parameters: Parameters = [
"job" : cellHolder.job!,
"itemId" : cellHolder.itemId!,
"createdBy" : appDelegate.username!
]
let urlComponents = NSURLComponents(string: webservice + "uploadQAImage");
urlComponents?.user = appDelegate.username;
urlComponents?.password = appDelegate.password;
let url = urlComponents?.url;
Alamofire.upload(multipartFormData: { (multipartFormData) in
for (key, value) in parameters {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
if let data = cellHolder.photo {
multipartFormData.append(data, withName: "image", fileName: "image.png", mimeType: "image/png")
}
}, usingThreshold: UInt64.init(), to: url!, method: .post, headers: nil) { (result) in
switch result{
case .success(let upload, _, _):
upload.responseJSON { response in
if let result = response.result.value {
let jsonData = result as! Dictionary<String, Any>
completion(jsonData)
}
}
case .failure(_):
print("error")
}
}
}
But that didn't work on the ASP.NET side I get this error:
can't bind multiple parameters to the request's content
I have also tried sending the data as [AnyHashable: Any] like so:
func saveQAPhotos(_ cellHolder: PhotoClass, completion: #escaping (_ result: Dictionary<String, Any>) -> Void)
{
var jsonDict = [AnyHashable: Any]()
jsonDict["job"] = cellHolder.job
jsonDict["itemId"] = cellHolder.itemId
jsonDict["createdBy"] = appDelegate.username
let jsonData: Data? = try? JSONSerialization.data(withJSONObject: jsonDict, options: .prettyPrinted)
let urlComponents = NSURLComponents(string: webservice + "uploadQAImage");
urlComponents?.user = appDelegate.username;
urlComponents?.password = appDelegate.password;
let url = urlComponents?.url;
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(jsonData!, withName: "fileUploadClass", mimeType: "application/json")
if let data = cellHolder.photo {
multipartFormData.append(data, withName: "image", fileName: "image.png", mimeType: "image/png")
}
}, usingThreshold: UInt64.init(), to: url!, method: .post, headers: nil) { (result) in
switch result{
case .success(let upload, _, _):
upload.responseJSON { response in
if let result = response.result.value {
let jsonData = result as! Dictionary<String, Any>
completion(jsonData)
}
}
case .failure(_):
print("error")
}
}
}
Same error as before
can't bind multiple parameters to the request's content
Now when I change the ASP.NET Controller to only get FileUploadClass like so:
[HttpPost]
public string uploadQAImage(FileUploadClass fileUploadClass)
{
}
I get this error:
Object reference not set to an instance of an object.
I can only assume if I do fix the can't bind multiple parameters to the request's content error I will get this error next.
I am pretty sure I am sending the data incorrectly, so I guess my question is how do I send data from Alamofire upload method to an ASP.NET MVC method?
I am sending an id and a list from angular to C# web API, but it is received by null when debugging the method, without knowing the reason.
angular service
this.deletevacs = function (staffid, vacs) {
return $http.post("/AssignUserToDepartmentapi/api/assignuser/deletevacs?staffid=" + staffid + '&vacs=' + JSON.stringify(vacs))
}
angular js
var result = DevExpress.ui.dialog.confirm("Are you sure want to delete vacations assigned employees ?", "Confirm changes");
result.done(function (dialogResult) {
if (dialogResult) {
var promisePost = Assignments.deletevacs($scope.SelectedEmp1.staffkey, $scope.oldvacs);
promisePost.then(function (pl) {
toastr.success("Successfully deleted");
C#
[HttpPost]
public HttpResponseMessage deletevacs(int staffid,int[] vacs)
{
try
{
obj.ExecNonQuery(string.Format("delete from HR_AssRole_Dep where staff_key={0} and Role=7 and Current_Flag=1 and VacMKey ={1}"
, staffid
, vacs));
}
catch (Exception ex)
{
}
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
any help, thanks in advance
new C#
[HttpPost]
public HttpResponseMessage deletevacs([FromBody] role r)
{
obj.ExecNonQuery(string.Format("delete from HR_AssRole_Dep where staff_key={0} and Role=7 and Current_Flag=1 and VacMKey ={1}"
,r.Staff_Key
, r.VacMKey));
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
class
public class role
{
//public int Ass_Dep_Key { get; set; }
public int Dep_Key { get; set; }
public int Staff_Key { get; set; }
public int Role { get; set; }
public List<int> VacMKey { get; set; }
public short SelfApprov { get; set; }
}
new angular
var deletevacssss = { Staff_Key: $scope.SelectedEmp1.staffkey, VacMKey: $scope.selectedvacs };
var result = DevExpress.ui.dialog.confirm("Are you sure want to delete vacations assigned employees ?", "Confirm changes");
result.done(function (dialogResult) {
if (dialogResult) {
var promisePost = Assignments.deletevacs(deletevacssss);
promisePost.then(function (pl) {
toastr.success("Successfully deleted");
new angular service
this.deletevacs = function (deletes) {
return $http.post("/AssignUserToDepartmentapi/api/assignuser/deletevacs", deletes)
}
when i make a debug, the r object from role class get the staffkey from angular correctly but the list of vacmkey count by 0 ???
you should pass the parameter values for post method in params property .
var data = {staffid: staffid, vacs:vacs};
$http({
url: "/AssignUserToDepartmentapi/api/assignuser/deletevacs",
method: "POST",
params: data
})
or try this below way
var data = {staffid: staffid, vacs:vacs};
$http.post("/AssignUserToDepartmentapi/api/assignuser/deletevacs", data ).then(function (data, status, headers, config) {
alert("success");
},function (data, status, headers, config) {
alert("error");
});
API code should be like
[HttpPost]
public HttpResponseMessage deletevacs([FromUri]int staffid, [FromUri] int[] vacs)
{
...
}
Solution 1:
Use [FromUri] attribute in your HttpPost method parameter since you are getting the value from the querystring in the Url.
Try this:
[HttpPost]
public HttpResponseMessage deletevacs([FromUri]int staffid, [FromUri] int[] vacs)
{
try
{
obj.ExecNonQuery(string.Format("delete from HR_AssRole_Dep where staff_key={0} and Role=7 and Current_Flag=1 and VacMKey ={1}"
, staffid
, vacs));
}
catch (Exception ex)
{
}
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
Solution 2:
Create an object that contains the staffId and vacs properties and assign it to the parameter. Add the [FromBody] attribute to before the object parameter. Then in your httpPost call, put the parameter inside the body of the request instead of the Url.
Google about the use of [FromBody] in webapi.
Solution 3:
Istead of using HttpPost, why not use HttpDelete method. It is clear in your problem that your intention is to delete records. In web API, you can use the HttpDelete attribute instead of HttpPost. To do this, change your attribute to HttpDelete from HttpPost, and in your paramter, you can just pass the [FromUri] int StaffId only and inside your API, all the vacs record related that StaffId, you can delete programmatically in DB. When calling your API use the $http.delete endpoint method instead.
I am using .net core C#, WebApi & AngularJs.
For saving data my Angularjs code makes a $http call to my WebApi. I can return single data from my api fine but not sure whats the best method to return multiple values here. I can make it comma separated and then return as well, but wanted to know if there is a better approach to this.
So basically when the API saves data to my db, I want to return a variable, boolean value if the save was successful and an exception message in case the save was not successfully. Below is my code.
AngularJs Code:
service.saveData(data).then(function (res) {
//get someDataToReturn, dataSaved & exception raised if any from db save here.
}, function (err) {
});
WebApi Code:
[HttpPost("data/save")]
public async Task<IActionResult> SaveData([FromBody] List<UserData> data)
{
bool dataSaved = true;
string someDataToReturn = string.Empty;
//do some processing and updating someDataToReturn here
//Saving data to DB
dataSaved = SaveData(data);
//I want to return someDataToReturn, dataSaved(true or false) and exception raised from SaveData if any
return Ok(someDataToReturn);
}
//DB Call to save data
public bool SaveData(List<UserData> data)
{
try
{
foreach (var set in data)
{
//creating query etc
_db.Execute(query);
}
return true;
}
catch (SqlException ex)
{
}
return false;
}
Let me know the best approach for this.
First of, you should check if the values in your request body is correctly populated.
Take a look at DataAnnotations.
You can use annotations to specify which properties in your model that are Required, Min and Maxlength etc.
Here's an example on how to define a Name property to be required on the UserData class
public class UserData
{
[Required]
public string Name { get; set; }
}
If the request model do not fulfill the specified rules set on the UserData class DataAnnotations, the context ModelState will be set to false and contain the DataAnnotations errors.
This can be used to determind if the current request is a bad request and return a proper http status code from that.
[HttpPost("data/save")]
public async Task<IActionResult> SaveData([FromBody] List<UserData> data)
{
if (!ModelState.IsValid)
return BadRequest(ModelState); //will return a 400 code
...
Then regarding the SaveData method. Capture the exception in the controller and return a proper status code from there
[HttpPost("data/save")]
public async Task<IActionResult> SaveData([FromBody] List<UserData> data)
{
if (!ModelState.IsValid)
return BadRequest(ModelState); //400 status code
try
{
SaveData(data);
}
catch(Exception e)
{
return InternalServerError(e); //500 status code
}
string someDataToReturn = string.Empty;
return Ok(someDataToReturn ); //200 status code
}
public void SaveData(List<UserData> data)
{
foreach (var set in data)
{
//creating query etc
_db.Execute(query);
}
}
You can use the Controller class method Json(object data). Something like:
[HttpPost("data/save")]
public async Task<IActionResult> SaveData([FromBody] List<UserData> data)
{
return this.Json(SaveData(data));
}
See this.
you can create an entity and return it
public class BaseResult{
public bool Result{get;set;}
public string Errors{get;set;}
}
or only
return Ok( new { result = dataSaved , error= exception.Message});
the standard way is:
return 201 status code
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201
[HttpPost("data/save")]
public async Task<IHttpActionResult> SaveData([FromBody] List<UserData> data)
{
try
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
// return response of 201 if you created the resource successfully
// typically return this with a uri to the new resource
return Created("location", saveData(data));
}
catch (Exception)
{
return InternalServerError();
}
}
I'm very confused. I'm using ASP.NET WebApi 2 as rest api and AngularJS for the SPA. My application uses 4 rest requests. but only one doesn't work and I don't know why.
I've defined the process as follows:
Client-side:
//Controller
CrudService.getRepo(selFrom, selTo).$promise.then(
function (response) {
...
},
function (err) {
$log.error('Mth: ', err);
});
//CrudService
function getRepo(selFrom, selTo) {
return ResService.ds022.query(
{
from: selFrom,
to: selTo
}
);
}
//ResService:
function ResService($resource, baseUrl) {
return {
ds022: $resource(baseUrl + '/api/qr_ds022/mth_test', {
from: '#from',
to: '#to'
}, {})
}
}
And on the other hand: Server-side (WebAPI)
[RoutePrefix("api/qr_ds022")]
public class QR_DS022Controller : ApiController
{
private TestContext db = new TestContext();
[HttpGet]
[Route("mth_test")]
public IQueryable<getRep_Result> getRepos(DateTime from, DateTime to)
{
var results = db.getRep(from, to).AsQueryable();
return results;
}
}
The Database model was created with Entity Framework 6. I have no idea where the problem is. As you can see, the route was defined correctly.
Map route one place with function parameter, try this way
public class QR_DS022Controller : ApiController
{
private TestContext db = new TestContext();
[HttpGet]
[Route("api/qr_ds022/mth_test/{from}/{to}")]
public IQueryable<getRep_Result> getRepos(DateTime from, DateTime to)
{
var results = db.getRep(from, to).AsQueryable();
return results;
}
}
I am learning to create a RESTful API with a client, but am struggling with passing user input to the post. My controller is fine as I can send data to db (tested with Swagger) but on the client side the debugger is giving me an error on my PostAsJsonAsync. I think it probably has to do with the routing. Here is my post code from my client:
static async Task AddAsync(ForumPost fp)
{
try
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:7656/");
client.DefaultRequestHeaders.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
ForumPost thePost = new ForumPost() {
Subject = fp.Subject,
Message = fp.Message};
HttpResponseMessage response = await client.PostAsJsonAsync("post", thePost);
if (response.IsSuccessStatusCode)
{
Uri uri = response.Headers.Location;
Console.WriteLine("URI for new resource: " + uri.ToString());
}
else
{
Console.WriteLine(response.StatusCode + " " + response.ReasonPhrase);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Console.ReadLine();
}
}
and the relevant bit of the controller
[HttpPost]
// POST: api/Forum
[Route("post")]
public void PostNewMessage (string subject, string message)
{
if (ModelState.IsValid)
{
ForumPost p = new ForumPost(subject, message);
db.ForumPosts.Add(p);
db.SaveChanges();
}
}
I have looked around at various different but similar questions here on SO but struggling to understand. I have tried putting placeholders in the route but maybe I implemented it incorrectly? (that's if that is even the correct way to be thinking!) If anyone could help me out on this I would appreciate it.
When your Web API action parameters are simple types like strings, the parameter binding mechanism assumes they are coming from the query string. To infer that the values should come from the request body, just use your ForumPost class directly as your parameter instead of the individual string values:
[HttpPost]
// POST: api/Forum
[Route("post")]
public void PostNewMessage(ForumPost p)
{
if (ModelState.IsValid)
{
db.ForumPosts.Add(p);
db.SaveChanges();
}
}
Also note that ForumPost needs a parameterless constructor in order for the framework to know how to create an instance. Define it like this and you should be good:
public class ForumPost
{
public string Subject { get; set; }
public string Message { get; set; }
}