I'm trying to download a file from a server and adding authentication and range header in my app, so is this syntax correct?
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
request.Headers["Range"] = "bytes=0-";
request.Credentials = new NetworkCredential("username","password");
Of course the code has other parts for reading the file as a stream and storing it but i'm concerned with the range header and authentication part because it's not working.
I get an exception
{"The 'Range' header must be modified using the appropriate property or method.\r\nParameter name: name"}
Here's how to do it:
public async Task<byte[]> DownloadFileAsync(string requestUri)
{
// Service URL
string serviceURL = "http://www.example.com";
// Http Client Handler and Credentials
HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClientHandler.Credentials = new NetworkCredential(username, passwd, domain);
// Initialize Client
HttpClient client = new HttpClient(httpClientHandler)
client.BaseAddress = new Uri(serviceURL);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/bson"));
// Add Range Header
client.DefaultRequestHeaders.Add("Range", "bytes=0-");
// Deserialize
MemoryStream result = new MemoryStream();
Stream stream = await client.GetStreamAsync(requestUri);
await stream.CopyToAsync(result);
result.Seek(0, SeekOrigin.Begin);
// Bson Reader
byte[] output = null;
using (BsonReader reader = new BsonReader(result))
{
var jsonSerializer = new JsonSerializer();
output = jsonSerializer.Deserialize<byte[]>(reader);
}
return output;
}
I'm current using the BSON media format. If you need addtional information regarding BSON in your backend, herre's a great article on how to implement it and consume it:
http://www.strathweb.com/2012/07/bson-binary-json-and-how-your-web-api-can-be-even-faster/
Here is another way to do it
var httpClientHandler = new HttpClientHandler();
httpClientHandler.Credentials = new System.Net.NetworkCredential("username", "password");
var client = new HttpClient(httpClientHandler);
System.Net.Http.HttpRequestMessage request = new System.Net.Http.HttpRequestMessage(HttpMethod.Post, new Uri(url));
request.Headers.Range = new RangeHeaderValue(0, null);
HttpResponseMessage response = await client.SendAsync(request);
Related
I'm fairly new to use HTTPClient and sending REST requests to APIs, I'm currently practicing multipart upload using this Google Drive API endpoint:
POST https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart
There's an instruction that states there to split the request body into two parts, I tried to recreate this but was unable to do so.
https://developers.google.com/drive/api/guides/manage-uploads#multipart
Here's my current code:
async void UploadFile(StorageFile fileName)
{
using (HttpClient client = new HttpClient())
{
// Opens files and convert it to stream
var resultStream = await fileName.OpenReadAsync();
var fileStreamContent = new StreamContent(resultStream.AsStream());
// Create file MetaData
var fileMetaData = JsonConvert.SerializeObject(
new { name = fileName.Name, mimetype = fileName.ContentType });
// Create POST request
var requestMessage = new HttpRequestMessage(HttpMethod.Post, uploadFileEndpoint);
requestMessage.Headers.Authorization = new AuthenticationHeaderValue(tokenType, accessToken);
// Add request body
requestMessage.Content = new StringContent(fileMetaData, Encoding.UTF8, "application/json");
requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/related");
var response = await client.SendAsync(requestMessage);
string responseString = await response.Content.ReadAsStringAsync();
output(responseString);
}
}
Any help would be greatly appreciated, thank you!
According to the documentation on Perform a multipart upload (HTTP tab), you need the MultipartFormDataContent as suggested by #Jeremy.
There are a few things needed to perform/migrate:
Add AuthenticationHeaderValue into client.DefaultRequestHeaders.Authorization.
Create a StreamContent instance, fileStreamContent (which you have done) and specify its Headers.ContentType.
Create a StringContent instance, stringContent (which you have done).
Append both StreamContent and StringContent into the MultipartFormDataContent instance, formData.
Specify the formData's Headers.ContentType as requested in API docs.
Post the formData with await client.PostAsync(/* API Url */, formData);
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(tokenType, accessToken);
// Opens files and convert it to stream
var resultStream = await fileName.OpenReadAsync();
var fileStreamContent = new StreamContent(resultStream.AsStream());
fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue(fileName.ContentType);
// Create file MetaData
var fileMetaData = JsonConvert.SerializeObject(new { name = fileName.Name, mimetype = fileName.ContentType });
var stringContent = new StringContent(fileMetaData, Encoding.UTF8, "application/json");
// Create POST request
MultipartFormDataContent formData = new MultipartFormDataContent();
formData.Add(stringContent, "metadata");
formData.Add(fileStreamContent, "media");
formData.Headers.ContentType = new MediaTypeHeaderValue("multipart/related");
var response = await client.PostAsync(uploadFileEndpoint, formData);
string responseString = await response.Content.ReadAsStringAsync();
}
I'm sending a POST request with a press of a button and what I'm getting back is an error telling me:
No MediaTypeFOrmatter is available to read an object of type 'Byte[]' from content with media type 'audio/wav'.
When sending the request, fiddler shows me a positive reply and I can play the audio in the WebView tab with no problem.
What I want is to properly store all bytes into an array that I can leter use to write a .wav file.
What can be done here?
Code:
var handler = new HttpClientHandler();
// If you are using .NET Core 3.0+ you can replace `~DecompressionMethods.None` to `DecompressionMethods.All`
handler.AutomaticDecompression = ~DecompressionMethods.None;
using (var httpClient = new HttpClient(handler))
{
using (var request = new HttpRequestMessage(new HttpMethod("POST"), URL))
{
string uri = URL;
request.Content = new StringContent("{\"audio_file\":\"dog\",\"doc\":\"" + Input.Text + "\"}");
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
//send
var send = await httpClient.SendAsync(request);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
// Error is here
result.Content = new ByteArrayContent(send.Content.ReadAsAsync<byte[]> ().Result); // <----- Error is here
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
//File.WriteAllBytes("output.wav", bytes);
}
}
I need to recreate this request I made in Postman with C#, I found that the HttpClient class solves most of my problems, but this time I couldn't solve it on my own.
I embbeded an image with an example of the very post request.
POST REQUEST IN POSTMAN
There are three text paramethers and one file I need to send, with a content-type of form-data, the file needs to be a .json.
I tried constructing the POST request in many ways; this is my last version:
string endpoint = $"{Endpoint}/captcha";
string token_paramsJSON = JsonConvert.SerializeObject(v3Request.token_params);
Hashtable ParametrosPOSTCaptcha = GetV3POSTParams(v3Request);
UnicodeEncoding uniEncoding = new UnicodeEncoding();
using (Stream ms = new MemoryStream()) {
var sw = new StreamWriter(ms, uniEncoding);
sw.Write(token_paramsJSON);
sw.Flush();
ms.Seek(0, SeekOrigin.Begin);
using (MultipartFormDataContent form = new MultipartFormDataContent())
{
form.Add(new StringContent(v3Request.username), "username");
form.Add(new StringContent(v3Request.password), "password");
form.Add(new StringContent(v3Request.type.ToString()), "type");
form.Add(new StreamContent(ms));
var response = await _httpClient.PostAsync(endpoint, form);
string ResponseTest = await GetResponseText(response);
}
}
With this code, I successfully establish a connection with the endpoint, send the username and password.
But the response differs from the one I get with Postman using the same paramethers:
Postman: x=0&xx=1892036372&xxx=&xxxxx=1
The actual response I get is this:
HttpClient: {"error": "not-logged-in"}
Thanks in advance!
Finally, I could solve it using the following implementation:
string endpoint = $"{Endpoint}/endpointName";
string token_paramsJSON = JsonConvert.SerializeObject(v3Request.token_params, Formatting.Indented);
Dictionary<string,string> PostParams = GetPOSTParams(v3Request);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, endpoint);
UnicodeEncoding uniEncoding = new UnicodeEncoding();
using (MultipartFormDataContent form = new MultipartFormDataContent())
{
foreach(var field in PostParams)
{
StringContent content = new StringContent(field.Value);
content.Headers.ContentType = null;
form.Add(content, field.Key);
}
var JsonFile = new StringContent(token_paramsJSON);
JsonFile.Headers.ContentType = new MediaTypeHeaderValue("application/json");
JsonFile.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "\"token_params\"",
FileName = "\"token.json\""
};
form.Add(JsonFile);
request.Content = form;
var response = await _httpClient.SendAsync(request, CancellationToken.None);
return await GetCaptchaFromResponse(response);
}
I am trying to call multiple rest services from the Web API I am creating and I am getting the below error while one of the Sharepoint rest service is called
This instance has already started one or more requests. Properties can only be modified before sending the first request.
Below is the code for calling the rest services using the HttpClient
try
{
var credential = new NetworkCredential(userName_SP, password_SP, domain_SP);
var myCache = new CredentialCache();
myCache.Add(new Uri(core_URL), "NTLM", credential);
var handler = new HttpClientHandler();
handler.AllowAutoRedirect = true;
handler.Credentials = myCache;
using (var client_sharePoint = new HttpClient(handler))
{
var response = client_sharePoint.GetAsync(core_URL).Result;
client_sharePoint.BaseAddress = uri;
client_sharePoint.DefaultRequestHeaders.Accept.Clear();
client_sharePoint.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var responsedata = await response.Content.ReadAsStringAsync();
var returnObj = JsonConvert.DeserializeObject<SharepointDTO.RootObject>(
responsedata);
return returnObj;
}
...
I have never encountered this error before. Can anyone please suggest me if I need set the timeout
Try this:
var credential = new NetworkCredential(userName_SP, password_SP, domain_SP);
var myCache = new CredentialCache();
myCache.Add(new Uri(core_URL), "NTLM", credential);
var handler = new HttpClientHandler();
handler.AllowAutoRedirect = true;
handler.Credentials = myCache;
using (var client_sharePoint = new HttpClient(handler))
{
client_sharePoint.BaseAddress = uri;
client_sharePoint.DefaultRequestHeaders.Accept.Clear();
client_sharePoint.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client_sharePoint.GetAsync(core_URL);
var responsedata = await response.Content.ReadAsStringAsync();
var returnObj = JsonConvert.DeserializeObject<SharepointDTO.RootObject>(
responsedata);
return returnObj;
}
Headers and BaseAddress must be set before you make the request with GetAsync.
I also took the liberty to change from .Result to await since calling .Result is poor practice and I can see this is in an async method.
You should also read this: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
I'm converting JAVA program to C# that send https request to server. Here is my program that log in to server and then log-out from server.
var login_httpWebRequest = (HttpWebRequest)WebRequest.Create(m_base_url + "session/login");
login_httpWebRequest.ContentType = "application/json; charset=UTF-8";
var logout_httpWebRequest = (HttpWebRequest)WebRequest.Create(m_base_url + "session/logout");
logout_httpWebRequest.ContentType = "application/json; charset=UTF-8";
CookieContainer cookieJar = new CookieContainer();
login_httpWebRequest.CookieContainer = cookieJar;
using (StreamWriter streamWriter = new StreamWriter(login_httpWebRequest.GetRequestStream()))
{
streamWriter.Write("{username:xxxxxx,password:yyyyyyy}");
}
var httpResponse = (HttpWebResponse)login_httpWebRequest.GetResponse();
var login_cookies = httpResponse.Cookies;
logout_httpWebRequest.CookieContainer = new CookieContainer();
httpWebRequest.CookieContainer.Add(login_cookies);
using (StreamWriter streamWriter = new StreamWriter(logout_httpWebRequest.GetRequestStream()))
{
streamWriter.Write("{}");
}
var httpResponse = (HttpWebResponse)login_httpWebRequest.GetResponse();
But my C# program takes more time than the original JAVA program and then I checked the request using Fiddler tool. So I found for every request C# Tunnel to server. but JAVA program only once.
Bellow image
Green color shows requests (tunnel->login->logout) sent to server by JAVA program.
Red color shows C# program requests(tunnel->login->tunnel->logout) sent to server by C# program.
Anyone knows how to avoid tunneling for each request by C# Http client.
Have you tried using HttpClient instead of WebRequest? I wrote this up with no way to test it so hopefully it's close....
using (HttpClientHandler handler = new HttpClientHandler())
{
CookieContainer cookies = new CookieContainer();
handler.CookieContainer = cookies;
using (HttpClient httpClient = new HttpClient(handler))
{
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json; charset=UTF-8"));
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, m_base_url + "session/login");
requestMessage.Content = new StringContent("{username:xxxxxx,password:yyyyyyy}"); ;
HttpResponseMessage loginResponse = await httpClient.SendAsync(requestMessage);
// The HttpClient should already have the cookies from the login so
// no need to transfer
requestMessage = new HttpRequestMessage(HttpMethod.Get, m_base_url + "session/logout");
requestMessage.Content = new StringContent("{}");
HttpResponseMessage logoutResponse = await httpClient.SendAsync(requestMessage);
}
}