HttpRequst with parameters not workign - c#

I am trying to make post request which works one way but other not.
Here is example how it works:
HttpClient client = new HttpClient();
string baseUrl = "https://192.168.56.1:45456/User/GetToken";
var response = await client.PostAsync(baseUrl + "?username=*******&password=****", null);
but then when I try adding it "normal way" at the endpoint i am getting nulls.
Here is how I try doing it:
HttpClient client = new HttpClient();
string baseUrl = "https://192.168.56.1:45456/User/GetToken";
Dictionary<string, string> parameters = new Dictionary<string, string>() { { "username", "ALEKS13" }, { "password", "asd" } };
FormUrlEncodedContent encodedParameters = new FormUrlEncodedContent(parameters);
var response = await client.PostAsync(baseUrl, encodedParameters);
What am I doing wrong in second code?
Here is receiving code:
[HttpPost]
[Route("/User/GetToken")]
public async Task<IActionResult> GetToken(string username, string password)
{
return await Task.Run<IActionResult>(() =>
{
if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
return StatusCode(400);
Models.User user = Models.User.Get(username);
if (user.ValidatePassword(password))
return StatusCode(200, APIAuthorization.GenerateToken(username));
return StatusCode(403);
});
}

Related

How to get body content in a http client call?

I am unable to get body content in this http client call, because I can't figure out how to get the actual content of the request in this async method.
Here's the async method:
public async Task<HttpResponseMessage> AuthenticateUser(string username, string password)
{
var client = new HttpClient();
var requestUri = new Uri($"{_authorityBaseUrl}/{_tenantID}/oauth2/token");
var authenticationBody = CreatePasswordGrantConsent(username,password);
return await client.PostAsync(requestUri, authenticationBody);
}
Here's the method that I wanna get the body content from
protected void loginBtn_Click(object sender, EventArgs e)
{
AADConnector connector = new AADConnector();
var result = connector.AuthenticateUser("username", "password").Result.Content;
}
I've tried in AuthenticateUser method to change to :
public async Task<string>(string username , string password)
{
...
...
var response = await client.PostAsync(requestUri, authenticationBody);
var contents = await response.Content.ReadAsStringAsync();
return contents;
}
And change in loginBtn_Click to :
AADConnector connector = new AADConnector();
Task<string> result = connector.AuthenticateUser("username","password");
var finalResult = result.Result;
But it just deadlocks and it keeps running forever.
Can you guys explain me why this happens?
Here is how I did it:
public async Task<string> AuthenticateUser(string username, string password)
{
var client = new HttpClient();
var requestUri = new Uri($"{_authorityBaseUrl}/{_tenantID}/oauth2/token");
var authenticationBody = CreatePasswordGrantConsent(username, password);
var response = await client.PostAsync(requestUri, authenticationBody);
var result = await response.Content.ReadAsStringAsync();
return result;
}
AADConnector connector = new AADConnector();
var result = Task.Run(async () => await connector.AuthenticateUser("username", "password"));
try {
result.Wait();
} catch {
}
dynamic data = JObject.Parse(result.Result);
string token = (string)data.access_token;

Very slow HttpClient SendAsync call

After reading other answers I can't realize why SendAsync is so slow.
Calling same endpoint from Postman, I got a response in 160ms.
Calling from the code below, takes 10 seconds. I'm using a c# desktop application to make the call.
public static async Task<string> GetToken()
{
var url = "....";
var dict = new Dictionary<string, string>();
dict.Add("username", "foo");
dict.Add("password", "bar");
using (var client = new HttpClient(
new HttpClientHandler
{
Proxy = null,
UseProxy = false
}))
{
//bypass SSL
ServicePointManager.ServerCertificateValidationCallback = new
RemoteCertificateValidationCallback
(
delegate { return true; }
);
var req = new HttpRequestMessage(HttpMethod.Post, url) { Content = new FormUrlEncodedContent(dict) };
var res = await client.SendAsync(req); //10 seconds here!
if (res.StatusCode != HttpStatusCode.OK)
return string.Empty;
var token = await JsonConvert.DeserializeObject<TokenResponse>(res.Content.ReadAsStringAsync());
return token.access_token;
}
}
Your code is tangled and ignores IDisposable and this: HttpClient is intended to be instantiated once per application, rather than per-use.
Make reusable method for other-type requests
private static readonly HttpClient client = new HttpClient();
private async Task<T> PostDataAsync<T>(string url, Dictionary<string, string> formData)
{
using (HttpContent content = new FormUrlEncodedContent(formData))
using (HttpResponseMessage response = await client.PostAsync(url, content).ConfigureAwait(false))
{
response.EnsureSuccessStatusCode(); // throws if 404, 500, etc.
string responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject<T>(responseText);
}
}
Usage
public static async Task<string> GetToken()
{
var url = "....";
var dict = new Dictionary<string, string>();
dict.Add("username", "foo");
dict.Add("password", "bar");
try
{
TokenResponse token = await PostDataAsync<TokenResponse>(url, dict);
return token.access_token;
}
catch (HttpRequestException ex)
{
// handle Exception here
return string.Empty;
}
}

