HttpClient post request for WebApi using asp.net mvc application - c#

I'm trying to consume WebApi but I'm having issues. My 'IsSuccessStatusCode' is always false and I have 404 in response.
I have tried multiple methods but can't be able to do it correctly.
Constants:
const string baseUri = ""; // base url of API
const string setDealFlagUri = "Deals/SetDealFlag";
Method 1, using PostAsync:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUri);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("deadId", "3"),
new KeyValuePair<string, string>("flagValueToSet", "true")
});
var response = await client.PostAsync(setDealFlagUri, content);
if (response.IsSuccessStatusCode)
{
return true;
}
}
Method 2, using PostAsJsonAsync:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUri);
DealFlag content = new DealFlag
{
deadId = 3,
flagValueToSet = true
};
var response = await client.PostAsJsonAsync(setDealFlagUri, content);
if (response.IsSuccessStatusCode)
{
return true;
}
}
WebApi request detail:
Curl:
curl -X POST --header 'Accept: application/json' '{baseApiurl}/Deals/SetDealFlag?dealId=3&flagValueToSet=true'
Request URL
{baseApiurl}/Deals/SetDealFlag?dealId=3&flagValueToSet=true
Response Body
{
"Successful": true,
"ErrorMessages": [],
"ValidationResults": {
"IsValid": false,
"ValidationErrors": []
}
}
Response Headers
{
"pragma": "no-cache",
"date": "Wed, 24 Aug 2016 18:38:01 GMT",
"content-encoding": "gzip",
"server": "Microsoft-IIS/8.0",
"x-aspnet-version": "4.0.30319",
"x-powered-by": "ASP.NET",
"vary": "Accept-Encoding",
"content-type": "application/json; charset=utf-8",
"cache-control": "no-cache",
"content-length": "198",
"expires": "-1"
}
Please help me to use this webapi function correctly.
Thanks!

I think that the problem is that your controller method has signature like
[HttpPost]
public HttpResponseMessage SetDealFlag(int dealId, bool flagValueToSet)
Am I right? If your answer is "Yes" so your method wants parameters in the URL.
And so you get 404 error becouse no one of yours Web API methods matches to that URL.
Send your parameters dealId and flagValueToSet in the URL is the solution.
I wrote simple console app for testing my theory and it works perfectly:
public static void Main(string[] args)
{
using (var client = new HttpClient())
{
try
{
// Next two lines are not required. You can comment or delete that lines without any regrets
const string baseUri = "{base-url}";
client.BaseAddress = new Uri(baseUri);
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("deadId", "3"),
new KeyValuePair<string, string>("flagValueToSet", "true")
});
// response.Result.IsSuccessStatusCode == true and no errors
var response = client.PostAsync($"{baseUri}/Deals/SetDealFlag?dealId=3&flagValueToSet=true", null);
// response.Result.IsSuccessStatusCode == false and 404 error
// var response = client.PostAsync($"{baseUri}/Deals/SetDealFlag", content);
response.Wait();
if (response.Result.IsSuccessStatusCode)
{
return;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
}

Related

Resolve Incident in D365 Online via OData

I have created a controller for one of our customers to use. It should run on POST and receive a JSON body with two parameters: id and statuscode.
The logic is simple - I wish to fetch the incident with guid equals id and change its statuscode based on the received value for statuscode.
Code of controller:
public async Task<MyCustomResponse> CloseIncident([FromBody] MyCustomRequest _request)
{
try
{
// Some logic here to check if both Id and StatusCode exist in _request ...
if(Guid.TryParse(_request.Id, out Guid guid))
{
// Construct OData request
JObject incidentResolution = new JObject();
incidentResolution.Add("subject", "testing");
incidentResolution.Add("incidentid#odata.bind", $"/incidents({guid})");
incidentResolution.Add("timespent", 2); //This is billable time in minutes
incidentResolution.Add("description", "description");
JObject parameters = new JObject();
parameters.Add("IncidentResolution", incidentResolution);
if (_request.StatusCode == 1)
{
parameters.Add("Status", (int)IncidentStatusCode.ProblemSolved);
}
else
{
parameters.Add("Status", (int)IncidentStatusCode.SomeOtherRejectedStatusCode);
}
RegenerateAccess(); // Connect to Microsoft Online
string urlAPI = "/api/data/v9.1/CloseIncident";
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(_serviceUrl);
client.Timeout = new TimeSpan(0, 2, 0); //2 minutes
client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
client.DefaultRequestHeaders.Add("OData-Version", "4.0");
//client.DefaultRequestHeaders.Add("Prefer", "return=representation");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpMethod method = HttpMethod.Post;
HttpRequestMessage request = new HttpRequestMessage(method, urlAPI);
request.Content = new StringContent(parameters.ToString(), Encoding.UTF8, "application/json");
// Set the access token
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _authResult.AccessToken);
HttpResponseMessage response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
return new MyCustomResponse()
{
Status = Status.Success,
Message = "..."
};
}
return new MyCustomResponse()
{
Status = Status.Error,
Message = "..."
};
}
else throw new Exception("Guid is invalid.");
}
catch(Exception ex)
{
return new MyCustomResponse() { Status = Status.Error, Message = ex.Message };
}
}
I'm getting a "Bad Request" from the client.SendAsync line. I think the OData body request is incorrect, but I can't figure out why.
Code looks perfect. I’ll try to add the below header and see the response.
client.DefaultRequestHeaders.Add("Content-Type", "application/json; charset=utf-8");
While trying to debug, if you see any useful error response in exception that will help troubleshooting.

