DotNetZip - This stream does not support seek operations - dotnetzip

When I try and extract the "test.png" I receive the following error: This stream does not support seek operations.
Also can a wildcard be used? var entry = zipout["*.png"]; I will not know the same when streaming.
var request = (HttpWebRequest)WebRequest.Create("http://www.xxx.xxxx.com/xxx/xxxx?key=ndXqH2fXzePomlVoX39trxUf%2FV1bfN0rZsHsTyEvI%2F0%3D&labelFormat=png");
using (var ms = new MemoryStream())
{
using (var response = (HttpWebResponse)request.GetResponse())
{
using (var stream =response.GetResponseStream())
{
using (var zipout = ZipFile.Read(stream))
{
var entry = zipout["test.png"];
entry.Extract(ms);
}
}
}
}
Updated
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var stream = new MemoryStream())
{
if (responseStream != null)
{
responseStream.CopyTo(stream);
}
using (var zipout = ZipFile.Read(stream))
{
using (var ms = new MemoryStream())
{
var entry = zipout["test.png"];
entry.Extract(ms);
}
}
}
}
}
New error: Message = "Cannot read that as a ZipFile"

var request = (HttpWebRequest)WebRequest.Create("var request = (HttpWebRequest)WebRequest.Create("http://www.xxx.xxxx.com/xxx/xxxx?key=ndXqH2fXzePomlVoX39trxUf%2FV1bfN0rZsHsTyEvI%2F0%3D&labelFormat=png");
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var stream = new MemoryStream())
{
if (responseStream == null)
{
return;
}
responseStream.CopyTo(stream);
stream.Position = 0;
using (var zipout = ZipFile.Read(stream))
{
using (var ms = new MemoryStream())
{
var entry = zipout["test.png"];
if (entry != null)
{
entry.Extract(ms);
}
else
{
return;
}
}
}
}
}
}

Related

Files not downloaded showing binay data in ASP.NET core web API

