On MSDN about using
, there's the new syntax presented. I like it and started to apply it.
Instead of
using (MemoryStream memory = new MemoryStream())
{
using (CryptoStream crypto = new CryptoStream(memory, transform, CryptoStreamMode.Write))
{
using (StreamWriter writer = new StreamWriter(crypto))
{
writer.Write(text);
}
}
}
I can now go
using Aes aes = Aes.Create();
using ICryptoTransform transform = aes.CreateEncryptor(key, iv);
using MemoryStream memory = new MemoryStream();
using CryptoStream crypto = new CryptoStream(memory, transform, CryptoStreamMode.Write);
using (StreamWriter writer = new StreamWriter(crypto))
writer.Write(text);
However, I can't make the last part work the new way. For some reason, StreamWriter
won't allow me to do this.
using Aes aes = Aes.Create();
using ICryptoTransform transform = aes.CreateEncryptor(key, iv);
using MemoryStream memory = new MemoryStream();
using CryptoStream crypto = new CryptoStream(memory, transform, CryptoStreamMode.Write);
using StreamWriter writer = new StreamWriter(crypto);
writer.Write(text);
I can't really see why. There might be a technical explanation to it in the linked article, as they discuss requirements and limitations. Regrettably, I simply fail to see where they say it and what's implied.
By Skeety's request - full reproducible sample.
public void Test()
{
string text = "hakuna matata";
string code = "1234567890abcdef";
byte[] key = Encoding.ASCII.GetBytes(code);
byte[] iv = key[..16];
using Aes aes = Aes.Create();
using ICryptoTransform transform = aes.CreateEncryptor(key, iv);
using MemoryStream memory = new MemoryStream();
using CryptoStream crypto = new CryptoStream(memory, transform, CryptoStreamMode.Write);
using StreamWriter writer = new StreamWriter(crypto);
writer.Write(text);
//writer.Flush();
//using (StreamWriter writer = new StreamWriter(crypto))
// writer.Write(text);
string output = Convert.ToBase64String(memory.ToArray());
}
Under your old code, all your resources, including the StreamWriter
and CryptoStream
, get disposed implicitly at the end of their using
block. Upon being disposed, any pending content would get flushed to the MemoryStream
. Thus, when you inspect the MemoryStream
after the end of these using
blocks, it would be correctly populated.
In your new code, the new using
syntax means that the resources only get disposed at the end of the enclosing block – in this case, the parent method. Thus, when you inspect the MemoryStream
within the same method, you are doing so before StreamWriter
and CryptoStream
have been disposed, and hence before their contents have been flushed to the MemoryStream
.
For the sake of demonstration, calling Dispose
on the StreamWriter
just before reading the MemoryStream
would restore the correct behavior:
using StreamWriter writer = new StreamWriter(crypto);
writer.Write(text);
writer.Dispose()
string output = Convert.ToBase64String(memory.ToArray());
That said, I would recommend against the above, since you're mixing explicit Dispose
calls with implicit ones generated by the using
.
Alternatively, you could consume the MemoryStream
from an outer method, hence ensuring the inner method would have disposed its resources at the end of its execution:
public void Test()
{
var memory = TestInner();
string output = Convert.ToBase64String(memory.ToArray());
}
private MemoryStream TestInner()
{
string text = "hakuna matata";
string code = "1234567890abcdef";
byte[] key = Encoding.ASCII.GetBytes(code);
byte[] iv = key[..16];
using Aes aes = Aes.Create();
using ICryptoTransform transform = aes.CreateEncryptor(key, iv);
using MemoryStream memory = new MemoryStream();
using CryptoStream crypto = new CryptoStream(memory, transform, CryptoStreamMode.Write);
using StreamWriter writer = new StreamWriter(crypto);
writer.Write(text);
return memory;
}
However, I would prefer using the old using
blocks for clarity in situations like this.