AngularJS ngResource POST object is Null in C# Web API - javascript

My problem is that when I send a complete Javascript object to my Web API Controller I always get null values. Even though I have a complete object I need to specify each attribute and value as you can see below. How can I make Web API accept a ready made Javascript object and bind it correctly?
C# Web Api Controller:
[Route("addcredentials/{salesId}")]
[HttpPost]
public IHttpActionResult AddCredentials([FromUri] int salesId, [FromBody] ScriveCredentials credentials)
{
return Ok(credentials);
}
C# Credentials object:
public class Credentials
{
public string ClientIdentifier { get; set; }
public string ClientSecret { get; set; }
public string TokenIdentifier { get; set; }
public string TokenSecret { get; set; }
}
Javascript object passed to resource, saved as "result" further down:
{ClientIdentifier: "a", ClientSecret: "b", TokenIdentifier: "c", TokenSecret: "d"}
Resource method:
addCredentials: {
method: 'POST',
url: 'api/addcredentials/:userSalesId'
}
Usage that results in null values:
userResource.addCredentials({ userSalesId: user.SalesId }, { credentials: result}).$promise.then(function (data) {
console.log(data);
});
Payload for this request:
{"credentials":{"ClientIdentifier":"a","ClientSecret":"b","TokenIdentifier":"c","TokenSecret":"d"}}
Usage that works but seems overly complicated:
userResource.addCredentials({ userSalesId: user.SalesId }, { ClientIdentifier: result.ClientIdentifier, ClientSecret: result.ClientSecret, TokenIdentifier: result.TokenIdentifier, TokenSecret: result.TokenSecret }).$promise.then(function (data) {
console.log(data);
});
Request payload:
{"ClientIdentifier":"a","ClientSecret":"b","TokenIdentifier":"c","TokenSecret":"d"}
Update
Tried the following and it did not work either, null on all values:
addScriveCredentials: {
method: 'POST',
url: 'api/addcredentials/'
result.SalesId = user.SalesId;
userResource.addCredentials({}, { credentials: result }).$promise.then(function (data) {
console.log(data);
});
C#:
[Route("addcredentials")]
[HttpPost]
public IHttpActionResult Addcredentials(Credentials credentials)
{
return Ok(credentials);
}

I had done a sample earlier, hope the follwing code will help you to understand.
The Model.
using System.ComponentModel.DataAnnotations;
public class ProductModel
{
public ProductModel(int id, string name, string category, decimal price)
{
Id = id;
Name = name;
Category = category;
Price = price;
}
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Category { get; set; }
[Required]
public decimal Price { get; set; }
}
The ApiController.
using Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Hosting;
using System.Web.Http;
public class ProductsController : ApiController
{
// other code omitted for brevity.
[HttpPost]
public IHttpActionResult PostProduct(ProductModel product)
{
try
{
if (product == null)
{
throw new ArgumentNullException("Product parameter cannot be null");
}
if (ModelState.IsValid)
{
// code omitted for brevity.
return this.Ok();
}
else
{
throw new Exception("Product is invalid");
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
[HttpPut]
public IHttpActionResult PutProduct(ProductModel product)
{
try
{
if (product == null)
{
throw new ArgumentNullException("Product parameter cannot be null");
}
if (ModelState.IsValid && product.Id > 0)
{
// code omitted for brevity.
return this.Ok();
}
else
{
throw new Exception("Product is invalid");
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
// other code omitted for brevity.
}
The Angular service.
// products.js
(function () {
"use strict";
angular
.module("exampleApp")
.constant("baseUrl", "http://localhost:53631/api/products/")
.factory("productsResource", productsResource);
productsResource.$inject = ["$resource", "baseUrl"];
function productsResource($resource, baseUrl) {
return $resource(baseUrl + ":id",
{
id: "#id"
},
{
create: {
method: "POST"
},
save: {
method: "PUT"
}
});
}
})();
The Angular controller. Focus on createProduct and updateProduct functions below
// edit.controller.js
(function () {
"use strict";
angular
.module("exampleApp")
.controller("EditController", EditController);
EditController.$inject = ["$routeParams", "$location", "productsResource"];
function EditController($routeParams, $location, productsResource) {
var vm = this;
vm.currentProduct = null;
vm.createProduct = createProduct;
vm.updateProduct = updateProduct;
vm.saveEdit = saveEdit;
vm.cancelEdit = cancelEdit;
if ($location.path().indexOf("/edit/") === 0) {
var id = $routeParams.id;
productsResource.get({ id: id }, function (data) {
vm.currentProduct = data;
});
}
function cancelEdit() {
$location.path("/list");
}
function updateProduct(product) {
product.$save().then(function () {
$location.path("/list");
});
}
function saveEdit(product) {
if (angular.isDefined(product.id)) {
vm.updateProduct(product);
} else {
vm.createProduct(product);
}
vm.currentProduct = {};
}
function createProduct(product) {
new productsResource(product).$create().then(function (newProduct) {
$location.path("/list");
});
}
}
})();

You could pass one object as the body of the post message instead.
Add a class like this
public class addCredentialObj
{
public int salesId { get; set; }
public Credentials credentials { get; set; }
}
Modify your controller like this (The use of FromBody can be read here)
[Route("addcredentials")]
[HttpPost]
public IHttpActionResult AddCredentials([FromBody]addCredentialObj obj)
{
return Ok(credentials);
}
In the client you need to create a matching json object to the addCredentialObj class
var yourCredentials = {"ClientIdentifier":"a","ClientSecret":"b","TokenIdentifier":"c","TokenSecret":"d"};
var jsonData = {
salesId: yourId,
credentials: yourCredentials
};
And then in the $http request to the controller, stringify the json object
$http({
method: 'POST',
url: 'api/addcredentials',
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
},
data: JSON.stringify(jsonData),
});

Related

How tu update database using ajax and the PUT verb?

I'm trying to update a property in my database called "Estado". I'm using ajax to do it, like so:
function atualizaBD(idmarcador, novoEstado) {
$.ajax
({
url: `/api/IgnicoesAPI/${idmarcador}`,
type: 'PUT',
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: JSON.stringify({ Id: idmarcador, Estado: novoEstado }),
async: true,
processData: false,
cache: false,
success: function (result) {
connection.invoke("PostMarker").catch(function (err) {
return console.error(err.toString());
});
},
error: function () {
alert("ocorreu um erro!")
}
});
}
Here is my model:
public class Ignicoes
{
public Ignicoes()
{
ListaOcorrencias = new HashSet<Ocorrencias>();
}
[Key]
public int Id { get; set; }
[Required]
public string Latitude { get; set; }
[Required]
public string Longitude { get; set; }
//estado(recusada, aceite, em avaliacao, concluido)
//public string Estado { get; set; }
[Required]
public string Estado { get; set; }
public DateTime DataInicioPropostaIgnicao { get; set; }
public DateTime DataDecisaoIgnicao { get; set; }
//lista de ocorrencias
public virtual ICollection<Ocorrencias> ListaOcorrencias { get; set; }
}
Here is my PUT method:
public async Task<IActionResult> PutIgnicoes([FromRoute] int id, [FromBody] Ignicoes ignicao)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != ignicao.Id)
{
return BadRequest();
}
else
{
var dataDecisao = DateTime.Now;
var ig = _context.Ignicoes.FirstOrDefault(ignicaoId => ignicaoId.Id.Equals(id));
if (ig != null)
{
ig.Estado = ignicao.Estado;
//ig.Estado = 0;
//ig.Latitude = ignicao.Latitude;
//ig.Longitude = ignicao.Longitude;
ig.DataDecisaoIgnicao = dataDecisao;
}
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!IgnicoesExists(id))
{
return NotFound();
}
else
{
throw;
}
}
}
return NoContent();
}
I already tried to use this code, but instead of changing the property "Estado" I changed the property "Latitude" and it worked perfectly. I don't know why this is happening. Both "Latitude" and "Estado" are the same type - String. Can somebody see the error?
Here is what appears in my output tab:
Here is the Network Analysis:
{"errors":{"Latitude":["The Latitude field is required."],"Longitude":["The Longitude field is required."]},"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"|43114da6-4594b09a6260f1a2."}
It would be easier to undestand the problem if you had added ajax http request + response logs as well (status and payloads). However, application output says 400 bad request for your API method ivocation.
Based on your resource class you have three properties declared as [Required] (except Id) : Longitude, Latitude, Estado, but in your ajax call you are passing only ID and Estado. More likely (if you are using asp.net validation) you have 400 response because of missing required properties in your ajax request body. Try to add missing properties data: JSON.stringify({ Id: idmarcador, Estado: novoEstado, string: latitude, string: longitude })

ASP.Net Core 3 Posting JSON array to controller

I´m having issues passing an array of JSON objects to an MVC controller in ASP.Net core 3. The JSON object is built from a CSV file and passed through an AJAX call. The correct action is called but the object received is always null.
JS:
async function updateData(){
var obj = await getData();
$.ajax({
type: "POST",
contentType: "application/json",
url: "/admin/metric/Update",
data: obj,
dataType: 'json',
success: function (data) {
console.log("SUCCESS : ", data);
},
error: function (e) {
console.log("ERROR : ", e);
}
});
}
async function getData(){
var metric = {};
var metrics = [];
var response = await fetch('https://bloburi.net/source/file.csv');
var data = await response.text();
var table = data.split('\n').slice(1);
table.forEach(row => {
var columns = row.split(',');
metric["FirstName"] = columns[0];
metric["LastName"] = columns[1];
metric["Email"] = columns[2];
metric["AverageHandleTime"] = columns[3];
metric["AverageFollowUp"] = columns[4];
metric["AverageHold"] = columns[5];
metric["Date"] = columns[6];
metrics.push(JSON.stringify(metric));
});
console.log(metrics);
return metrics;
}
Models:
public class MetricBase
{
[Required]
public string Date { get; set; }
public double AverageHandleTime { get; set; }
public double AverageHold { get; set; }
public double AverageFollowUp { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class MetricModel
{
public IEnumerable<MetricBase> MetricBase { get; set; }
}
Controller:
[HttpPost]
public IActionResult Update([FromBody]MetricModel obj)
{
return Json(new { obj });
}
I think the issue may be on how I'm deffining the class that is receiving the JSON, but I've tried multiple things like deffining MetricBase as a List<> or straight up as an array in MetricModel, but it doesn't seem to work.
Any help is appreciated!
You adding the stringify item inside array via code
metrics.push(JSON.stringify(metric));
instead of stringify the whole array. Change the line to
metrics.push(metric);
and data: obj, to
data: JSON.stringify(obj),.
With the mentioned change, the $.ajax sends the whole array. Also change the action to
public IActionResult Update([FromBody]IEnumerable<MetricBase> obj)

Values null when I make a simple post request to my .net controller from angular

This used to be a 415 error question.
Now it is a a receiving null values on the server side question.
I am having difficulty trying to get my values in the object myMessage over to the server side.
I have so far tried to add JSON.stringify to newMessage which is being console.logged in the service file.
I tried many ways to alter or make the object the way it would be recognized such as JSON.stringify() and creating a url ending with the correct parameters.
Sorry if it seems like I am dumping code below, but I have been working on this for a second day and don't understand why I can't do a simple post request with three parameters. One string, one int, and one datetime.
If anyone can see where I have gone wrong I would so appreciate it. I will be desperately waiting.
Below I am trying to hit api/SlgCorpNotes/Edit in backend from updateMessage(message: any) in the service in service.ts
slg-corp-notes.service.ts
import { Component, Injectable, Inject } from '#angular/core';
import { HttpClient, HttpHeaders, HttpResponse } from '#angular/common/http';
import { Observable, Subject, BehaviorSubject } from 'rxjs';
import { SLGReportParams, CorpNotes } from './models/slg.model';
import { SlgOverviewComponent } from './slg-overview/slg-overview.component';
import { SlgNote } from './models/slg-notes';
#Injectable({
providedIn: 'root'
})
export class SlgCorpNotesService {
constructor(private http: HttpClient, #Inject('BASE_URL') private baseUrl: string) { }
getWeekTempValue(endDate, department) {
var Params = '?endDate=' + endDate + '&department=' + department;
return this.http.get<any>(this.baseUrl + 'api/SlgCorpNotes/getWeekTempValue' + Params);
}
updateMessage(message: any) {
console.log("at service")
console.log(message)
var newMessage = new CorpNotes(message['departments'], message['noteBody'], message['weeks'].weekEnding)
var Params = '?Department=' + message['departments'] + '&Note=' + message['noteBody'] + '&WeekEnding=' + message['weeks'].weekEnding
console.log(newMessage)
console.log(JSON.stringify(newMessage))
console.log(Params)
const headers = new HttpHeaders()
.set('Content-Type', 'application/json;charset=UTF-8')
let options = { headers: headers };
return this.http.post(this.baseUrl + 'api/SlgCorpNotes/Edit', JSON.stringify(newMessage), options).subscribe(res => {
console.log(res);
}, error => {
console.log(error);
});;
}
}
model.ts
export class CorpNotes {
constructor(
public department: number,
public note: string,
public weekEnding: Date
) { }
}
SLGCorpNotesController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using mocHub2.Models;
using mocHub2.Models.Enterprise;
using Microsoft.EntityFrameworkCore;
using System.Data.SqlClient;
namespace mocHub2.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SlgCorpNotesController : Controller
{
SLGContext _SLGContext;
BRDataContext _BRDataContext;
//injects new context
public SlgCorpNotesController(SLGContext context, BRDataContext context2)
{
_SLGContext = context;
_BRDataContext = context2;
}
// GET: api/SlgCorpNotes
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET: api/SlgCorpNotes/5
[HttpGet("{id}", Name = "Get")]
public string Get(int id)
{
return "value";
}
// POST: api/SlgCorpNotes
[HttpPost]
public void Post([FromBody] string value)
{
}
// Get Corporate Notes
[HttpGet("[action]")]
public JsonResult getWeekTempValue(DateTime endDate, int department)
{
// Find the WeekID from the weekending from SLGHeaderTemplate table
var WeekID = (from x in _SLGContext.SlgheaderTemplate
where x.WeekEnding == endDate
select x.Id).ToList();
// Find Department name by ID
var DepartmentString = (from x in _BRDataContext.Departments
where x.Department == department
select x.Description).ToList();
// Get the Note.
var DeptNote = from x in _SLGContext.SLGCorpNotes
where x.Department == DepartmentString[0]
&& x.WeekID == WeekID[0]
select x.Notes;
// Create return object
var notes = new Notes();
// If Note exists then return Json containing note and department for display, else return empty string.
if (DeptNote.Any() && WeekID.Count() > 0 && DepartmentString.Count() > 0)
{
var ReturnDeptNote = DeptNote.First();
notes = new Notes() { WeekID = WeekID[0], Department = DepartmentString[0], Note = ReturnDeptNote };
}
else
{
var ReturnDeptNote = "";
notes = new Notes() { WeekID = WeekID[0], Department = DepartmentString[0], Note = ReturnDeptNote };
}
return Json(notes);
}
[HttpPost]
[Route("Edit")]
public void Edit([FromForm] CorpNotes item)
{
_SLGContext.Entry(item).State = EntityState.Modified;
_SLGContext.SaveChanges();
}
}
public class CorpNotes
{
public int department { get; set; }
public string note { get; set; }
public DateTime weekEnding { get; set; }
}
public class Notes
{
public int ID { get; set; }
public int WeekID { get; set; }
public string Department { get; set; }
public string Note { get; set; }
}
}
Results of console.logs in the service file.
at service
slg-corp-notes.service.ts:22 {departments: 2, weeks: SLGTime, noteBody: "asdf"}
slg-corp-notes.service.ts:25 CorpNotes {department: 2, note: "asdf", weekEnding: "2019-11-02T00:00:00"}
slg-corp-notes.service.ts:26 {"department":2,"note":"asdf","weekEnding":"2019-11-02T00:00:00"}
slg-corp-notes.service.ts:27 ?Department=2&Note=asdf&WeekEnding=2019-11-02T00:00:00
slg-corp-notes.service.ts:28 Observable {_isScalar: false, source: Observable, operator: MapOperator}
app.module.ts
This is in my app.module.ts where I specify routes
{ path: 'slg-corp-notes', component: SlgCorpNotesComponent },
{ path: 'slg-corp-notes/edit/', component: SlgCorpNotesComponent }
slg-corp-notes.component.ts
save() {
console.log("at save")
if (!this.optionsForm.valid) {
return;
}
//this.Notes.note = this.optionsForm.get['noteBody'].value;
console.log(this.Notes);
this._slgCorpNotesService.updateMessage(this.optionsForm.value)
.subscribe((data) => {
this._router.navigate(['/slg-corp-notes']); //This will navigate back to the mochhub2 index where the message will be displayed
}, error => this.errorMessage = error)
}
Please let me know if additional info is needed.
1) You need to set the Content-Type header to application/json.
2) stringify the message.
const headers = new HttpHeaders()
.set('Content-Type', 'application/json;charset=UTF-8')
let options = { headers : headers };
this.http.post(this.baseUrl + 'api/SlgCorpNotes/Edit', JSON.stringify(newMessage), options);
At your angular side update your method like this
updateMessage(message: any) {
console.log("at service")
console.log(message)
var newMessage = new CorpNotes(message['departments'], message['noteBody'], message['weeks'].weekEnding)
var Params = '?Department=' + message['departments'] + '&Note=' + message['noteBody'] + '&WeekEnding=' + message['weeks'].weekEnding
console.log(newMessage)
console.log(JSON.stringify(newMessage))
console.log(Params)
var item = {
"Departments": message["Departments"],
"Note": message["noteBody"],
"WeekEnding": message["weeks"]
}
return this.http.post(this.baseUrl + 'api/SlgCorpNotes/Edit', item).subscribe(res
=> {
console.log(res);
}, error => {
console.log(error);
});
}

How to retrieve a web-api controller method(without database), from Javascript

I want to retrieve the function/method written in controller of Web-Api, from javascript of multi-channel devextreme template.(need to show data from Web-API Controller in front-end, where data is not from server).
Please suggest me which site I should refer/by writing simple code...
Controller
namespace WebApiODataService3.Controllers
{
public class ShaileshsController : ODataController
{
public string GetShailesh()
{
return "say hello";
}
}
}
shailesh.js of shailesh.dxview-from devextreme multichannel template
Application2.shailesh = function (params) {
"use strict";
var viewModel = {
// Put the binding properties here
};
return viewModel;
};
I think you ask for an example:
Classes
public class CustomModel
{
public int var1 { get; set; }
public string var2 { get; set; }
public IEnumerable<SubSetModel> subset { get; set; }
}
public class SubSetModel
{
public string subvar1 { get; set; }
public string subvar2 { get; set; }
}
Test Controller Methods
[Route("api/route/postaction")]
public System.Web.Http.Results.JsonResult<string> postaction(CustomModel data)
{
return Json<string>("ok");
}
[Route("api/route/getaction")]
public dynamic getaction()
{
var data = new CustomModel() { var1 = 1, var2 = "ter" };
data.subset = new List<SubSetModel>() { new SubSetModel() { subvar1 = "hi", subvar2 = "hola" } };
return data;
}
Call to getaction
$.ajax({
url: "http://localhost:45007/api/maestro/getaction",
method: "GET",
data: {}
}).done(function (dataSel) {
alert("OK");
}).fail(function (dataSel) {
alert("Fail");
});

Pass Array of Objects in http Post

I have a web api developed. I need to pass an array of objects
[{"Id":"10010","lati":"12.991845763535506","longi":"77.54596710205078","PSID":"1001"},
{"Id":"10011","lati":"12.97846402705198","longi":"77.55729675292969","PSID":"1001"},
{"Id":"10012","lati":"12.967758119178907","longi":"77.54425048828125","PSID":"1001"}]
The model class of web api is given below
Locate.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace webapi.Models
{
public class Locate
{
[Key][Required]
public string Id { get; set; }
public string lati { get; set; }
public string longi { get; set; }
public string PSID { get; set; }
}
}
and the code corresponding to post method in controller file is given below
LocatesController.cs
// POST: api/Locates
[ResponseType(typeof(Locate))]
public async Task<IHttpActionResult> PostLocate(Locate locate)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Locates.Add(locate);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateException)
{
if (LocateExists(locate.Id))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtRoute("DefaultApi", new { id = locate.Id }, locate);
}
private bool LocateExists(string id)
{
return db.Locates.Count(e => e.Id == id) > 0;
}
I send the http post request in my js script given below
app.js
$scope.adding = function()
{
var idd = $rootScope.vaar;
var datas = [];
var len = latitudes.length;
for (var i = 0; i < len; i++) {
datas.push({
"Id": idd + i.toString(),
"lati": latitudes[i].toString(),
"longi": longitudes[i].toString(),
"PSID": idd
});
}
var jsonData = angular.Json(datas);
var objectToSerialize = {'object':jsonData};
var data = $.param(objectToSerialize);
var config = {
headers: {
'Content-Type': 'application/-www-form-urlencoded;charset=utf-8'
}
}
$http.post('http://localhost:8080/pool/api/locates/', data,config).success(function (data, status, headers, config) {
alert("Success");
}).error(function (data, status, header, config) {
alert("An error has occured while adding!"+status);
});
}
It does not add the above array. Please help me
the problem is here:
[ResponseType(typeof(Locate))]
public async Task<IHttpActionResult> PostLocate(Locate locate)
and you are posting an array so it should be:
[ResponseType(typeof(Locate))]
public async Task<IHttpActionResult> PostLocate(List<Locate> locates)
The problem is solved. I changed the parameter to (List<Locate> locates) and made a logic inside post method. Thank you Glenn Packer

Categories