I am trying to post some unicode data using Http request message. Somehow content encoding is causing some issue. I am not setting any encoding explicitly in my code.
For example, I am trying to send 'รัค' & on client side it is being received as 'รัà¸'.
Sample code
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer, })
using(var httpClient = new HttpClient(handler)){
//set all cookies
foreach (var obj in configurationData["request_cookies"])
{
var cookie = ((JProperty)(obj));
cookieContainer.Add(new Uri(configurationData["request_cookie_base_url"].ToString()),
new Cookie(cookie.Name, HttpUtility.UrlEncode(cookie.Value.ToString())));
}
var request = new HttpRequestMessage();
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(configurationData["form_url"].ToString());
//set all request headers
foreach (var obj in configurationData["request_headers"])
{
var cookie = ((JProperty) (obj));
request.Headers.Add(cookie.Name, cookie.Value.ToString());
}
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
//get request content data from configurationData as keyvalue pair
var contentValue = parsedCrmConfigurationData["form_data_template"]
.ToObject<Dictionary<string, string>>();
request.Content = new FormUrlEncodedContent(contentValue);
var response = httpClient.SendAsync(request).Result;
response.EnsureSuccessStatusCode();
}
Do I need to pass encoding specifically? if yes then how?
Please help me understand the issue.
you can use below code to encode your content
private static HttpContent getencodedContent(string jsonString)
{
var cont = new StringContent(jsonString, Encoding.UTF8, "application/json");
return cont;
}
Related
I am writing code in C# to consume POST API that accepts form-body with the following parameters.
Files[Array] (User can send multiple files in request)
TemplateId[Int]
Also, I need to pass the bearer AuthToken as a header in the HTTP client Post Request.
I need some help writing the HTTP request with the above form data.
using (var client = new HttpClient())
{
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, $" {_apiBaseUri}/{route}");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue($"Bearer {authToken}");
var pdfFiles = Directory.GetFiles($"C:\\files", "*.pdf");
foreach (var filename in pdfFiles)
{
// create array[] of each File and add them to the form data request
}
// Add TemplateId in the form data request
}
postman request
swagger request
you can add files with 'MultipartFormDataContent'.
private static async Task UploadSampleFile()
{
var client = new HttpClient
{
BaseAddress = new("https://localhost:5001")
};
await using var stream = System.IO.File.OpenRead("./Test.txt");
using var request = new HttpRequestMessage(HttpMethod.Post, "file");
using var content = new MultipartFormDataContent
{
{ new StreamContent(stream), "file", "Test.txt" }
};
request.Content = content;
await client.SendAsync(request);
}
for more: https://brokul.dev/sending-files-and-additional-data-using-httpclient-in-net-core
The Below Code change worked for me,
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("POST"), _apiBaseUri))
{
request.Headers.TryAddWithoutValidation("Authorization", $"Bearer {authToken}");
var pdfFiles = Directory.GetFiles($"C:\\test", "*.pdf");
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(new StringContent("100"), "templateId");
foreach (var filename in pdfFiles)
{
multipartContent.Add(new ByteArrayContent(File.ReadAllBytes(filename)), "files", Path.GetFileName(filename));
}
request.Content = multipartContent;
var response = await httpClient.SendAsync(request);
}
}
I am doing a request through postman to a specific url but I set the form-data type in order to get data to the site like this:
Now I want to program this request inside C# but everything I tried so far is returning a 400 Bad Request response. This is what I tried:
public async Task<CheckAccessTokenModel> CheckAccessTokenAsync(string accessToken)
{
string uriString = "someurl";
var uri = new Uri(uriString);
try
{
using(var httpClient = new HttpClient())
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = uri
};
var ClientId = ConfigurationAccessor.Configuration["WebCredentials:ClientId"];
var Secret = ConfigurationAccessor.Configuration["WebCredentials:Secret"];
var authString = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{ClientId}:{Secret}"));
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authString);
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(new StringContent("token"), accessToken);
request.Content = content;
var response = await httpClient.SendAsync(request);
var checkTokenResponseData = await response.Content.ReadAsStringAsync();
//return new CheckAccessTokenModel { Active = true, Exp = 1647431224233 };
return JsonConvert.DeserializeObject<CheckAccessTokenModel>(checkTokenResponseData);
}
}
catch
{
return null;
}
}
I am doing it with the MultipartFormDataContent Object as suggested by many others here but it still won't work.
What can be the problem here?
EDIT: Wrong picture replaced
You can simply
request.Content = new StringContent($"token={accessToken}");
With form data I think it's something like this:
var data = new Dictionary<string, string>
{
{"token", acccessToken}
};
using var content = new FormUrlEncodedContent(data);
request.Content = content;
I am trying to upload image to ServiceNow incident using SNow API provided in this link:
https://developer.servicenow.com/dev.do#!/reference/api/orlando/rest/c_AttachmentAPI#r_AttachmentAPI-POSTmultipart
I've written below C# code to post the image:
string url = "https://mycompany.service-now.com/api/now/attachment/upload/"
, userName = "MyUser", passwd = "MyPassword";
var httpClientHandler = new HttpClientHandler()
{
Credentials = new NetworkCredential(userName, passwd),
};
using (var httpClient = new HttpClient(httpClientHandler))
{
// Add an Accept header for JSON format.
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var multipartContent = new MultipartFormDataContent();
multipartContent.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data");
multipartContent.Add(new StringContent("incident"), "table_name");
multipartContent.Add(new StringContent("f264fd3a1bghghgjjhg8f7b4bcbb6"), "table_sys_id"); // id of my incident
multipartContent.Add(new ByteArrayContent(File.ReadAllBytes("D:\\MyImage.jpeg")), "uploadFile", "MyImage.jpeg");
var response = httpClient.PostAsync(new Uri(url), multipartContent).Result;
string result = response.Content.ReadAsStringAsync().Result;
MessageBox.Show(result);
}
However, I keep getting:
Requested URI does not represent any resource
What could be the problem and how to adjust the code accordingly?
After removing the "/" at the end of the url, and also adding double qoutes around the keys in the headers as I read from this post:
https://community.servicenow.com/community?id=community_question&sys_id=328614ffdb00eb808e7c2926ca9619ad&view_source=searchResult
The final working code is:
string url = "https://mycompany.service-now.com/api/now/attachment/upload"
, userName = "MyUser", passwd = "MyPassword";
var httpClientHandler = new HttpClientHandler()
{
Credentials = new NetworkCredential(userName, passwd),
};
using (var httpClient = new HttpClient(httpClientHandler))
{
// Add an Accept header for JSON format.
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var fileStream = new ByteArrayContent(File.ReadAllBytes("D:\\Image.jpeg"));
fileStream.Headers.Remove("Content-Type");
fileStream.Headers.Add("Content-Type", "application/octet-stream");
fileStream.Headers.Add("Content-Transfer-Encoding", "binary");
fileStream.Headers.Add("Content-Disposition", $"form-data;name=\"uploadFile\"; filename=\"{"Image.jpeg"}\"");
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(new StringContent("incident"), "\"table_name\"");
multipartContent.Add(new StringContent("f264fd3a1bghghgjjhg8f7b4bcbb6"), "\"table_sys_id\"");
multipartContent.Add(fileStream, "uploadFile");
var response = httpClient.PostAsync(new Uri(url), multipartContent).Result;
string result = response.Content.ReadAsStringAsync().Result;
MessageBox.Show(result);
}
I'm trying to find the redirect url using the headers, so I googled around and found a few examples:
Header[] arr = httpResponse.getHeaders("Location");
for (Header head : arr){
String whatever = arr.getValue();
}
AND
HttpPost request1 = new HttpPost("https://hrlink.healthnet.com/");
HttpResponse response1 = httpclient.execute(request1);
// expect a 302 response.
if (response1.getStatusLine().getStatusCode() == 302) {
String redirectURL = response1.getFirstHeader("Location").getValue();
// no auto-redirecting at client side, need manual send the request.
HttpGet request2 = new HttpGet(redirectURL);
HttpResponse response2 = httpclient.execute(request2);
... ...
}
Where they get "Location" from header, however I am not able to pull the "Location" out of the HttpResponseMessage from my version, I tried moving things here and there but it does not contain the method to accept the parameter, how am I able to get the redirect URL using httpClient?
var client = new HttpClient();
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("username", "---"),
new KeyValuePair<string, string>("password", "---")
};
var content = new FormUrlEncodedContent(pairs);
var response = client.PostAsync(uri, content).Result;
HttpHeaders headerlist = response.Headers;
foreach (var header in headerlist)
{
//Red line on header("Location")
label1.Text += header("Location") + "\n";
}
Just for test, with www.google.com you can test redirection:
var request = (HttpWebRequest) WebRequest.Create("http://www.google.com");
request.AllowAutoRedirect = false;
using (var response = (HttpWebResponse) request.GetResponse())
{
string location = response.Headers["Location"];
Console.WriteLine(location);
}
This is my recent code:
HttpClient authClient = new HttpClient();
authClient.BaseAddress = new Uri("http://localhost:4999/test_db/_session");
authClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var user = new LoginUserSecretModel
{
name = userKey,
password = loginData.Password,
};
HttpResponseMessage authenticationResponse = authClient.PostAsJsonAsync("", user).Result;
The issue I have with many of the answers here is that using CookieContainer uses short-lived HttpClient objects which is not recommended.
Instead, you can simply read the "Set-Cookie" header from the response:
// httpClient is long-lived and comes from a IHttpClientFactory
HttpResponseMessage response = await httpClient.GetAsync(uri);
IEnumerable<string> cookies = response.Headers.SingleOrDefault(header => header.Key == "Set-Cookie").Value;
If the "Set-Cookie" header is not present, cookies will be null.
Try this:
CookieContainer cookies = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookies;
HttpClient authClient = new HttpClient(handler);
var uri = new Uri("http://localhost:4999/test_db/_session");
authClient.BaseAddress = uri;
authClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var user = new LoginUserSecretModel
{
name = userKey,
password = loginData.Password,
};
HttpResponseMessage authenticationResponse = authClient.PostAsJsonAsync("", user).Result;
var responseCookies = cookies.GetCookies(uri).Cast<Cookie>();
This is what you need to get a list of cookies;
private async Task<List<Cookie>> GetCookies(string url, string cookieName)
{
var cookieContainer = new CookieContainer();
var uri = new Uri(url);
using (var httpClientHandler = new HttpClientHandler
{
CookieContainer = cookieContainer
})
{
using (var httpClient = new HttpClient(httpClientHandler))
{
await httpClient.GetAsync(uri);
List<Cookie> cookies = cookieContainer.GetCookies(uri).Cast<Cookie>().ToList();
return cookies;
}
}
}
and if you need only one cookie value here's how
private async Task<string> GetCookieValue(string url)
{
var cookieContainer = new CookieContainer();
var uri = new Uri(url);
using (var httpClientHandler = new HttpClientHandler
{
CookieContainer = cookieContainer
})
{
using (var httpClient = new HttpClient(httpClientHandler))
{
await httpClient.GetAsync(uri);
var cookie = cookieContainer.GetCookies(uri).Cast<Cookie>().FirstOrDefault(x => x.Name == cookieName);
return cookie?.Value;
}
}
}
Building on top of Daniel's answer and this answer to another question, this would be an easy way to read the cookies from an HTTP response.
// httpClient is long-lived and comes from a IHttpClientFactory
HttpResponseMessage response = await httpClient.GetAsync(uri);
CookieContainer cookies = new CookieContainer();
foreach (var cookieHeader in response.Headers.GetValues("Set-Cookie"))
cookies.SetCookies(uri, cookieHeader);
string cookieValue = cookies.GetCookies(uri).FirstOrDefault(c => c.Name == "MyCookie")?.Value;