Passing Object in get Request to WebAPI 2 - angularjs

selectedLocation is always null on the Server
I am using Angular , what is the proper way of passing object to get method
This is Class that is defined on Server, which is being passed as parameter in get request
public class Location
{
public string LocationName { get; set; }
public string MFGName { get; set; }
}
This is the method in WebAPI that is being called.
[HttpGet]
[ActionName("RenewToken")]
[AllowAnonymous]
[ResponseType(typeof(string))]
public async Task<IHttpActionResult> RenewToken(Location selectedlocation)
{
}
The Captured Request looks like this(In google Chrome Developers Tool)
http://localhost:58146/api/Account/RenewToken?selectedlocation=%7B%22LocationName%22:%22Guad%22,%22MFGName%22:%22Flex%22%7D
What am i doing wrong ?

Okay so from what i got from this
Why do we have to specify FromBody and FromUri in ASP.NET Web-API?
when the parameter of the method is a complex type is looks in the body of the request
since you're using GET the data gets put into the uri instead of the body
couple options you could do are
public async Task<IHttpActionResult> RenewToken(string LocationName, string MFGName)
{
}
you could always change your verb to a post or something that accepts data in teh body
You might try changing your get in angular to something like
$http({
method: "GET",
url: "/api/Account/RenewToken",
params: {
LocationName: "Guad",
MFGName: "Flex"
}
})
which will parameterize the data

Related

Call .NET Core API from AngularJS using $https - 400 Bad Request

