Calculate SHA1 during PostAsync with StreamContent in .net core - c#

I wanted to make an HTTP POST request with a big file so I composed C# code on .net core like following:
using (var fileStream = new FileStream(filePath, FileMode.Open))
using (var streamContent = new StreamContent(fileStream))
{
var content = new MultipartFormDataContent();
content.Add(streamContent);
resp = await httpClient.PostAsync(requestUri, content);
}
It worked well for me. But, I found that it might be happy if SHA1 can be calculated during this context then it can be used for a simple caching for the POST result.
I found some answers on SO like the following:
How do I do a SHA1 File Checksum in C#?
But, I have no idea how I can use this to my code.
Here is what I tried so far:
byte[] hash = null;
using (SHA1Managed shaForStream = new SHA1Managed())
using (var fs = new FileStream(filePath, FileMode.Open))
using (var streamContent = new StreamContent(fs))
{
var content = new MultipartFormDataContent();
content.Add(streamContent);
resp = await httpClient.PostAsync(requestUri, content);
hash = shaForStream.ComputeHash(fs);
}
It is not working. For example, the sha1 value is the same for different files.
I think I might need to study Stream more. Could you tell me which materials do I need to study for this problem?
p.s, There are a couple of ways to cache request and response i.e., request params and response, but I want to do it with a SHA1 way for testing. I am just curious how I can do calculate something and request POST with only one stream. I can do it by creating two file streams. :)

Related

How to get httpcontext.request as it is in .net Core?

I am trying to read request from httpcontext,but it is changing, not same with original request.So it creates problem during hashing on SHA256.When I try to create sha256 on online tools with original request it is okey,but when I take request after reading it from httpcontext.request its is not same hash I create with original request.
What is the exact solution to read request as same as with original request without changing it and convert to string to compute SHA256?
using (var ms = new MemoryStream())
{
await httpContext.Request.Body.CopyToAsync(ms);
ms.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(ms))
{
using (var jsonTextReader = new JsonTextReader(sr))
{
var bodyContent = serializer.Deserialize(jsonTextReader);
//hashing starts here with bodyContent.ToString()
}
}
}

Redirecting/Proxying Stream in ASP.NET MVC using C#

I try to download and parallel upload streams (.ts, .mkv, .avi) from one source (locally limited) to an ASP.NET MVC response, so I can access the stream without any manipulation from outside.
I have this code so far.
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage response = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).Result)
using (Stream streamToReadFrom = response.Content.ReadAsStreamAsync().Result)
{
using (var returnStream = new MemoryStream())
{
streamToReadFrom.CopyToAsync(returnStream);
return new FileStreamResult(returnStream, "video/mp2t");
}
}
}
I thought I can just pass the download stream onto the response stream, but I got stuck with the asynchronous part. The system is responding with the following:
ObjectDisposedException: Cannot access a closed Stream.
Does anyone have an idea what I have to change, to get this running?
I found a second solution for my problem which seems to work sort of. At least the code wont crash. But when I try to save the file, it wont have any data (0kB)
var client = new HttpClient();
var result = await client.GetAsync(url);
var stream = await result.Content.ReadAsStreamAsync();
return new FileStreamResult(stream, "video/mp2t");
But now I can't access the stream. I am not sure why that is.
I have set the action to asynchronous, to use the code.
I am not sure if I have to change the result stream or add some header information or what to do, to get it work.

What is the correct way to post and save stream response to file using Flurl

I am trying to implement an asynchronous POST file and read the response directly to a file using Flurl. The code below works fine but not sure about the writing stream to file using c.Result.CopyTo or c.Result.CopyToAsync? What method is correct?
var result = new Url(url)
.WithHeader("Content-Type", "application/octet-stream")
.PostAsync(new FileContent(Conversion.SourceFile.FileInfo.ToString()))
.ReceiveStream().ContinueWith(c =>
{
using (var fileStream = File.Open(DestinationLocation + #"\result." + model.DestinationFileFormat, FileMode.Create))
{
c.Result.CopyTo(fileStream);
//c.Result.CopyToAsync(fileStream);
}
});
if (!result.Wait(model.Timeout * 1000))
throw new ApiException(ResponseMessageType.TimeOut);
You can certainly use CopyToAsync here, but that's cleaner if you avoid ContinueWith, which generally isn't nearly as useful since async/await were introduced. It also makes disposing the HTTP stream cleaner. I'd go with something like this:
var request = url.WithHeader("Content-Type", "application/octet-stream");
var content = new FileContent(Conversion.SourceFile.FileInfo.ToString());
using (var httpStream = await request.PostAsync(content).ReceiveStream())
using (var fileStream = new FileStream(path, FileMode.CreateNew))
{
await httpStream.CopyToAsync(fileStream);
}

Parsing CSV from HttpResponseMessage using CSVHelper

Currently I am using a two step approach to fetch data from the Web Api and
deserialize the CSV records into objects.
var response = await httpClient.GetAsync(queryString);
using (var reader = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
var csvr = new CsvReader(reader);
var responseValue = csvr.GetRecords<TrainingDataSetData>().ToList();
result.Readings.AddRange(responseValue);
}
How do I optimize this code?
If you're trying to avoid creating an intermediate MemoryStream - you could use the GetStreamAsync method on HttpClient, which should return the raw NetworkStream for you pass straight into CsvHelper, instead of ReadAsStreamAsync, which will default to reading the full response into a MemoryStream before returning.
using (var reader = new StreamReader(await httpClient.GetStreamAsync(queryString)))
{
var csvr = new CsvReader(reader);
var responseValue = csvr.GetRecords<TrainingDataSetData>().ToList();
result.Readings.AddRange(responseValue);
}
If you still need access to the HttpResponseMessage, you could achieve the same effect by using HttpCompletionOption.ResponseHeadersRead, which won't buffer the response before returning.
var response = await httpClient.GetAsync(queryString, HttpCompletionOption.ResponseHeadersRead);
As to whether or not this is actually more efficient - this is something that would require benchmarking in your particular environment to decide, since it may be conditional on the size of the response, speed of the network etc.

C# Serving a stream to a browser - can it be done?

I am trying to output a file to the browser from a REST API - but I don't have a physical file, instead I have a MemoryStream (and I would prefer not to write a physical file).
This works:
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(path, FileMode.Open);
result.Content = new StreamContent(stream);
return result;
This does not:
var stream = new MemoryStream();
// Iterate DataReader and populate MemoryStream code omitted for brevity.
// Assume MemoryStream has been written to correctly and contains data.
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(stream);
return result;
This has consumed most of my weekend so I would be delighted if anyone can offer some definitive insight.
I've found the answer through trial and error and a lot of research:
Yes, it can be done.
Instead of using StreamContent use ByteArrayContent:
e.g.
result.Content = new ByteArrayContent( stream.GetBuffer() );
Ensure that there is no HttpResponseMessage.ContentLength set or it will fail to work (connection reset) - it took me hours to figure that out.

Categories