How to pass two different types parameters in http POST method using angularjs to Web API? - angularjs

First parameter is a complex type object(JSON) and second parameter is a simple type(String).Here I am using Web API 2.
I am putting my code below.
Web API
public class UserDetailsModel
{
[Key]
[EmailAddress]
public string LoginEmail { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public string DisplayPic { get; set; }
[EmailAddress]
public string AlternateEmail { get; set; }
public string Organization { get; set; }
public string Occupation { get; set; }
public string Contact { get; set; }
public DateTime DoB { get; set; }
public string Gender { get; set; }
public string Country { get; set; }
public string State { get; set; }
public string City { get; set; }
public string Website { get; set; }
public string Info { get; set; }
public DateTime DateOfRegister { get; set; }
//public string LoginIP { get; set; }
public int LoginFlag { get; set; }
}
public int RegisterUser(UserDetailsModel userReg, string LoginIP)
{
.
.
.
}
angularjs
var UserDetails = {
'LoginEmail': $scope.LoginEmail,
'LoginName': $scope.LoginName,
'Password': $scope.Password,
'DoB': $scope.DoB,
'Gender': $scope.Gender,
'City': $scope.City,
'State': $scope.State,
'Country': $scope.Country
};
var request = $http({
method: 'post',
url: urlBase + '/UserDetails',
params: { 'userRegJSON': UserDetails, 'LoginIP': LoginIP }
});
Here in above code, I am getting NULL in UserDetails and 192.152.101.102 in LoginIP in Web API.
var request = $http({
method: 'post',
url: urlBase + '/UserDetails',
data: { 'userRegJSON': UserDetails, 'LoginIP': LoginIP }
});
Here in above code, I am getting NULL in both parameter UserDetails and LoginIP in Web API.
Then how to pass two or more different parameter types in http POST method using angularjs.

You cannot pass 2 types in webAPI.Either you pass everything in a single type or you can do the below
var request = $http({
method: 'post',
url: urlBase + '/UserDetails?LoginIp=' + LoginIP,
data: UserDetails,
});
In the API change the signature to
public int RegisterUser([FromBody]UserDetailsModel userReg, [FromUri]string LoginIP)
{
.
.
.
}

Go throught this:
Use simple and complex types in my api method signatures
POST multiple objects from Angular controller to Web API 2

Webapi doesn't work fairly well when you wish to pass 2 parameters in a POST
method. ModelBinding in Webapi always works against a single object because it maps a model.
There a few workarounds that you can use to make this work:
Use both POST and QueryString Parameters in Conjunction
If you have both complex and simple parameters, you can pass simple parameters on the query string. Your code should actually work with:
something like this
/baseUri/UserDetails?LoginIP=LoginIP
but that's not always possible. In this example it might not be a good idea to pass a user token on the query string though.
Refer to #Ravi A's suggestions for making changes in your code.

Related

.Net Core Web API not deserializing JSON from angularJS

I have this angular JS controller where I am serialising a view model to json which doesnt deserialise on the backend with a web api.
Here is my angular controller constructor..
constructor($scope, $http, $routeParams: IBookingParams) {
this.http = $http;
//get parameters from Recommendation page
this.bookingView = <IBookingViewModel>{};
this.bookingView.CampaignName = $routeParams.CampaignName;
this.bookingView.CampaignSupplierId = $routeParams.CampaignSupplierId;
this.bookingView.SupplierName = $routeParams.SupplierName;
this.bookingView.MediaChannelNames = $routeParams.MediaChannelNames;
this.bookingView.MediaChannelIds = $routeParams.MediaChannelIds;
let livedate = this.GetJSDate($routeParams.LiveDate);
let liveDateTime = this.GetDateTime(livedate);
this.bookingView.LiveDate = liveDateTime;
//populate the rest of our model
this.bookingView.Action = "from angular";
var model = this.bookingView;
let json = JSON.stringify(model);
this.http({
url: "/api/asdabooking",
method: "POST",
data: json
})
.then((response: any) => {
let test = "";
})
.catch((data: any) => {
let test = "";
});
}
Here is my web api
[HttpPost]
[Route("api/asdabooking")]
public async Task<IActionResult> BuildBookingModel([FromBody]BookingViewModel model)
{
try
{
//model is null??!!
return Ok("");
}
catch (Exception ex)
{
base.Logger.LogError(ex.Message, ex);
return BadRequest(ex.Message);
}
}
This is pretty bizarre, the bookingView view model on the front end matches the fields on the backend view model "BookingViewModel. I have inspected the json and all looks ok.
This is my view model
public class BookingViewModel
{
public string CampaignName { get; set; }
public string CampaignSupplierId { get; set; }
public string SupplierName { get; set; }
public List<string> MediaIds { get; set; }
public List<string> MediaChannelNames { get; set; }
public List<MediaChannelViewModel> MediaChannels { get; set; }
public string Action { get; set; }
public DateTime LiveDate { get; set; }
public List<int> MediaChannelIds { get; set; }
public int SupplierId { get; set; }
public bool SuccessfulSave { get; set; }
/// <summary>
/// Track which tab is updating
/// </summary>
public string TabAction { get; set; }
/// <summary>
/// Price summary - list of media channels (tabs)
/// </summary>
public List<MediaSummaryViewModel> MediaSummaries { get; set; }
public string UserMessage { get; set; }
}
This is my json
Often when I run into this issue it is caused from the types within the JSON object not matching the types of your properties that you defined within your model. I would ensure those types match. It also might help folks interested in answering this question to post a snippet of your JSON object as well as your model class.
mediaChannelIds should be
"mediaChannelIds":[
4,
5]
This is because I was getting an array from a query string using $routeParams by referring to the same parameter more than once which is a bad idea.. better to separate values with a character to get an array because you cant make it typesafe with $routeParams.. it will always give you strings.
In the JSON You can miss out fields or pass null no problem and it will still deserialise, but you can't mismatch types or the whole thing comes back as null.

Postman POST working but AngularJS post throwing 404

I'm just trying to pass some basic form data through to a web-api via AngularJS $http.
here is the function that called to send data to the API:
$http({
url: "/Portal/GenerateTimeSheets",
method: "POST",
headers: {
'Content-Type': 'application/json'
},
data: angular.toJson($scope.placementForm),
}).then(function (response) {
}), function(response) {
};
Note: if I breakpoint and copy and paste the $scope.placementForm data into postman it works completely fine, but going through a browser is throwing errors.
Here is my api:
[HttpPost]
public void GenerateTimeSheets([FromBody]PlacementModel placement)
{
Console.WriteLine("STUB");
}
and the Placement Model:
[JsonProperty(PropertyName = "candidateName")]
public string CandidateName { get; set; }
[JsonProperty(PropertyName = "clientName")]
public string ClientName { get; set; }
[JsonProperty(PropertyName = "jobTitle")]
public string JobTitle { get; set; }
[JsonProperty(PropertyName = "placementStartDate")]
public string StartDate { get; set; }
[JsonProperty(PropertyName = "placementEndDate")]
public string EndDate { get; set; }
[JsonProperty(PropertyName = "frequency")]
public string TimeSheetFrequency { get; set; }
404 Usually denotes that the url of the request is wrong, You are missing something in the url. Validate your url with the backend. Hope it helps

sending byteArray in a JSON body via angularjs http request

I want to send a post request in which the body of request is a JSON included two attributes , one of them is canvas information generated with fabricjs and the second one is a byteArray of project thumbnail. the problem is that, when I send the request , I receive null in server side.
var dataURI = this.getDataUrl($rootScope.imageType, $rootScope.imageQuality);
var strImage = dataURI.replace(/^data:image\/[a-z]+;base64,/, "");
var byteArray = covertBase64ToByteArray(strImage);
var data = {
data: {
name: name,
state: canvas.fabric.toJSON(['selectable', 'name']),
zoom: canvas.zoom,
canvasWidth: width,
canvasHeight: height,
},
typeArray: byteArray
};
$http({
method: "POST",
url: _url,
data: JSON.stringify(data),
processData: false,
transformRequest: [],
contentType: 'application/json',
})
backend Code in .Net
public IHttpActionResult InsertOrUpdateUILayout(long user_Id, long layout_Id, int userLayout_Id, int? layoutType_Id, UserlayoutContentVM data)
{
// back end code here
}
public class UserlayoutContentVM
{
public object data { get; set; }
//public string base64Image { get; set; }
public byte[] typeArray{ get; set; }
}
When posting data to the backend api you need to tell the method to read the data from the request body.
This can be done with the FromBody attribute which will map the body data to the define model.
So add all properties to one model
public class UserlayoutContentVM
{
public long user_Id { get; set; }
public long layout_Id { get; set; }
public int userLayout_Id { get; set; }
public int? layoutType_Id { get; set; }
public object data { get; set; }
public byte[] typeArray{ get; set; }
}
Then make sure the client send all data in the same structure and use the FromBody attribute in the controller method to read the values
public IHttpActionResult InsertOrUpdateUILayout([FromBody]UserlayoutContentVM data){ }

angularjs $http is throwing error 500 (Internal Server Error) when groupby in linq is used and passed as json

angularjs $http is throwing error 500 (Internal Server Error) when groupby in linq is used and passed as json
I have 2 classes Offer and OfferDetails
public class OfferDetails
{
public long? eventid { get; set; }
public List<Offer> offer { get; set; }
}
public class Offer
{
public long OfferId { get; set; }
public string OfferType { get; set; }
public Nullable<long> EventId { get; set; }
public Nullable<decimal> OfferDiscount { get; set; }
public Nullable<int> NoofPeople { get; set; }
public Nullable<long> UserId { get; set; }
public Nullable<System.DateTime> CreatedDate { get; set; }
public Nullable<System.DateTime> UpdatedDate { get; set; }
public string CreatedIp { get; set; }
public string UpdatedIp { get; set; }
public Nullable<bool> IsActive { get; set; }
}
When I am calling the method offerdetailsjson() using angularjs $http and putting breakpoint on method offerdetailsjson() then it is running fine but $http throws error
public JsonResult offerdetailsjson()
{
List<OfferDetails> r = repository.Offers.GetAll().GroupBy(x => x.EventId).Select(x => new OfferDetails
{
eventid = x.Key,
offer = x.ToList()
}).ToList();
return Json(r);
}
<script>
angular.module('app', []).controller("OfferListCtrl", OfferListController);
OfferListController.$inject = ['$scope', '$http'];
function OfferListController($scope, $http) {
$http({
url: '/Master/offerdetails',
method: 'post',
}).then(function (response) {
debugger
alert(JSON.stringify(response.data));
}, function () { alert('Failed'); });
}
</script>
I will be thankful if someone can help me.

Json parsing in MVC 4 web api with angularjs

public partial class User
{
public System.Guid UserId { get; set; }
public Nullable<System.Guid> RoleId { get; set; }
public Nullable<long> MembershipNo { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public string Emaiil { get; set; }
public Nullable<decimal> MobileNo { get; set; }
public string Description { get; set; }
public Nullable<System.Guid> ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
public virtual Role Role { get; set; }
}
This is my table in DB named Users which is associated with Roles table of DB (as you can see last virtual row at the end above)
Now My problem is simple. I'm using angulars $http.get() method to call my Web Api in MVC 4. When i call it, it gets connected and fetches desired record but it doesn't throw proper result back to .js file or controller.
At .js side I run into error. Every time, it executes .error(jsonResult,config,header,status) .
When I jump on to JsonResult, it shows me below error.
Object
ExceptionMessage: "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'."
ExceptionType: "System.InvalidOperationException"
InnerException: Object
ExceptionMessage: "Self referencing loop detected for property 'Role' with type
'System.Data.Entity.DynamicProxies.Role_82CA96EA045B1EB47E58B8FFD4472D86502EEA79837B4AE3AD705442F6236E58'.
Path 'Role.Users[0]'."
ExceptionType: "Newtonsoft.Json.JsonSerializationException"
Message: "An error has occurred."
I don't know what's wrong here. Is it json parsing error or something? if so, I've heard and read the articles that webapi in .net handles or throws json itself.
My call happens through
$http.get(apiUrl).success(function (jsonResult, header, config, status) {
debugger;
var number = parseInt(jsonResult.membershipNo) + 1;
$scope.membershipNo = "M" + number;
})
.error(function (jsonResult, header, config, status) {
debugger;
toastr.error('Something went wrong ! Contact Administrator!!!');
});
Edited:
One more thing to mention, .CS side when I fetch single cell value (from DB/table) , it gets returned back to .success() call but when i fetch particular row or all rows, it gets returned to .error() call. I'm using entity frameworkd 6.1.1. and above class is generated by EF-6.1.1.
public partial class Role
{
public Role()
{
this.Permissions = new List<Permission>();
this.Users = new List<User>();
}
public System.Guid RoleId { get; set; }
public string RoleName { get; set; }
public string Description { get; set; }
public Nullable<System.Guid> ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDate { get; set; }
public virtual ICollection<Permission> Permissions { get; set; }
public virtual ICollection<User> Users { get; set; }
}
Hi you can solve that in 2 easy steps
First Step: Create globalConfig class where you can set ignoring ReferenceLoopHandling (http://james.newtonking.com/json/help/index.html?topic=html/SerializationSettings.htm) and if you crating js app you can set as well to remove xml formaters and always get return from Webapi as JSON string is usefull for debugging. So in your app_start folder add class GlobalConfig like below:
public class GlobalConfig
{
public static void CustomizeConfig(HttpConfiguration config)
{
// Remove Xml formatters. This means when we visit an endpoint from a browser,
// Instead of returning Xml, it will return Json.
//that is optional
config.Formatters.Remove(config.Formatters.XmlFormatter);
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling =
Newtonsoft.Json.ReferenceLoopHandling.Ignore;
}
}
Second Step: In Global.asax set your custom configuration to do that please add code below to method Application_Start():
GlobalConfig.CustomizeConfig(GlobalConfiguration.Configuration);
it sounds like:
the problem is that EF is using lazy loading that is not materialized in time of constructing this, on role. EF from early version has switched lazy loading on by default.
Suggested solution
Create subset of you user class, with the parts that you really need.
=> Its bad practise to fetch too much data that you are not gonna need.

Resources