decompressing a gzip encoded response - c#

I am using C# to write a small console app. The app needs to make a call to an API service to login.
I was able to make the call successfully. But, I am unable to decode the response
Here is my code
using (var client = new WebClient())
{
client.Headers.Add("User-Agent", "Console App");
client.Headers.Add("RETS-Version", "RETS/1.7.2");
client.Headers.Add("Accept-Encoding", "gzip");
client.Headers.Add("Accept", "*/*");
client.Credentials = new NetworkCredential("username", "password");
try
{
var response = client.DownloadData("url/login.ashx");
MemoryStream stream = new MemoryStream(response);
using (var stram = new GZipStream(stream, CompressionMode.Decompress ))
using (var file = File.Create("../../../Downloads/login_result.txt"))
{
stream.CopyTo(file);
}
} catch(Exception e)
{
}
}
However, the data that gets written to the login_result.txt file looks something like this
‹ í½`I–%&/mÊ{JõJ×àt¡€`$Ø#ìÁˆÍæ’ìiG#)«*ÊeVe]f#Ìí¼÷Þ{ï½÷Þ{ï½÷º;N'÷ßÿ?\fdlöÎ
How can I correctly decode the response?

Probably you should copy GZip decompressed stream and not the memory one:
using (var stram = new GZipStream(stream, CompressionMode.Decompress ))
using (var file = File.Create("../../../Downloads/login_result.txt"))
{
stram.CopyTo(file); //stream.CopyTo(file);
}

Related

How to stream zip file from TFS api

I am using TFS2018 api and I am trying to to retrieve the zip file of a solution but I always get an internal server error.
internal async Task<bool> GetSourceZipFile(string sourceVersionId)
{
using (var handler = new HttpClientHandler { Credentials = new NetworkCredential(tfsUser, tfsPass) })
using (var client = new HttpClient(handler))
{
try
{
client.BaseAddress = new Uri(tfsServer);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));
var tempFolder = "c:\\temp\\test";
tempFolder = HttpUtility.UrlEncode(tempFolder);
var url = $"DefaultCollection/_api/_versioncontrol/itemContentZipped?path={tempFolder}&version={sourceVersionId}";
using (var file = await client.GetStreamAsync(url).ConfigureAwait(false))
using (var memoryStream = new MemoryStream())
{
await file.CopyToAsync(memoryStream);
var s = memoryStream.ToArray();
var f = s;
};
}
catch (Exception ex)
{
// LOGGING
}
return true;
}
}
I am not sure if the zip file is generated by the TFS server. Do I need to set it specifically? Any idea why this is not working?
You're passing in a local folder to the path parameter in the REST API. The path should be to the item in source control (ex: $/MyTeamProject/DEV/SomeCode), not to the local file system.

How to send remote mp3 file to Telegram channel using Telegram Bot API's sendAudio method in C#