Trying to download multiplefile as zip using System.io.compression from asp.net core web api. But i got binary error text. How can i fix this? below is my code
Error:
Error from backend. {"headers":{"normalizedNames":{},"lazyUpdate":null},"status":200,"statusText":"OK","url":"http://localhost:4000/api/filegeneration/createfile/2023-02-08/1","ok":false,"name":"HttpErrorResponse","
message":"Http failure during parsing for http://localhost:4000/api/filegeneration/createfile/2023-02-08/1",
"error":{"error":{},"text":"PK\u0003\u0004\u0014\u0000\u0000\u0000\b\u0000��HV�
u0010\u0001\u000b\u0000\u0000\u0000\u0003\u0000\u0000\u0000\u001e\u0000\u0000\u0000
Fareshare_Qty_08.02.2023_0.txtz�{?\u0000\u0000\u0000��\u0003\u0000PK\u0001\u0002\u0014
\u0000\u0014\u0000\u0000\u0000\b\u0000��HV�\u0010\u0001\u000b\u0000\u0000\u0000\u0003\u0000\u0000
\u0000\u001e\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000Fareshare_Qty_08.02.2023_0.txtPK\u0005
\u0006\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000L\u0000\u0000\u0000G\u0000\u0000\u0000\u0000\u0000"}}
Controller:
using (var outstream = new MemoryStream())
{
using (var archive = new ZipArchive(outstream,ZipArchiveMode.Create,true))
{
foreach (string filePath in files)
{
var filearcive = archive.CreateEntry(Path.GetFileName(filePath),CompressionLevel.Optimal);
using (var entrystream = filearcive.Open())
{
using (var fileCompressionStream = new MemoryStream(System.IO.File.ReadAllBytes(filePath)))
{
await fileCompressionStream.CopyToAsync(entrystream);
}
}
}
}
outstream.Position = 0;
return File(outstream.ToArray(), "application/zip", "Fareshare.zip");
Below code works for me. Please check it.
public (string fileType, byte[] archiveData, string archiveName) DownloadFiles(string subDirectory)
{
var zipName = $"archive-{DateTime.Now.ToString("yyyy_MM_dd-HH_mm_ss")}.zip";
List<FileInfo> files = new DirectoryInfo(Path.Combine(_hostingEnvironment.ContentRootPath, subDirectory)).GetFiles().ToList();
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
files.ForEach(file =>
{
var theFile = archive.CreateEntry(file.Name);
using (var streamWriter = new StreamWriter(theFile.Open()))
{
streamWriter.Write(File.ReadAllText(file.FullName));
}
});
}
return ("application/zip", memoryStream.ToArray(), zipName);
}
Test Result

.Net Core Equivalent to CryptoJS.AES.encrypt

I have below JavaScript code that uses CryptoJS.AES.encrypt function from CryptoJS library and I am looking for equivalent .Net Core code, can anyone please guide?
var myData = '';
var key1 = '';
var key2 = '';
var encryptedData = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(myData.substr(0, myData.length - 1)), CryptoJS.enc.Utf8.parse(key1),
{
keySize: 128 / 8,
iv: CryptoJS.enc.Utf8.parse(key2),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
Edit
I have found below code for .Net Core:
public string EncryptString(string text, string keyString, string ivString)
{
var key = Encoding.UTF8.GetBytes(keyString);
using (var aesAlg = Aes.Create())
{
using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
{
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(text);
}
var iv = aesAlg.IV;
var decryptedContent = msEncrypt.ToArray();
var result = new byte[iv.Length + decryptedContent.Length];
Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);
return Convert.ToBase64String(result);
}
}
}
}
But I am not sure how to specify these options as specified in JavaScript code:
{
keySize: 128 / 8,
iv: CryptoJS.enc.Utf8.parse(key2),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}
Edit 2
I updated my C# code following suggestions from Topaco and below is my code.
But when I test it the output of my C# code and JavaScript code is different can anyone please guide what's missing?
public string RequestHash(string text, string keyString, string ivString)
{
var key = Encoding.UTF8.GetBytes(keyString);
var iv = Encoding.UTF8.GetBytes(ivString);
using (var aesAlg = Aes.Create())
{
using (var encryptor = aesAlg.CreateEncryptor(key, iv))
{
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(text);
}
var decryptedContent = msEncrypt.ToArray();
return Convert.ToBase64String(decryptedContent);
}
}
}
}
Thank you so much Topaco for your help, really appreciate!
Here's my final code:
public string RequestHash(string text, string keyString, string ivString)
{
var key = Encoding.UTF8.GetBytes(keyString);
var iv = Encoding.UTF8.GetBytes(ivString);
using (var aesAlg = Aes.Create())
{
using (var encryptor = aesAlg.CreateEncryptor(key, iv))
{
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(text);
}
var decryptedContent = msEncrypt.ToArray();
return Convert.ToBase64String(decryptedContent);
}
}
}
}

How to download multiple files at once from S3 using C# AWS SDK

