So I have been learning some .net core and I am building an API with it. Normally I would work with angular and send requests there.
I have the following angular snippet:
const BloclDTO = {
Period: value.YearFormControl + value.MonthFormControl + '00',
ValueBlock1: value.OnelFormControl,
ValueBlock2: value.TwolFormControl,
ValueBlock3: value.ThreelFormControl,
ValueBlock4: value.FourlFormControl,
ParamId: 1
}
Then there's the backend model for the same data:
public class MiddleDTO
{
public string Period { get; set; }
public double ValueBlock1 { get; set; }
public double ValueBlock2 { get; set; }
public double ValueBlock3 { get; set; }
public double ValueBlock4 { get; set; }
public int ParamId { get; set; }
}
And finally the method that should send it:
in HttpService
addData(param: any) {
console.log('is http service: ', param);
return this.HttpClient.post(`api/Data/AddValue`, { params: param });
}
in Component
this.http.addData(BloclDTO).subscribe(res => {
console.log('res add ', res);
});
in .net Core Controler
[HttpPost]
[Route("AddValue")]
public JsonResult AddValue([FromBody]MiddleDTO param)
{
if (param == null)
{
return Json(new { error = true, text = "param is null" });
}
return Json(param);
}
But i have empty data in controller.
Try this one:
[HttpPost]
[Route("AddValue")]
public IHttpActionResult AddValue([FromBody]MiddleDTO param)
{
if (param == null)
{
return InternalServerError(new Exception("param is null"));
}
return OK(param);
}
angular:
addData(param: any) {
let bodyString = JSON.stringify( param );
let headers = new HttpHeaders({ 'Content-Type': 'application/JSON' });
return this._http.post<any>('api/Data/AddValue', bodyString, { headers: headers });
}
Related
I want to upload an image to my project, but unfortunately it gives an error of 415. Swagger does not give an error when I install it from above, but it gives an error when I install it from above Angular. What is the solution to this?
Backend Web Api Code;
[Produces("application/json", "text/plain")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(string))]
[HttpPost("update")]
public async Task<IActionResult> Update([FromFrom] UpdatePresidentMessageCommand updatePresidentMessage)
{
var result = await Mediator.Send(updatePresidentMessage);
if (result.Success)
{
return Ok(result.Message);
}
return BadRequest(result.Message);
}
}
Backend Handlers Code;
if (request.Image != null)
{
var fileUpload = Core.Extensions.FileExtension.FileUpload(request.Image, fileType: Core.Enums.FileType.Image);
if (fileUpload != null)
{
isTherePresidentMessageRecord.Image = fileUpload.Path;
}
}
Angular Service Code;
updatePresidentMessage(presidentMessage: FormData): Observable<any> {
return this.httpClient.post('https://localhost:60021/Admin/api' + '/presidentMessages/update', presidentMessage,{ responseType: 'text' });
}
Angular Ts Code;
update(): void {
let presidentModel = Object.assign({}, this.presidentMessageFormGroup.value);
const formData = new FormData();
formData.append('id', presidentModel.id.toString());
formData.append('shortDescription', presidentModel.shortDescription);
formData.append('description', presidentModel.description);
for (const photo of this.photos) {
formData.append('image', photo, photo.name);
}
this.presidentMessageService.updatePresidentMessage(formData).subscribe(response => {
this.alertifyService.success(response);
});
}
onFileSelect(event: any) {
if (event.target.files.length > 0) {
for (const file of event.target.files) {
this.photos.push(file);
}
}
}
" const headers = new HttpHeaders().set('Content-Type', 'multipart/form-data');
" the error I get when I add;
enter image description here
UpdatePresidentMessageCommand Class;
public int ID { get; set; }
public string ShortDescription { get; set; }
public string Description { get; set; }
public IFormFile Image { get; set; }
public class UpdatePresidentMessageCommandHandler : IRequestHandler<UpdatePresidentMessageCommand, IResult>
{
private readonly IPresidentMessageRepository presidentMessageRepository;
private readonly IUserService userService;
public UpdatePresidentMessageCommandHandler(IUserService userService, IPresidentMessageRepository presidentMessageRepository)
{
this.userService = userService;
this.presidentMessageRepository = presidentMessageRepository;
}
[LogAspect(typeof(FileLogger))]
[SecuredOperation(Priority = 1)]
public async Task<IResult> Handle(UpdatePresidentMessageCommand request, CancellationToken cancellationToken)
{
var isTherePresidentMessageRecord = await this.presidentMessageRepository.GetAsync(u => u.ID == request.ID);
if (isTherePresidentMessageRecord == null)
{
return new ErrorResult(message: Messages.Error);
}
isTherePresidentMessageRecord.ShortDescription = request.ShortDescription;
isTherePresidentMessageRecord.Description = request.Description;
isTherePresidentMessageRecord.UpdateByUserID = this.userService.GetNameIdentifier();
isTherePresidentMessageRecord.UpdateDateTime = System.DateTime.Now;
if (request.Image != null)
{
var fileUpload = Core.Extensions.FileExtension.FileUpload(request.Image, fileType: Core.Enums.FileType.Image);
if (fileUpload != null)
{
isTherePresidentMessageRecord.Image = fileUpload.Path;
}
}
this.presidentMessageRepository.Update(isTherePresidentMessageRecord);
await this.presidentMessageRepository.SaveChangesAsync();
return new SuccessResult(Messages.Updated);
}
}
Try to set the correct 'Content-Type' on the header of your POST request.
I'm looking to send the following fields to a MVC action
public class AddProductViewModel
{
public string ProductId { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public double Price { get; set; }
public bool Enabled { get; set; }
public List<CategorySelectModel> Categories { get; set; } = new List<CategorySelectModel>();
public List<IFormFile> Photos { get; set; } = new List<IFormFile>();
}
CategorySelectModel:
public string CategoryId { get; set; }
public string CategoryName { get; set; }
and I haved used what i believe represents the actual json data...but I dont get why it isnt posting the data to the action
here is the js code where I have serialized the data and send to the controller
function SubmitProducts(element)
{
element.preventDefault();
let ulContainer = document.getElementById("dropDownAndSel").getElementsByTagName('ul')[0];
var Categories = [];
let x = document.getElementById("dropDownCategories");
for (let i = 0; i < x.children.length; i++) {
if (x.options[i].selected) {
let CategoryName = x.options[i].innerHTML;
let CategoryId = x.children[i].value;
let dropdownItems = { CategoryId, CategoryName };
if (!Categories.includes(dropdownItems)) {
Categories.push(dropdownItems);
}
}
}
let pId = document.getElementById('pId').value;
let ProductId = pId;
let ProductName = document.getElementById('ProductName').value;
if (!ProductName || ProductName.length ==0) {
alert('ProdutName cannot be null or empty');
return;
}
let priceStr = document.getElementById('productPriceId').value;
if (!priceStr || priceStr.length == 0) {
alert('Price cant be empty')
return;
}
let Price = parseFloat(priceStr);
let QuantityStr = document.getElementById('qtyNum').value;
if (!QuantityStr || QuantityStr.length==0) {
alert('Quantity cant be empty');
return;
}
let Quantity = parseInt(QuantityStr);
var formData = new FormData();
let filesContainer = document.getElementById('photoProduct_0');
for (let i = 0; i < filesContainer.files.length; i++) {
formData.append('model.Photos', filesContainer.files[i], filesContainer.files[i].name);
}
formData.set('model.ProductId', ProductId);
formData.set('model.ProductName', ProductName);
formData.set('model.Price', Price);
formData.set('model.Quantity', Quantity);
formData.set('model.Categories', JSON.stringify(Categories));
$.ajax({
url: '/' + 'Product' + '/' + 'AddProduct',
type: 'POST',
contentType: false,
processData: false,
data: formData,
success: console.log('success'),
});
}
Here is the action signature:
[HttpPost]
public async Task<IActionResult> AddProduct([FromBody] AddProductViewModel model)
Code above post FormData data. Therefore, the AddProductViewModel parameter should be bound using form-data in the request body:
[HttpPost]
public async Task<IActionResult> AddProduct([FromForm] AddProductViewModel model)
Reference to the following post: ASP.NET Core form POST results in a HTTP 415 Unsupported Media Type response
I am sending data to HTTP post API. But everytime I try to call the API, I get error code: 400, Bad request message.
Here is my API code:
[Route("InsUpPlayer")]
[HttpPost]
public async Task<object> InsUpPlayer([FromForm] Players player)
{
try
{
//Some code here
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
And my repository code:
public async Task<string> PlayerInsUpPost(Player player1)
{
var SendResponse = "false";
try
{
var RequestUrl = baseUrl + "Master/InsUpPlayer";
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(RequestUrl);
using (var player = new MultipartFormDataContent())
{
if (player1.ProfileImageFile != null)
{
string objimgFileBase64 = "";
ByteArrayContent fileContent;
using (var ms = new MemoryStream())
{
player1.ProfileImageFile.CopyTo(ms);
var fileBytes = ms.ToArray();
objimgFileBase64 = Convert.ToBase64String(fileBytes);
}
byte[] bytes = Convert.FromBase64String(objimgFileBase64);
fileContent = new ByteArrayContent(bytes);
player.Add(fileContent, "ProfileImageFile", string.Format("{0}", player1.ProfileImageFile.FileName));
}
if (player1.DetailImageFile != null)
{
string objimgFileBase64 = "";
ByteArrayContent fileContent;
using (var ms = new MemoryStream())
{
player1.DetailImageFile.CopyTo(ms);
var fileBytes = ms.ToArray();
objimgFileBase64 = Convert.ToBase64String(fileBytes);
}
byte[] bytes = Convert.FromBase64String(objimgFileBase64);
fileContent = new ByteArrayContent(bytes);
player.Add(fileContent, "DetailImageFile", string.Format("{0}", player1.DetailImageFile.FileName));
}
player.Add(new StringContent(player1.playerId.ToString()), "playerId");
player.Add(new StringContent(player1.FirstName), "FirstName");
player.Add(new StringContent(player1.LastName), "LastName");
player.Add(new StringContent(player1.DOB.ToString()), "DOB");
player.Add(new StringContent(player1.Nationality.ToString()), "Nationality");
player.Add(new StringContent(player1.BirthState.ToString()), "BirthState");
player.Add(new StringContent(player1.JerseyNo.ToString()), "JerseyNo");
player.Add(new StringContent(player1.Postion.ToString()), "Postion");
player.Add(new StringContent(player1.Biography), "Biography");
player.Add(new StringContent(player1.isActive.ToString()), "isActive");
player.Add(new StringContent(player1.isPublish.ToString()), "isPublish");
player.Add(new StringContent(player1.UserType.ToString()), "UserType");
HttpResponseMessage objResponse = await httpClient.PostAsync(RequestUrl, player);
if (objResponse.IsSuccessStatusCode && (int)objResponse.StatusCode == 200)
{
var serResponse = objResponse.ContentAsType<ResultModel>();
//SendResponse = serResponse.result;
SendResponse = "true";
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Exception Occured");
throw;
}
return SendResponse;
}
The Player class is like this:
public class Player
{
public long playerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DOB { get; set; }
public int Nationality { get; set; }
public int BirthState { get; set; }
public int JerseyNo { get; set; }
public int Postion { get; set; }
public string Biography { get; set; }
public bool isActive { get; set; }
public bool isPublish { get; set; }
public int UserType { get; set; }
public IFormFile ProfileImageFile { get; set; }
public IFormFile DetailImageFile { get; set; }
public string ProfileImage { get; set; }
public string DetailImage { get; set; }
}
Update: Here is my JQuery code: The DOB here is correct, but I realized just now that it is not getting passed correctly to the controller.
$("#PublishPlayer").click(function () {
debugger;
var value = $('#CreatePlayerForm').valid();
var url = '/Admin/PlayerInsUpPost';
var day = $('#Day').val();
var month = $('#Month').val();
var year = $('#Year').val();
var DOB = new Date(year, month, day);
var fdata = new FormData();
fdata.append("playerId", $('#playerId').val());
fdata.append("FirstName", $('#FirstName').val());
fdata.append("LastName", $('#LastName').val());
fdata.append("DOB", DOB);
fdata.append("Nationality", $('#Nationality').val());
fdata.append("BirthState", $('#BirthState').val());
fdata.append("JerseyNo", $('#JerseyNo').val());
fdata.append("Position", $('#Position').val());
fdata.append("Biography", $('#Biography').val());
fdata.append('ProfileImageFile', $('#ProfileImageFile')[0].files[0]);
fdata.append('DetailImageFile', $('#ProfileImageFile')[0].files[0]);
if (value == true) {
$.ajax({
url: url,
datatype: "json",
accept: {
javascript: 'application/javascript'
},
type: "POST",
cache: false,
processData: false,
contentType: false,
data: fdata,
success: function (result) {
if (result == "true") {
alert('Player added successfully.');
window.location.href = "/Admin/PlayerList";
} else if (result == "false") {
alert('Failed to update, please try later.');
}
},
error: function () {
alert('Something went wrong');
}
});
}
else {
//$('.playeradd').removeClass('show');
//$('.playeradd').addClass('hide');
return false;
}
//event.stopPropagation();
});
The DOB in JQuery before calling Ajax is : Wed Sep 12 2001 00:00:00 GMT+0530 (India Standard Time) {}
When passed to controller it is: {01-01-0001 12:00:AM}
If I comment DOB in API and in the frontend, everything works fine. But I need to send DOB to API and I can't change the datatype of DOB in API. How do I fix this error?
When passing the data into the ajax request convert it to ISO string. Dotnet understands that. So do something like this:
fdata.append("DOB", DOB.toISOString());
I suppose it is some problem with ASP.NET deserialization of DateTime (I'm not sure tho). I have run into similar problem of sending dates before and my solution was instead of sending DateTime struct, I send number of ticks (which you can get from DateTime object) as long variable.
DateTime BOD = DateTime.Now; // You may fill your DateTime object with your own data
long BODticks = BOD.Ticks;
And then on the server side you can easily recreate date time like this:
DateTime myDate = new DateTime(BODticks);
And then in order to use it you can modify your player class as follows:
public class Player
{
public long playerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public long DOBTicks { get; set; }
public DateTime DOB { get => new DateTime(DOBTicks); set => DOBTicks = value.Ticks; }
public int Nationality { get; set; }
public int BirthState { get; set; }
public int JerseyNo { get; set; }
public int Postion { get; set; }
public string Biography { get; set; }
public bool isActive { get; set; }
public bool isPublish { get; set; }
public int UserType { get; set; }
public IFormFile ProfileImageFile { get; set; }
public IFormFile DetailImageFile { get; set; }
public string ProfileImage { get; set; }
public string DetailImage { get; set; }
}
I'm sure someone could find a better solution though and that's assuming this one actually works and I understood your problem right.
The new serializer in .net core > 3.0 is strict when parsing date formats (note that the default has changed from newtonsoft json). They have to be in ISO8601 format, i.e. YYYY-MM-DD. If you are passing something that isn't in ISO8601 forms you have to write a custom formatter.
public class DateTimeJsonConverter : JsonConverter<DateTime>
{
public override DateTime Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
DateTime.ParseExact(reader.GetString(),
"<YOUR FORMAT HERE>", CultureInfo.InvariantCulture);
public override void Write(
Utf8JsonWriter writer,
DateTime dateTimeValue,
JsonSerializerOptions options) =>
writer.WriteStringValue(dateTimeValue.ToString(
"<YOUR FORMAT HERE>", CultureInfo.InvariantCulture));
}
The code above is an example of a custom formatter.
Read further details here (https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to#sample-basic-converter) in how to create a custom formatter for your input.
I am trying to call the controller from ajax and sending model data which consist some list of data inside it. I am getting the count correct for them but inside the list properties are coming null.
Controller:
public JsonResult InsertorUpdate(IncidentEdit incident)
{
try
{
SrvincidentDtls.TicketNo = incident.TicketNo;
SrvincidentDtls.Priority = incident.Priority;
SrvincidentDtls.Status = incident.Status;
SrvincidentDtls.Title = incident.Title;
SrvincidentDtls.IsActive = incident.IsActive;
List<Comments> lstComm = new List<Comments>();
if(incident.CommentList!=null )
{
foreach (var comm in incident.CommentList)
{
Comments Comm = new Comments();
Comm.Comment = comm.Comments;
Comm.AddedBy = comm.AddedBy;
Comm.AddedBy_ID = comm.AddedBy_ID;
Comm.CreatedDate = comm.CreatedDate;
lstComm.Add(Comm);
}
}
SrvincidentDtls.Comments = lstComm.ToArray();
SrvincidentDtls.Description = incident.Description;
var result=proxyService.InsertorUpdateIncidentDetails(SrvincidentDtls);
return Json(new { success = true, jvalue = result }, JsonRequestBehavior.AllowGet);
}
catch(Exception ex)
{
throw ex;
}
}
Model:
public class IncidentEdit
{
public string Title { get; set; }
public string Description { get; set; }
public bool IsActive { get; set; }
public string Status { get; set; }
public string Priority { get; set; }
public List<IncidentComments> CommentList { get; set; }
}
Generic Class:
public class IncidentComments
{
public string Comments { get; set; }
public string AddedBy { get; set; }
public string AddedBy_ID { get; set; }
public DateTime CreatedDate { get; set; }
}
Ajax call:
function InsertOrUpdate(){
incidentDetails = {
Title: $("#txtTitle").val(),
Description: $("#txtDescription").val(),
Priority: $('#selPriority option:selected').val(),
Status: $('#selStatus option:selected').val(),
IsActive: 1,
CreatedDate :$('#spncrtdDt').text(),
CommentList:PopulateCommentList()
};
$.ajax({
type: "Get", //HTTP POST Method
url: insertORupdatUrl, // Controller/View
data: {incident:incidentDetails},
contentType: "application/json; charset=utf-8",
success: function (data) {
}
});
}
js function:
function PopulateCommentList() {
var CommentList = [];
var dtTable = $('#dvCommentTbl').DataTable();
for (var i = 0; i < 10; i++) {
if (dtTable.row(i).data() != "" && dtTable.row(i).data() != null && dtTable.row(i).data() != undefined) {
CommentList.push({
Comments: dtTable.row(i).data()[1],
AddedBy: dtTable.row(i).data()[2],
AddedBy_ID: dtTable.row(i).data()[0],
CreatedDate: dtTable.row(i).data()[3]
});
}
}
return CommentList;
}
the count for comment list is coming fine but the data like Added_By,comments,Created Dtae all coming null.
Plz help.
You can take a variable like
var commlist=PopulateCommentList();
then populate it in your model json:
incidentDetails = {
Title: $("#txtTitle").val(),
Description: $("#txtDescription").val(),
Priority: $('#selPriority option:selected').val(),
Status: $('#selStatus option:selected').val(),
IsActive: 1,
CreatedDate :$('#spncrtdDt').text(),
CommentList:commlist
};
it will work as it work for me.
I'm working on some demo examples on how to pass the form data from an Angular Service to a Web API 2 controller POST action. But my object is always null on the controller side. Here is how my code looks like
AngularJS Call to Web API
$http({
method: 'POST',
url: MyApp.rootPath + 'api/CustomerSpaSilo/SearchCustomers?nameFilter=' + nameFilter,
data: $.param({ '': pagingVM }),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
The pagingVM is an angular $scope object that contains paging details - SortBy, CurrentPage, ItemsPerPage, SortDesc.
My Web API POST method
[HttpPost]
[Route("SearchCustomers")]
public HttpResponseMessage Post(string nameFilter, [FromBody] PagingViewModel pagingVM)
{
if (nameFilter == null)
nameFilter = "";
//Code Implementation
}
The PagingViewModel class
public class PagingViewModel
{
public string SortBy { get; set; }
public bool SortDesc { get; set; }
public int CurrentPage { get; set; }
public int TotalItems { get; set; }
public int ItemsPerPage { get; set; }
public int TotalPages
{
get {
if (this.ItemsPerPage > 0)
return (int)Math.Ceiling((decimal)TotalItems / this.ItemsPerPage);
else
return 1;
}
}
}
The pagingVM parameter is always coming as default object. A quick look in the Chrome's network activity shows that all the values are being passed in the request body as the form data. If I change the parameter type to FormDataCollection, then I can read the values and build my object but I'm looking to Web API bind the incoming request values for me. Am I missing something here?
controller
[RoutePrefix("api/CustomerSpaSilo")]
public class CustomerSpaSiloController : ApiController
{
[HttpPost]
[Route("SearchCustomers")]
public IHttpActionResult Post(string nameFilter, [FromBody] PagingViewModel pagingVM)
{
if (nameFilter == null)
nameFilter = "";
//Code Implementation
return Ok("Result=" + pagingVM.ToString());
}
}
model
public class PagingViewModel
{
public string SortBy { get; set; }
public bool SortDesc { get; set; }
public int CurrentPage { get; set; }
public int TotalItems { get; set; }
public int ItemsPerPage { get; set; }
public int TotalPages
{
get
{
if (this.ItemsPerPage > 0)
return (int) Math.Ceiling((decimal) TotalItems/this.ItemsPerPage);
else
return 1;
}
}
public override string ToString()
{
return string.Format("PagingViewModel(SortBy='{0}',SortDesc='{1}', CurrentPage='{2}', TotalItems='{3}', ItemsPerPage='{4}')",
SortBy, SortDesc, CurrentPage, TotalItems, ItemsPerPage);
}
}
postman screenshot
js client
<!DOCTYPE html>
<html ng-app="app">
<head>
<title>Home</title>
</head>
<body ng-controller="HomeController">
<button ng-click="post()">post</button>
<p>{{status}}</p>
<pre>{{result | json}}</pre>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<script>
(function() {
'use strict';
console.trace('js loaded');
angular
.module('app', [])
.factory('api', apiFactory)
.controller('HomeController', HomeController);
function apiFactory($http) {
var svc = {
searchCustomers: searchCustomers
};
return svc;
function searchCustomers(nameField, paging) {
return $http
.post('/api/CustomerSpaSilo/SearchCustomers?nameFilter=' + nameField,
paging,
{
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
transformRequest: function (obj) {
var str = [];
for (var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
}
}
);
}
}
function HomeController($scope, api) {
console.trace('HomeController');
$scope.status = null;
$scope.result = null;
$scope.post = function () {
var paging = {
SortBy: 'abc',
SortDesc: false,
CurrentPage: 3,
TotalItems: 52,
ItemsPerPage: 10
};
api.searchCustomers('ddd', paging)
.then(function(response) {
$scope.status = 'OK';
$scope.result = response.data;
}, function(reason) {
$scope.status = 'Error';
$scope.result = reason;
});
};
}
})();
</script>
</body>
</html>
chrome screenshot
you should use your $http service like as -
$http.post(MyApp.rootPath + 'api/CustomerSpaSilo/SearchCustomers?nameFilter=' + nameFilter, pagingVM ).then(function (result) {
//success
}, function (data) {
//faild
});