Even with a successful access Token I get a 401 unauthorized in my Get() async method?

Currently I have to async methods Post() & Get(). For my Post() method is returning a access token and if you look at the bottom of my post method I am calling my Get() in there also, for the simple reason of being able to call string result in my get. but even with a successful access token I Keep getting a 401 unauthorized Status code, why?
Click to view error in VS
namespace APICredential.Controllers
{
[RoutePrefix("api")]
public class ValuesController : ApiController
{
[HttpGet, Route("values")]
public async Task<string> Post()
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("https://api.elliemae.com/oauth2/");
var parameters = new Dictionary<string, string>()
{
{"grant_type", "password"}, //Gran_type Identified here
{"username", "admin#encompass:BE11200822"},
{"password", "Shmmar****"},
{"client_id", "gpq4sdh"},
{"client_secret", "dcZ42Ps0lyU0XRgpDyg0yXxxXVm9#A5Z4ICK3NUN&DgzR7G2tCOW6VC#HVoZPBwU"},
{"scope", "lp"}
};
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "v1/token")
{
Content = new FormUrlEncodedContent(parameters)
};
HttpResponseMessage response = await client.SendAsync(request);
string resulted = await response.Content.ReadAsStringAsync();
await Get(resulted);
return resulted;
}
}
[HttpGet, Route("values/get")]
public async Task<string> Get(string resulted)
{
string res = "";
using (var client = new HttpClient())
{
// HTTP POST
client.BaseAddress = new Uri("https://api.elliemae.com/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync("/encompass/v1/loans/{ea7c29a6-ee08-4816-99d2-fbcc7d15731d}?Authorization=Bearer "+resulted+"&Content-Type=application/json").Result;
using (HttpContent content = response.Content)
{
// ... Read the string.
Task<string> result = content.ReadAsStringAsync();
res = result.Result;
}
}
return res;
}
The following is missing:
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + Accesstoken);
This is your default header once you insert this then you have premission to getstring data from whatever your URL is...
code will look like this:
public async Task<string> Get(string Accesstoken)
{
string res = "";
using (var client = new HttpClient())
{
Accesstoken = Accesstoken.Substring(17, 28);
client.BaseAddress = new Uri("https://api.elliemae.com/");
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + Accesstoken);
var response = client.GetAsync("encompass/v1/loans/ea7c29a6-ee08-4816-99d2-fbcc7d15731d").Result;
using (HttpContent content = response.Content)
{
// ... Read the string.
Task<string> result = content.ReadAsStringAsync();
res = result.Result;
}

How to PATCH data using System.Net.Http

I have uploaded a file to SharePoint and found out what id it has. Now I need to update some of the other columns on that listitem. The problem is that System.Net.Http.HttpMethod.Patch doesn't exist.
public static async Task<string> UpdateFileData()
{
var (authResult, message) = await Authentication.AquireTokenAsync();
string updateurl = MainPage.rooturl + "lists/edd49389-7edb-41db-80bd-c8493234eafa/items/" + fileID + "/";
var httpClient = new HttpClient();
HttpResponseMessage response;
try
{
var root = new
{
fields = new Dictionary<string, string>
{
{ "IBX", App.IBX }, //column to update
{ "Year", App.Year}, //column to update
{ "Month", App.Month} //column to update
}
};
var s = new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat };
var content = JsonConvert.SerializeObject(root, s);
var request = new HttpRequestMessage(HttpMethod.Put, updateurl);
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken);
request.Content = new StringContent(content, Encoding.UTF8, "application/json");
response = await httpClient.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
catch (Exception ex)
{
return ex.ToString();
}
}
Modify the code as below.
public static async Task<string> UpdateFileData()
{
var (authResult, message) = await Authentication.AquireTokenAsync();
string updateurl = MainPage.rooturl + "lists/edd49389-7edb-41db-80bd-c8493234eafa/items/" + fileID + "/";
var httpClient = new HttpClient();
HttpResponseMessage response;
try
{
var root = new
{
fields = new Dictionary<string, string>
{
{ "IBX", App.IBX }, //column to update
{ "Year", App.Year}, //column to update
{ "Month", App.Month} //column to update
}
};
var s = new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat };
var content = JsonConvert.SerializeObject(root, s);
var request = new HttpRequestMessage(new HttpMethod("PATCH"), updateurl);
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken);
request.Content = new StringContent(content, System.Text.Encoding.UTF8, "application/json;odata=verbose");
response = await httpClient.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
catch (Exception ex)
{
return ex.ToString();
}
}
Or we can also use REST API to update list item by ID.
Refer to: SharePoint 2013 REST Services using C# and the HttpClient
It dependents whether .NET Core or .NET Framework is utilized, in case of `.NET Core HttpClient.PatchAsync Method could be utilized.
In case of .NET Framework ListItem could be updated like this:
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.BaseAddress = new Uri("https://graph.microsoft.com");
var listItemPayload = new Dictionary<string, object>
{
{"Color", "Fuchsia"},
{"Quantity", 934}
};
var requestContent = new StringContent(JsonConvert.SerializeObject(listItemPayload));
requestContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
var response = await client.PatchAsync(new Uri($"https://graph.microsoft.com/v1.0/sites/{siteId}/lists/{listId}/items/{itemId}/fields"), requestContent);
var data = response.Content.ReadAsStringAsync().Result.ToString();
}
where PatchAsync is the extension method for HttpClient class:
public static class HttpClientExtensions
{
public static async Task<HttpResponseMessage> PatchAsync(this HttpClient client, Uri requestUri, HttpContent iContent)
{
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, requestUri)
{
Content = iContent
};
HttpResponseMessage response = new HttpResponseMessage();
try
{
response = await client.SendAsync(request);
}
catch (TaskCanceledException e)
{
Debug.WriteLine("ERROR: " + e.ToString());
}
return response;
}
}
All the credits for extension method go to the author of this answer
Can't you just use the HttpMethod class constructor?
new HttpMethod("PATCH");
Source: https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpmethod.-ctor?view=netframework-4.7.2#System_Net_Http_HttpMethod__ctor_System_String_

Make a post Request with azure new rest api (ressource manager)

I want to start my VM using the post Uri as described here https://msdn.microsoft.com/en-us/library/azure/mt163628.aspx
Since i don't have body in my request i get 403 frobidden. I can make a get Request without problem. Here is my code
public void StartVM()
{
string subscriptionid = ConfigurationManager.AppSettings["SubscriptionID"];
string resssourcegroup = ConfigurationManager.AppSettings["ressourgroupename"];
string vmname = ConfigurationManager.AppSettings["VMName"];
string apiversion = ConfigurationManager.AppSettings["apiversion"];
var reqstring = string.Format(ConfigurationManager.AppSettings["apirestcall"] + "subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Compute/virtualMachines/{2}/start?api-version={3}", subscriptionid, resssourcegroup, vmname, apiversion);
string result = PostRequest(reqstring);
}
public string PostRequest(string url)
{
string content = null;
using (HttpClient client = new HttpClient())
{
StringContent stringcontent = new StringContent(string.Empty);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string token = GetAccessToken();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = client.PostAsync(url, stringcontent).Result;
if (response.IsSuccessStatusCode)
{
content = response.Content.ReadAsStringAsync().Result;
}
}
return content;
}
i've also tried this in the PostRequest
var values = new Dictionary<string, string>
{
{ "api-version", ConfigurationManager.AppSettings["apiversion"] }
};
var posteddata = new FormUrlEncodedContent(values);
HttpResponseMessage response = client.PostAsync(url, posteddata).Result;
with url=string.Format(ConfigurationManager.AppSettings["apirestcall"] + "subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Compute/virtualMachines/{2}/start", subscriptionid, resssourcegroup, vmname);
I Get 400 Bad request
I found the solution. Needed to add role in Azure to allow starting/stopping the VM. That is why i received 4.3 forbidden.
Thank you

Categories