I create a bot (#mp3lyric_bot_test) in telegram and set it as administrator in my channel (#mp3lyric_test). Now I want to make a request to send an mp3 to channel using telegram api.
my mp3 is in web, something like this: http://bayanbox.ir/download/7028444634071302239/Sound-1.mp3
At first i download mp3 with this method:
public static Task<byte[]> DownloadAsync(string requestUriSt)
{
var requestUri = new Uri(requestUriSt);
byte[] fileBytes;
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
{
using (var responseMessage = await httpClient.SendAsync(request))
{
fileBytes = await responseMessage.Content.ReadAsByteArrayAsync();
var audioString = Encoding.UTF8.GetString(fileBytes, 0, fileBytes.Length);
}
}
}
return fileBytes;
}
if there is a way to send mp3 directly without download, please tell me how? thanks.
Then send that byte array (fileBytes) using this code:
my bot token is 247655935:AAEhpYCeoXA5y7V8Z3WrVcNJ3AaChORjfvw
using (var client = new HttpClient())
{
var uri = new Uri("https://api.telegram.org/bot247655935:AAEhpYCeoXA5y7V8Z3WrVcNJ3AaChORjfvw/sendAudio");
using (var multipartFormDataContent = new MultipartFormDataContent(
"SendAudio----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
{
multipartFormDataContent.Add(
new StringContent("#mp3lyric_test"),
string.Format("\"{0}\"", "chat_id")
);
multipartFormDataContent.Add(
new StreamContent(new MemoryStream(fileBytes)),
'"' + "audio" + '"'
);
using (var message = await client.PostAsync(uri, multipartFormDataContent))
{
var contentString = await message.Content.ReadAsStringAsync();
}
}
}
I have two error:
"Request Entity Too Large" when my mp3 is about 6mb or 7mb or ... (not using http://bayanbox.ir/download/7028444634071302239/Sound-1.mp3)
error_code:400, description:"Bad Request: URL must be in UTF-8" (after using that mp3 for test that is 28kb)
To send a new AudioFile you use the SendAudio method but with the InputFile field.
First create an InputFile object, then pass those bytes in the audio parameter of the SendAudio method
If you need to resend the same AudioFile to another user, then you can use the String option as the audio parameter in the SendAudio
I chaged my codes for send the byte array (fileBytes) and now it works:
using (var client = new HttpClient())
{
var uri = new Uri("https://api.telegram.org/bot247655935:AAEhpYCeoXA5y7V8Z3WrVcNJ3AaChORjfvw/sendAudio?chat_id=#mp3lyric_test");
using (var multipartFormDataContent = new MultipartFormDataContent())
{
var streamContent = new StreamContent(new MemoryStream(fileBytes));
streamContent.Headers.Add("Content-Type", "application/octet-stream");
streamContent.Headers.Add("Content-Disposition", "form-data; name=\"audio\"; filename=\"Sound-1.mp3\"");
multipartFormDataContent.Add(streamContent, "file", "Sound-1.mp3");
using (var message = await client.PostAsync(uri, multipartFormDataContent))
{
var contentString = await message.Content.ReadAsStringAsync();
}
}
}

Send file to service using Microsoft.Net.Http

I have a method:
private bool UploadFile(Stream fileStream, string fileName)
{
HttpContent fileStreamContent = new StreamContent(fileStream);
using (var client = new HttpClient())
{
using (var formData = new MultipartFormDataContent())
{
formData.Add(fileStreamContent, fileName, fileName);
var response = client.PostAsync("url", formData).Result;
return response.StatusCode == HttpStatusCode.OK;
}
}
}
}
That is sending the file to a WCF service, but looking at the Wireshark log of the post, the fileStream isn't being appended, just the filename. Do I need to do something else?
Use a ByteArrayContent instead of a stream content.
var fileContent = new ByteArrayContent(File.ReadAllBytes(fileName));
Then specify your content disposition header:
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = fileName
};
formData.Add(fileContent);
Turns out the fileStream wasn't getting to the method. Using context.Request.Files[0].InputStream seemed to be the culprite. Using .SaveAs and then reading it in as a byteArray and attaching that to the MultiPartFormDataContent worked.

c# HttpClient upload file to spring rest service

Problem:
I have a Java spring rest service to upload a file (large size).
I want use a .NET httpClient (or other .net client) to call upload service.
Questions:
It seems that best option to send large file is multi-part file, what's about interoperability ?
If it weren't possible, what is the best alternative ?
Thank you!
This is the answer:
I can send a file with multipart attachment from c# client to Java JAX Rest Webservice.
try
{
using (
var client = new HttpClient())
using (var form = new MultipartFormDataContent())
{
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
using (var fileContent = new StreamContent(stream)) {
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {FileName = fileName, DispositionType = DispositionTypeNames.Attachment, Name = "fileData"};
form.Add(fileContent);
// only for test purposes, for stable environment, use ApiRequest class.
response = client.PostAsync(url, form).Result;
}
}
}
return response.RequestMessage != null ? response.ReasonPhrase : null;
}
catch (Exception ex)
{
TraceManager.TraceError("Post Asyn Request to " + url + " \n" + ex.Message, ex);
throw;
}
HTTP is a standard that is independent of OS platforms and programming languages, so you shouldn't have any problems with interoperability in case your .net client complies with the standards.
java spring boot
#RequestMapping(value="/upload", method=RequestMethod.POST)
public #ResponseBody String upload(#RequestParam("FileParam") MultipartFile file){
InputStream fromClient=file.getInputStream();
...do stuff with the database/ process the input file...
c#
HttpClient client = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();
FileInfo file = new FileInfo(#"<file path>");
form.Add(new StreamContent(file.OpenRead()),"FileParam",file.Name);
HttpResponseMessage response = await client.PostAsync("http://<host>:<port>/upload", form);
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.ReasonPhrase);
Console.WriteLine(response.ToString());
Console.WriteLine(Encoding.ASCII.GetString(await response.Content.ReadAsByteArrayAsync()));

How do I download zip file in C#?

I use HTTP GET that downloads a zip file in a browser, something like https://example.com/up/DBID/a/rRID/eFID/vVID (not the exact url)
Now, when I try to do the same download in C# code(same GET method as above) for a desktop application, the zip file downloaded is not a valid archive file. When I opened this file in notepad, it was some HTML page.
I think I'm not setting some header correctly. I looked around for examples. I'd found several wrt uploads, but did not see anything for downloads.
Code:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.ContentType = "application/zip";
try
{
HttpWebResponse res = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(res.GetResponseStream(), System.Text.Encoding.Default))
{
StreamWriter oWriter = new StreamWriter(#"D:\Downloads\1.zip");
oWriter.Write(sr.ReadToEnd());
oWriter.Close();
}
res.Close();
}
catch (Exception ex)
{
}
It's mainly because you use a StreamWriter : TextWriter to handle a binary Zip file. A StreamWriter expects text and will apply an Encoding. And even the simple ASCII Encoder might try to 'fix' what it thinks are invalid line-endings.
You can replace all your code with:
using (var client = new WebClient())
{
client.DownloadFile("http://something", #"D:\Downloads\1.zip");
}
Note that for new code you should look at HttpClient instead of WebClient.
And then don't use using( ) { }
You could just use WebClient for a 2-liner:
using(WebClient wc = new WebClient())
{
wc.DownloadFile(url, #"D:\Downloads\1.zip");
}
You can also use System.Net.Http.HttpClient
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage response = await client.GetAsync(downloadURL))
{
using(var stream = await response.Content.ReadAsStreamAsync())
{
using(Stream zip = FileManager.OpenWrite(ZIP_PATH))
{
stream.CopyTo(zip);
}
}
}
}
Expanding on Ruben's answer which uses HttpClient instead of WebClient, you can add as an extension method like this:
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
public static class Extensions
{
public static async Task DownloadFile (this HttpClient client, string address, string fileName) {
using (var response = await client.GetAsync(address))
using (var stream = await response.Content.ReadAsStreamAsync())
using (var file = File.OpenWrite(fileName)) {
stream.CopyTo(file);
}
}
}
And then use like this:
var archivePath = "https://api.github.com/repos/microsoft/winget-pkgs/zipball/";
using (var httpClient = new HttpClient())
{
await httpClient.DownloadFile(archivePath, "./repo.zip");
}

Categories

Resources