I'm trying to call a .NET Core API from AngularJS. In the AngularJS I'm calling the method like this:
$http({
method: 'POST',
url: '/api/message/transaction/' + this.transaction.id,
data: { "transactionJson": "hello"}
})
.then(function (response) {
var r = response;
})
My .NET Core API method is like this:
[Route("~/api/message/transaction/{transactionId}")]
[HttpPost]
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] string transactionJson)
{
I'm getting a 400 Bad Request response back from the server. How do I fix it?
I realised the type for the parameter must be a type that has a property named TransactionJson, so I need to define a new C# type:
public class TransactionData() {
public string TransactionJson
}
Then in the API method:
[Route("~/api/message/transaction/{transactionId}")]
[HttpPost]
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] TransactionData transactionJson)
{
getting a 400 Bad Request response back from the server. How do I fix it?
To fix the issue, as your mentioned, one solution is modifying action parameter, like below.
public async Task<ActionResult<DeviceEventsTransactionmsg>> PostTransaction([FromBody] TransactionData transactionJson)
{
//...
//code logic here
TransactionData class
public class TransactionData
{
public string TransactionJson { get; set; }
}
Besides, we can also implement and use a custom plain text input formatter to make PostTransaction action method that accepts a string-type ACTION parameter work well.
public class TextPlainInputFormatter : TextInputFormatter
{
public TextPlainInputFormatter()
{
SupportedMediaTypes.Add("text/plain");
SupportedEncodings.Add(UTF8EncodingWithoutBOM);
SupportedEncodings.Add(UTF16EncodingLittleEndian);
}
protected override bool CanReadType(Type type)
{
return type == typeof(string);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
string data = null;
using (var streamReader = new StreamReader(context.HttpContext.Request.Body))
{
data = await streamReader.ReadToEndAsync();
}
return InputFormatterResult.Success(data);
}
}
Add custom formatter support
services.AddControllers(opt => opt.InputFormatters.Insert(0, new TextPlainInputFormatter()));
Test Result

Call .NET Core controller method from React with values

I'm new to React and I just can't find clear information on how to call a controller in my .NET Core application, send it values from the form inputs and then get a result back from it. Doesn't seem like it should be hard to do but maybe I know so little that I'm asking Google the wrong questions. Anyway...
I have a controller method that looks like this. I have called it from Postman and it seems to work.
[ApiController]
[Route("user")]
public class UserController : ControllerBase
{
[HttpGet]
[Route("login/authenticate")]
public async Task<IActionResult> AuthenticateUserAsync([FromBody] AuthenticateUserRequest request)
{
... // sends request to back-end and gets a response
return Ok(response);
}
}
There's a request class that looks like this, and I want the UserID and Password properties from the React form to be set here.
public class AuthenticateUserRequest: Request
{
public string UserID { get; set; }
public string Password { get; set; }
}
The response that is returned contains a list of strings which is used to authenticate the user with an identity in the controller. I want to return this list to React to show what permissions the user has.
public class AuthenticateUserResponse: Response
{
public List<String> Permissions { get; set; }
}
And I'm trying to call it with something like this:
I got this fetch example from here: ASP.NET Core React project template - how to link to C# backend
but it doesn't seem to work.
handleSubmit(event) {
if (this.state.userId == "" || this.state.password == "") {
alert('Please enter User ID and Password.');
event.preventDefault();
}
else {
fetch('user/login/authenticate', {
method: 'get',
headers: { 'Content-Type': 'application/json' },
body: {
"UserID": this.state.userId.value,
"Password": this.state.password.value
}
})
.then(response => response.json())
.then(data => {
alert(data);
});
}
}
The alert never gets called and I don't know if it's doing anything at all. When I press the Submit button the form clears, and that's it.
When you use get in ajax to request the action in the Core API, you need to accept the parameters by using [FromQuery] attribute instead of [FromBody] attribute.
[HttpGet]
[Route("login/authenticate")]
public async Task<IActionResult> AuthenticateUserAsync([FromQuery] AuthenticateUserRequest request)
{
... // sends request to back-end and gets a response
return Ok();
}
Refer to this.

ASP.Net Web Api, POST multiple objects

I have this AngularJS Http Call
$http({
method: "POST",
url: Helper.ApiUrl() + '/Api/Case/SendCase',
data: { obecttype1, obj2, obj3},
}).then(function mySuccess(response) {});
Ant this ASP.net Web Api method
[HttpPost]
[Route("Api/Path/SendCase")]
public int SendCase(object application)
{
string applicantName = ((Newtonsoft.Json.Linq.JObject)application)["applicant"].ToString();
obecttype1 obj = JsonConvert.DeserializeObject<obecttype1>(((Newtonsoft.Json.Linq.JObject)application)["obecttype1"].ToString());
.........................
return ID;
}
This works pretty well, but I feel it is a bit dirty because I am parsing my objects in my method, so my question is
Is the are way to send multiple objects as params in a POST method, I would prefer to avoid modifying my model, avoid creating a class for this
So my Api Method would look like this
public int SendCase(class1 obecttype1, class2 obj2, class3 obj3)
"Is the are way to send multiple objects as params in a POST method, I would prefer to avoid modifying my model, avoid creating a class for this"
By design HTTP Post can only have one body and web api will try to cast the body to the parameter defined in the method signature. So sending multiple objects in the body and trying to match these against multiple params in the method signature will not work. For that you need to define a class which holds the other classes and match the body signature.
public class postDTO
{
public class1 class1Data { get; set; }
public class2 class2Data { get; set; }
public class3 class3Data { get; set; }
}
//The api signature
public int SendCase(postDTO application)
If you still don't want to add the new class then I would use the JObject directly as the parameter as this
[HttpPost]
public int SendCase(JObject jsonData)
{
dynamic json = jsonData;
JObject class1DataJson = json.class1Data;
JObject class2DataJson = json.class2Data;
JObject class3DataJson = json.class3Data;
var class1Data = class1DataJson.ToObject<class1>();
var class2Data = class2DataJson.ToObject<class2>();
var class3Data = class3DataJson.ToObject<class3>();
}
1. Define models for the parameters
public class ClassType1
{
public int Num1 { get; set; }
public string Str1 { get; set; }
}
public class ClassType2
{
public double Test2 { get; set; }
}
2. Use the models as the parameters on the API controller method
// Sorry this example is setup on .Net Core 2.0 but I think the previous
// versions of Web Api would have similar/same behavior
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpPost]
public void Post(ClassType1 ct1, ClassType2 ct2)
{}
}
3. When posting, your objects inside the data {} have to have the keys that match the parameter name you defined on the Controller method
jQuery ajax
$.ajax({
method: 'post',
url: 'http://localhost:53101/api/values',
dataType: 'json',
data: {
// It takes key value pairs
ct1: {
num1: 1,
str1: 'some random string'
},
ct2: {
test2: 0.34
}
}
});
To summarize, yes you can post multiple objects back to the server, as long as
You define a key for each object and the key has to match the parameter name you define on the server method.
The object structure has to match.
-- update --
Just as a proof, here is the screenshot:
We have an app that uses DefaultHttpBatchHandler to accept multi-part POST requests. I believe it to be a bit clunky for many reasons but it is the built-in way to accept multiple objects on a single request in a structured fashion.
https://msdn.microsoft.com/en-us/library/system.web.http.batch.defaulthttpbatchhandler(v=vs.118).aspx
As for the script to create something, that I don't know about. Our callers that use this API are C# services that can create the multi-part requests using a simple client library we provide to help them do just that.