How to download multiple files from s3 buckets. I could not find any better option on SO.
Here is my code for single file download. Given list of Urls, I am looping to download multiple files.
public async Task Download(string url, Stream output)
{
var s3Uri = new AmazonS3Uri(url);
GetObjectRequest getObjectRequest = new GetObjectRequest
{
BucketName = s3Uri.Bucket,
Key = System.Net.WebUtility.UrlDecode(s3Uri.Key)
};
using (var s3Client = new AmazonS3Client(s3Uri.Region))
{
// dispose the underline stream when writing to stream is done
using (var getObjectResponse = await s3Client.GetObjectAsync(getObjectRequest).ConfigureAwait(false))
{
using (var responseStream = getObjectResponse.ResponseStream)
{
await responseStream.CopyToAsync(output);
}
}
}
output.Seek(0L, SeekOrigin.Begin);
}
Download files given s3 urls
var list = new List<Stream>();
foreach(var url in urls)
{
var stream = new MemoryStream();
await Download(url,ms);
list.Add(stream);
}
Is there any better option to download multiple files at once from S3?
I finally decided to implement my own version
public class StreamWrapper
{
public string Url { get; set; }
public Stream Content { get; set; }
public string FileName { get; set; }
}
public async Task Download(IList<StreamWrapper> inout, int maxConcurrentDownloads)
{
if (maxConcurrentDownloads <= 0)
{
maxConcurrentDownloads = 20;
}
if (!inout.HasAny())
return;
var tasks = new List<Task>();
for (int i = 0; i < inout.Count; i++)
{
StreamWrapper wrapper = inout[i];
AmazonS3Uri s3Uri = null;
if (AmazonS3Uri.TryParseAmazonS3Uri(wrapper.Url, out s3Uri))
{
tasks.Add(GetObject(s3Uri, wrapper.Content));
}
if (tasks.Count == maxConcurrentDownloads || i == inout.Count - 1)
{
await Task.WhenAll(tasks);
tasks.Clear();
}
}
}
private async Task GetObject(AmazonS3Uri s3Uri, Stream output)
{
GetObjectRequest getObjectRequest = new GetObjectRequest
{
BucketName = s3Uri.Bucket,
Key = System.Net.WebUtility.UrlDecode(s3Uri.Key)
};
using (var s3Client = new AmazonS3Client(s3Uri.Region))
{
// dispose the underline stream when writing to local file system is done
using (var getObjectResponse = await s3Client.GetObjectAsync(getObjectRequest).ConfigureAwait(false))
{
using (var responseStream = getObjectResponse.ResponseStream)
{
await responseStream.CopyToAsync(output);
}
}
}
output.Seek(0L, SeekOrigin.Begin);
}

How to convert MailAttachment to MimeKit Attachment

