Postman Post call Screenshot
Hi Below is my current code:
var url = "https://localhost:44332/token";
var login = new Login()
{
username = "test#gmail.com",
password = "Password#1",
grant_type = "password"
};
using (var client = new HttpClient())
{
httpResponseMessage = await client.PostAsJsonAsync(url, login);
if (httpResponseMessage.IsSuccessStatusCode)
{
var token = httpResponseMessage.Content.ReadAsStringAsync();
}
}
My error is that 400: Bad Request, whenever i make the API call.
If i use postman, its working,
The following is what i put in POSTMAN body:
"username=test#gmail.com&password=Password#1&grant_type=password"
Many Thanks in advance if anyone can correct me!
It looks like you're trying to get hte token from OAuth 2.0 authentications server. You shouldn't be posting JSON - it expects the data as form. It returns a JSON object with access token storen in property access_token - you probably will need to deserialize it as well.
using System.Net.Http.Json;
using System.Text.Json.Serialization;
var url = "https://localhost:44332/token";
var form = new Dictionary<string, string>
{
{"grant_type", "password"},
{"username","test#gmail.com#1"},
{"password", "Password#1"},
};
using (var client = new HttpClient())
{
var response = await client.PostAsync(url, new FormUrlEncodedContent(form));
if (response.IsSuccessStatusCode)
{
var token = await response.Content.ReadFromJsonAsync<Token>();
var accessToken = token.AccessToken;
}
}
class Token
{
[JsonPropertyName("access_token")]
public string AccessToken { get; set; }
[JsonPropertyName("token_type")]
public string TokenType { get; set; }
[JsonPropertyName("expires_in")]
public int ExpiresIn { get; set; }
[JsonPropertyName("refresh_token")]
public string RefreshToken { get; set; }
}
Do you pass these parameters by URL in postman? This form username=test#gmail.com&password=Password#1&grant_type=password looks like you use URL past parameters in postman.
Usually, in POST requests we pass parameters in the request body, not the URL.
Besides, a recommendation is not directly a HttpClient instance. If you use .NET Framework and create the HttpClient instance directly, cannot release the socket resource even if you disposable the HttpClient object. If you use .NET Core, you can inject an HttpClient or IHttpClientFactory.
Refers: Use IHttpClientFactory to implement resilient HTTP requests
Related
I am working with RestSharp and an API I believe is set up with Azure. I making a POST request to the API, but have noted that the request only works when the body is named, "agentGetRequest" in Postman.
Bad Body:
{
"supplierKey": "XXXX-XXXX-XXXX-XXXX",
"inputDate": "2021-01-17T00:00:00.000Z"
}
Good Body:
{
"agentGetRequest": {
"supplierKey": "XXXX-XXXX-XXXX-XXXX",
"inputDate": "2021-01-17T00:00:00.000Z"
}
}
So when I run my code
void Post(AgentRequest agentRequest, Credentials creds )
{
Uri baseUrl = new Uri(creds.baseURL);
IRestClient client = new RestClient(baseUrl);
IRestRequest request = new RestRequest(ENDPOINT, Method.POST);
request.AddHeader("subscriptionKey", creds.subscriptionKey);
// Option 1:
request.AddJsonBody(agentRequest);
// Option 2:
request.AddJsonBody(agentRequest, "agentGetRequest")
IRestResponse<GetAgentResponse> response = client.Execute<GetAgentResponse>(request);
if (response.IsSuccessful)
{
Console.WriteLine(JsonConvert.SerializeObject(response.Content));
}
else
{
Console.WriteLine(response.ErrorMessage);
}
}
// Body request object
public class AgentRequest
{
public string inputDate { get; set; }
public string supplierKey { get; set; }
}
It throws a bad request error because it can't find the body, "agentRequest."
I have found a workaround where I feed it a string as the body - but this would hate to have to do this for every endpoint:
// Instead of request.AddJsonBody()...
string body = "{\"agentGetRequest\": {\"supplierKey\": \"XXXX-XXXX-XXXX-XXXX\",\"inputDate\": \"2021-0117T00:00:00.000Z\"}}";
request.AddParameter("application/json", body, ParameterType.RequestBody);
How can I correctly format the body when adding it via AddJsonBody to include the name (and maybe the encapsulating brackets)?
Recording to the accepted answer of RestSharp Post a JSON Object, you could add JSON body like below:
request.AddJsonBody(
new
{
agentGetRequest = agentRequest
}); // AddJsonBody serializes the object automatically
I am working on creating an API that call the other third party API. The third party API is an REST API and returns response in the JSON format when I call it in the web browser
[{"Acc":"IT","Cnt":"023","Year":"16"}]
I am trying to get the same response when I call the third party API from my API.
public IHttpActionResult Get(string acctID)
{
using (var client_EndPoint= new HttpClient())
{
Uri uri_EndPoint = new Uri(BaseURL_EndPoint);
client_EndPoint.BaseAddress = uri;
client_EndPoint.DefaultRequestHeaders.Accept.Clear();
client_EndPoint.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string EndPoint_URL = BaseURL_EndPoint+"api/NameCreation?Account="+acctID;
var response_EndPoint = client_EndPoint.GetAsync(EndPoint_URL).Result;
string responseString = response_EndPoint.Content.ReadAsStringAsync().Result;
return Ok(responseString);
}
}
What I have been doing is getting the response from the third party API in a string. But I am checking if there is a way I can get in the JSON format so I can return them directly. The return type of the get method is IHttpActionResult. If I am returning as string the response looks like
"[{\"Acc\":\"adm\",\"Cnt\":\"001\",\"Year\":\"16\"}]"
Any help is greatly appreciated.
Create a model to hold rest api data
public class Model {
public string Acc { get; set; }
public string Cnt { get; set; }
public string Year { get; set; }
}
Deserialize it from api
var response_EndPoint = await client_EndPoint.GetAsync(EndPoint_URL);
var models = await response_EndPoint.Content.ReadAsAsync<Model[]>();
And then return that
return Ok(models);
Full example
public async Task<IHttpActionResult> Get(string LabName) {
using (var client_EndPoint = new HttpClient()) {
//...other code removed for brevity
var response_EndPoint = await client_EndPoint.GetAsync(EndPoint_URL);
var models = await response_EndPoint.Content.ReadAsAsync<Model[]>();
return Ok(models);
}
}
you can use Newtonsoft.Json ,Just add it from nuget and add this config to webapiconfig:
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
then use
return Json(responseString)
I am posting an object to a WebApi method. I'm using PostAsJsonAsync to do this.
public async Task<HttpResponseMessage> PostAsync(string token, ServiceCall call)
{
var client = new HttpClient();
client.SetBearerToken(token);
var response = await client.PostAsJsonAsync(Uri + "id/nestedcall", call);
return response;
}
The object call that I'm passing is not null when I post it.
[HttpPost]
[Route("id/nestedcall")]
public async Task<IHttpActionResult> NestedCall([FromBody]ServiceCall call)
{
// call is null here
}
However it is null in my API method. I can't seem to work out why as all of the examples I've followed use this format.
Why isn't the call object being picked up by the web api?
Edit
Here is the ServiceCall object. It is in a separate class library and a reference is included in both the web application and the API.
public class ServiceCall
{
public ServiceCall(Service service, string grantType)
{
ClientId = service.Id;
ClientSecret = service.Secret;
Uri = service.Uri;
Scope = service.Scope;
GrantType = grantType;
}
public ServiceCall(string clientid, string clientsecret, string uri, string scope, string grantType)
{
ClientId = clientid;
ClientSecret = clientsecret;
Uri = uri;
Scope = scope;
GrantType = grantType;
}
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string Uri { get; set; }
public string Scope { get; set; }
public string GrantType { get; set; }
}
I have seen Object null in WebApi method after PostAsJsonAsync due to serialization.
Better to use PostAsync like below :
var obj = new MyClass()
{
MyProperty = 11
};
using (var client = new HttpClient())
{
string inputJson = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
HttpContent inputContent = new StringContent(inputJson, Encoding.UTF8, "application/json");
HttpResponseMessage response1 = client.PostAsync("http://localhost:60909/api/home/Test", inputContent).Result;
if (response1.IsSuccessStatusCode)
{
}
}
Using Prefix Stackify I was able to diagnose that the serialiser was throwing an exception:
Newtonsoft.Json.JsonSerializationException: Unable to find a constructor to use for type Core.Models.ServiceCall. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'ClientId', line 1, position 12.
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize
However, very helpfully, rather than tell me that an exception occurred the controller simply gave me a null object.
As hinted by the exception the solution is to add a default constructor (or at least one the serialiser can understand).
public ServiceCall()
{
}
looks like the JSON serialization may be failing. BTW, remove that [FromBody] and try without it like below. PostAsJsonAsync method serializes the ServiceCall object to JSON and then sends the JSON payload in a POST request.
public async Task<IHttpActionResult> NestedCall(ServiceCall call)
{
// your code
}
I run into exactly the same problem and had to do this to solve it:
using (var client = new HttpClient())
{
client.SetBearerToken(token);
var content = new StringContent(JsonConvert.SerializeObject(call), Encoding.UTF8, "application/json");
var response = await client.PostAsJsonAsync(Uri + "id/nestedcall", content);
return response;
}
When I try to pass a value to my Web API using a Windows Forms Client like this:
SessionModel s = new SessionModel()
{
SessionID = "123456"
};
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:49584/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", txtToken.Text.Trim());
try
{
HttpResponseMessage response = await client.PostAsJsonAsync("api/account/depositaccounts", s);
response.EnsureSuccessStatusCode(); // Throw if not a success code.
if (response.IsSuccessStatusCode)
{
MessageBox.Show("Results", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
catch (HttpRequestException ex)
{
MessageBox.Show(ex.Message);
}
}
And the API Controller code is this:
[HttpPost]
[Authorize]
[Route("DepositAccounts", Name = "DepositAccounts")]
public HttpResponseMessage GetDepositAccounts(Models.AuthenticationBindingModel model)
{
var sessionId = model.SessionID;
}
When the model comes in the SessionID property is null. I confirmed that is not null on the client side.
When use Fiddler to create the Json request on the other hand it works. Am I missing something on the client side?
Thanks.
** EDIT: changed the property 'SessionId' to 'SessionID' on the client side. Same issue though.
Change the API signiture to be GetDepositAccounts(dynamic model) or use the same class on both client and server side.
Apparently on the client side I was declaring my class with a constructor like this:
class SessionModel
{
public SessionModel()
{
}
public String SessionId { get; set; }
}
And it resulted in some extra data being added to the fields in the json request ('k__BackingField'). Although there are lots of articles on how to remove that from the response I couldn't figure out how to remove it from the request. Turns out declaring the class on the client side without the constructor removes that 'k__BackingField' text and then the request works.
class SessionModel
{
public String SessionID { get; set; }
}
Not sure the reasoning behind this, just that it happens. If anyone wants to comment on the 'why' that would be great!
I am trying to use http Client to make a call to Web API to get the token.I have one MVC app and Web API app.below is the MVC controller action I have.
[HttpPost]
public ActionResult Login()
{
LoginModel m = new LoginModel();
m.grant_type = "password";
m.username = "xxx";
m.password = "xxx1234";
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:51540/");
var response = client.PostAsJsonAsync("Token", m).Result;
response.EnsureSuccessStatusCode();
return View();
}
But when I make the request the API responds as BAD request. I tried to add the content type as "application/json" and have confirmed using fiddler that the request is of type json.
I am able to register the user using Web API so at WebAPI side things are looking fine to me,I am using default project created by VS2013 using Individual account and haven't modified any thing on API side.
I am following this tutorial http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api and trying to use HTTP Client instead of fiddler.
I will be thankful if someone helps me
TokenEndpointRequest seems doesn't support JSON yet, but you can use query string
var response = client.PostAsync("Token", new StringContent("grant_type=password&username=xxx&password=xxx1234", Encoding.UTF8)).Result;
Here's my code from the answer & comment above
using (var client = new HttpClient{ BaseAddress = new Uri(BaseAddress) })
{
var token = client.PostAsync("Token",
new FormUrlEncodedContent(new []
{
new KeyValuePair<string,string>("grant_type","password"),
new KeyValuePair<string,string>("username",user.UserName),
new KeyValuePair<string,string>("password","P#ssW#rd")
})).Result.Content.ReadAsAsync<AuthenticationToken>().Result;
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(token.token_type, token.access_token);
// actual requests from your api follow here . . .
}
created an AuthenticationToken class for beautification purposes:
public class AuthenticationToken
{
public string access_token { get; set; }
public string token_type { get; set; }
public int expires_in { get; set; }
}