Why is this Web API 2 action returning 404 not found?

Here is my ApiController:
[RoutePrefix("api/Campaign")]
public class CampaignController : ApiController
{
private readonly ICampaignLogic _campaignLogic;
public CampaignController(ICampaignLogic campaignLogic)
{
_campaignLogic = campaignLogic;
}
[HttpGet]
[Route("GetCampaignsByYearCompanyAndContactIds/{companyId:int}/{contactId:int}/{year:int}")]
public List<Campaign> GetCampaignsByYearCompanyAndContactIds(int companyId, int contactId, int year)
{
return _campaignLogic.GetByYearCompanyAndContactIds(year, companyId, contactId);
}
}
And here is where I make the call in AngularJS:
$http.get(ApiUrl + "/api/Campaign/GetCampaignsByYearCompanyAndContactIds",
{ params: { year: $scope.year, companyId: $scope.client, contactId: $scope.contactId } })
.then(function (responses) {
})
This is what is being called when I debug it in Chrome:
http://localhost/MyApi/api/Campaign/GetCampaignsByYearCompanyAndContactIds?companyId=12046&contactId=13662&year=2016
Everything is set up correctly in terms of my localhost as I am calling other API actions without any problem. However, when I call this one I am getting a 404 Not Found error.
What am I missing here?
Based on your route the url needs to have the parameters included in the route and not a part of the query string. if you want to make them available only in the query string then remove them from the route attribute.
What you should be passing in AngularJS
http://localhost/MyApi/api/Campaign/GetCampaignsByYearCompanyAndContactIds/12046/13662/2016
So you will need to build the URL using the parameters, you cannot use params with this url.
If you want to use params in AngularJS change the Route attribute to the following.
[Route("GetCampaignsByYearCompanyAndContactIds")]

Angular $http post returning empty data

I'm managing to post to the server OK, I'd like to get the updated data and load it back into the same JSON object, but the data response is null.
$scope.saveDetails = function() {
$http({
method : 'POST',
url : '/service/rest/orders',
data : $scope.orderDetails
})
.success(function(data, status) {
$scope.orderDetails = data;
})
.error(function() {
alert('error');
});
}
Also worth mentioning, that the initial object is being passed from another controller via $rootscope and injected into the local scope.
$scope.orderDetails = $rootScope.newOrder;
Thanks for any help.
Your code looks fine, I would be checking the backend to make sure data is actually being sent. Another option would be to use the chrome inspector and check the response to make sure you are actually getting something back.
It turns out it was returning the whole object and the order was deeper down, I didn't see that in my console at first.
$scope.orderDetails = data.order;
Thanks for all replies.
In case anyone else runs into this, in my case I had a class with a data contract attribute applied:
[DataContract(Namespace = "http://somespace.com")]
And my class members had not been given the [DataMember] attribute. Web API was not returning back the data. I added the [DataMember] attribute and it fixed it.
[DataMember] public int NumberUpdated { get; set; }
[DataMember] public int NumberInserted { get; set; }
[DataMember] public List<ServicesListImport> InvalidRows {get; set;}

Resources