We have to rework how we're sending emails since we are using Amazon SES. In the past, we were using smtp but can't do that in this case. The class that needs updated has taken in a MailMessage object and used smtp to send it. So I'm trying to rework the method to be able to continue to accept the MailMessage object and convert it to a MimeKit MimeMessage. For the most part it's working fine except when it comes to attachments. In the code I have, the attachment gets added and sent, however, when trying to open it appears it's corrupted or something. In my test case I attached a csv file. I could not open it in excel after receiving the email.
public class EmailAbstraction
{
public virtual void Send(MailMessage mailMessage)
{
sendMessage(mailMessage);
}
private static void sendMessage(MailMessage mailMessage)
{
using (var client = new AmazonSimpleEmailServiceClient(AwsConstants.SESAWSKey, AwsConstants.SESAWSSecret, AwsConstants.RegionEndpoint))
{
foreach (var to in mailMessage.To)
{
using (var messageStream = new MemoryStream())
{
var newMessage = new MimeMessage();
var builder = new BodyBuilder
{
HtmlBody = mailMessage.Body
};
newMessage.From.Add(mailMessage.From == null
? new MailboxAddress(EmailConstants.DefaultFromEmailDisplayName, EmailConstants.DefaultFromEmailAddress)
: new MailboxAddress(mailMessage.From.Address));
newMessage.To.Add(new MailboxAddress(to.DisplayName, to.Address));
newMessage.Subject = mailMessage.Subject;
foreach (var attachment in mailMessage.Attachments)
{
builder.Attachments.Add(attachment.Name, attachment.ContentStream);
}
newMessage.Body = builder.ToMessageBody();
newMessage.WriteTo(messageStream);
var request = new SendRawEmailRequest
{
RawMessage = new RawMessage { Data = messageStream }
};
client.SendRawEmail(request);
}
}
}
}
}
And in my test app, I have this.
internal class Program
{
private static void Main(string[] args)
{
var s = GetFileStream();
var m = new MailMessage();
var sender = new MailAddress("info#ourwebsite.com", "info");
m.From = sender;
m.Sender = sender;
m.Body = "test email";
m.Subject = "test subject";
m.To.Add(myemail);
m.Attachments.Add(new Attachment(s, "test-file.csv"));
new EmailAbstraction().Send(m);
}
private static MemoryStream GetFileStream()
{
var stream = new MemoryStream();
var fileStream = File.Open(#"C:\Users\dev\Desktop\test-file.csv", FileMode.Open);
fileStream.CopyTo(stream);
fileStream.Close();
return stream;
}
}
This is just copied from the MimeKit source code:
static MimePart GetMimePart (System.Net.Mail.AttachmentBase item)
{
var mimeType = item.ContentType.ToString ();
var contentType = ContentType.Parse (mimeType);
var attachment = item as System.Net.Mail.Attachment;
MimePart part;
if (contentType.MediaType.Equals ("text", StringComparison.OrdinalIgnoreCase))
part = new TextPart (contentType);
else
part = new MimePart (contentType);
if (attachment != null) {
var disposition = attachment.ContentDisposition.ToString ();
part.ContentDisposition = ContentDisposition.Parse (disposition);
}
switch (item.TransferEncoding) {
case System.Net.Mime.TransferEncoding.QuotedPrintable:
part.ContentTransferEncoding = ContentEncoding.QuotedPrintable;
break;
case System.Net.Mime.TransferEncoding.Base64:
part.ContentTransferEncoding = ContentEncoding.Base64;
break;
case System.Net.Mime.TransferEncoding.SevenBit:
part.ContentTransferEncoding = ContentEncoding.SevenBit;
break;
//case System.Net.Mime.TransferEncoding.EightBit:
// part.ContentTransferEncoding = ContentEncoding.EightBit;
// break;
}
if (item.ContentId != null)
part.ContentId = item.ContentId;
var stream = new MemoryStream ();
item.ContentStream.CopyTo (stream);
stream.Position = 0;
part.Content = new MimeContent (stream);
return part;
}

Why CsvHelper not reading from MemoryStream?

I am trying to convert an uploaded csv file to an object, so i can save in db.
In the controller I am using CsvHeler
But looks like this only works if I first save the file and read from it. CsvHelper is not able to process the file contents directly from memory stream. In the code below the first GetRecords returns empty
[HttpPost]
[Route(ApiRoutes.EodVariationMarginPlugs)]
public async Task<IActionResult> UploadPlugAsync(IFormFile filePayload)
{
if (filePayload.Length > 0)
{
using (var stream = new MemoryStream())
{
filePayload.CopyTo(stream);
using (var reader = new StreamReader(stream))
using (var csv = new CsvReader(reader))
{
csv.Configuration.RegisterClassMap<EodVariationMarginPlugMap>();
csv.Configuration.MissingFieldFound = null;
var records = csv.GetRecords<EodVariationMarginPlug>().ToList(); // record count is 0
foreach (var p in records)
{
p.CreatedAt = DateTimeOffset.Now;
p.CreatedBy = HttpContext.User.Identity.Name;
}
await _repository.InsertPlugsAsync(records);
}
}
var fileName = ContentDispositionHeaderValue
.Parse(filePayload.ContentDisposition)
.FileName.ToString().Trim('"');
var path = Path.Combine(Path.GetTempPath(), fileName);
using (var fileStream = new FileStream(path, FileMode.Create))
{
await filePayload.CopyToAsync(fileStream);
}
var textReader = System.IO.File.OpenText(path);
using (var csv = new CsvReader(textReader))
{
csv.Configuration.RegisterClassMap<EodVariationMarginPlugMap>();
csv.Configuration.MissingFieldFound = null;
var records = csv.GetRecords<EodVariationMarginPlug>().ToList();
foreach (var p in records)
{
p.CreatedAt = DateTimeOffset.Now;
p.CreatedBy = HttpContext.User.Identity.Name;
}
await _repository.InsertPlugsAsync(records);
}
}
return Ok();
}
The most common error here is forgetting MemoryStream is binary; it deals in bytes. You need something that deals in characters, which isn't always a 1:1 adaption. The good news is you avoided that error by wrapping the MemoryStream in a StreamReader:
using (var reader = new StreamReader(stream))
StreamReader implements TextReader, which works with characters rather than bytes. Yay! The bad news is the StreamReader is created right after this line:
filePayload.CopyTo(stream);
The problem was that line left the stream pointed at the end of the data. When you try to read from it, there's nothing left in the stream.
All you should need to do to fix this is seek back to the beginning. So this:
using (var stream = new MemoryStream())
{
filePayload.CopyTo(stream);
using (var reader = new StreamReader(stream))
Becomes this:
using (var stream = new MemoryStream())
{
filePayload.CopyTo(stream);
stream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(stream))