RestSharp: Error "expected type: JSONObject, found: Null"

I am using RestSharp library for my REST APIs, and I am getting 400 BadRequest "expected type: JSONObject, found: Null" for GET request. With Postman it is working fine.
{
"Result": {
"RequestId": "495f45c0-d9e9-11eb-9936-02a74f481686",
"OverallStatus": "FAILURE",
"ErrorDetails": [
{
"ErrorLineItem": {
"ErrorCode": "400",
"ErrorMessage": "Bad Request",
"ErrorDescription": "expected type: JSONObject, found: Null"
}
}
]
}
}
Below is my code:
var request = new GetAlertProfileDistributionChannelRequest
{
AccountCustomerNumber = "*****201",
DistributionChannelSubscriptions = new AlertProfileDistributionChannelSubscriptions
{
AlertProfileId = Guid.Parse("7adaaa2c-5b2d-424c-8dc8-4e9a01908729")
}
};
var client = new RestClient("https://******/v1/profile/channels")
{
Timeout = -1
};
var apiRequest = new RestRequest(Method.GET) { RequestFormat = DataFormat.Json };
apiRequest.AddHeader("client_id", "********4cedc");
apiRequest.AddHeader("client_secret", "*******d526c");
apiRequest.AddHeader("Authorization", $"Bearer eyJhbGciOiJSUzI*******");
apiRequest.AddHeader("Content-Type", "application/json");
apiRequest.AddParameter("application/json", JsonConvert.SerializeObject(request), ParameterType.RequestBody);
var apiResponse = client.ExecuteAsync(apiRequest).Result;
Console.WriteLine(apiResponse.Content);
With Postman it is working fine:
Am I missing something here?
I resolved my issue with System.Net.Http.WinHttpHandler package that does support the functionality - simply installed and used when constructing my HttpClient instances.
var request = new GetAlertProfileDistributionChannelRequest
{
AccountCustomerNumber = "***0201",
DistributionChannelSubscriptions = new AlertProfileDistributionChannelSubscriptions
{
AlertProfileId = Guid.Parse("7adaaa2c-5b2d-424c-8dc8-4e9a01908729")
}
};
var handler = new WinHttpHandler();
var client = new HttpClient(handler);
client.DefaultRequestHeaders.Add("client_id", "**********5487");
client.DefaultRequestHeaders.Add("client_secret", "*******c99");
client.DefaultRequestHeaders.Add("Authorization", "Bearer eyJhbGciOiJSU");
var apirequest = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("https://*********profile/channels"),
Content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json"),
};
var response = client.SendAsync(apirequest).Result;
response.EnsureSuccessStatusCode();
var result = response.Content.ReadAsStringAsync().Result;

.Net Core 5 Web Api - Swagger POST ok Xunit POST Error

I'm using XUnit to test my WebApi, GET requests are working ok. But when testing a POST through XUnit I received a 404 Bad Request while Swagger returns 200 OK
Teste
[Theory]
[InlineData("POST")]
public async Task ContestCreateTest(string method)
{
var _httpClient = new Setup().httpClient;
var request = new HttpRequestMessage(new HttpMethod(method), "/v1/Contest");
var contestObject = new
{
title = "Concurso automatizado",
description = "Concurso automatizado",
submissionDeadLineInit = TimeZoneInfo.ConvertTime(DateTime.UtcNow.AddDays(1), TZConvert.GetTimeZoneInfo("America/Sao_Paulo")).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"),
submissionDeadLineEnd = TimeZoneInfo.ConvertTime(DateTime.UtcNow.AddDays(2), TZConvert.GetTimeZoneInfo("America/Sao_Paulo")).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"),
ratingDeadLineInit = TimeZoneInfo.ConvertTime(DateTime.UtcNow.AddDays(3), TZConvert.GetTimeZoneInfo("America/Sao_Paulo")).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"),
ratingDeadLineEnd = TimeZoneInfo.ConvertTime(DateTime.UtcNow.AddDays(4), TZConvert.GetTimeZoneInfo("America/Sao_Paulo")).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"),
closingDate = TimeZoneInfo.ConvertTime(DateTime.UtcNow.AddDays(5), TZConvert.GetTimeZoneInfo("America/Sao_Paulo")).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"),
useDistritoRules = true,
rules = ""
};
string contestJson = JsonConvert.SerializeObject(contestObject);
request.Content = new StringContent(contestJson, Encoding.UTF8, "multipart/form-data");
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
As the image shows your API accepts form but you're sending data in json format.
var formDataContent = new MultipartFormDataContent
{
{ new StringContent("Concurso automatizado", Encoding.UTF8), "title"},
{ new StringContent("Concurso automatizado", Encoding.UTF8), "description")},
{ new StringContent(TimeZoneInfo.ConvertTime(DateTime.UtcNow.AddDays(1), TZConvert.GetTimeZoneInfo("America/Sao_Paulo")).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'", Encoding.UTF8), "submissionDeadLineInit" },
...
};
// Act
var response = await _client.PostAsync("/v1/Contest", formDataContent);

How to create a post to LinkedIn

We are getting a HTTP error 400 Bad Request while creating the Post in linkedin using HTTP POST request.
Sample COde:
public static bool PostLinkedInNetworkUpdate(string accessToken, string title, string submittedUrl = "", string submittedImageUrl = "")
{
var requestUrl = String.Format(linkedinSharesEndPoint, accessToken);
var message = new
{
comment = "Testing out the LinkedIn Share API with JSON",
content = new Dictionary<string, string>
{ { "title", title },
{ "submitted-url", submittedUrl },
{"submitted-image-url" , submittedImageUrl}
},
visibility = new
{
code = "anyone"
}
};
var requestJson = new JavaScriptSerializer().Serialize(message);
var client = new WebClient();
var requestHeaders = new NameValueCollection
{
{ "Content-Type", "application/json" },
{ "x-li-format", "json" },
{"Host", "api.linkedin.com"}
};
client.Headers.Add(requestHeaders);
var responseJson = client.UploadString(requestUrl, "POST", requestJson);
var response = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(responseJson);
return response.ContainsKey("updateKey");
}
}
We are getting an error message on the line:
var responseJson = client.UploadString(requestUrl, "POST", requestJson);
as HTTP Error 400 Bad Request.
We have tested the code with GET Request which is working from my Dev server,However any of the POST requests are failing with this error message.
We have verified the REsponse headers with the request made from POSTMAN which is working.The response headers of POSTMAN are matching with the Bad Request response
Do we need to install the LinkedIn certificate in the Server?
Does anyone have any suggestions/comments?
Thanks in advance

Http Post C# with Json response

I would like to get a method that generates an http post with the following configuration in c#.
POST pqs.php HTTP/1.1
Host: nationalmap.gov/epqs/pqs.php
Content-Type: application/x-www-form-urlencoded
Content-Length: length
x=string&y=string&units=string&output=string
I tried the following however I am getting invalid coordinates although they do exist in the map ( example tried is lat = 36.574832 and lon = -85.411825
Here is the code I am using:
public class ElevationUSGISPull
{
public string responseString = null;
private string BASEURL = "http://nationalmap.gov/epqs/pqs.php";
public bool httpPostElevationRequest( string lon,string lat)
{
try
{
using (WebClient client = new WebClient())
{
byte[] response =
client.UploadValues(BASEURL, new NameValueCollection()
{
{ "x", lon },
{ "y", lat },
{"units", "feet" },
{"output","json" },
});
string result = System.Text.Encoding.UTF8.GetString(response);
responseString = result;
}
return true;
}
catch(Exception eX)
{
return false;
}
}
}
The error I am getting is as below:
<error>General failure: Invalid Coordinates</error>
Moreover has anyone tried the .gov website to get elevation data. I used the google server however it has many restrictions related to number of requests and I am trying to do many requests for a given area.
Below is a website for verifying the lat and longs with a good json response.
https://nationalmap.gov/epqs/
Thanks all.
I have also tried the following example here:
http://ronaldrosiernet.azurewebsites.net/Blog/2013/12/07/posting_urlencoded_key_values_with_httpclient
But is giving me the following error.
Exception thrown: 'System.NullReferenceException'
I modified the code to this:
public async Task<string> HTTPPOST(string lon, string lat)
{
var client = new HttpClient();
client.BaseAddress = new Uri(BASEURL);
var request = new HttpRequestMessage(HttpMethod.Post, "");
var keyValues = new List<KeyValuePair<string, string>>();
keyValues.Add(new KeyValuePair<string, string>("x", lon));
keyValues.Add(new KeyValuePair<string, string>("y", lat));
keyValues.Add(new KeyValuePair<string, string>("units", "feet"));
keyValues.Add(new KeyValuePair<string, string>("output", "json"));
request.Content = new FormUrlEncodedContent(keyValues);
var response = await client.SendAsync(request);
return response.ToString();
}
After debugging for an hour I noticed that I had units as a parameter rather than unit :( ......
public string httpPostElevationRequest( string lon,string lat)
{
try
{
using (WebClient client = new WebClient())
{
byte[] response =
client.UploadValues(BASEURL, new NameValueCollection()
{
{ "x", lon },
{ "y", lat },
{"unit", "feet" },
{"output","json" },
});
string result = System.Text.Encoding.UTF8.GetString(response);
responseString = result;
}
return responseString;
}
catch(Exception eX)
{
return null;
}
}
Also baseurl is as follows:
private string BASEURL = "https://nationalmap.gov/epqs/pqs.php";
Use .NET HttpClient
Find an example here

Categories