I get the warning CA2202 (Object can be disposed more than once) on the following code:
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
using (var br = new BinaryReader(responseStream))
{
responseValue = br.ReadBytes(500000);
}
}
It seems like, the responseStreams Dispose is called when the BinaryReaders Dispose is called. Does the BinaryReader always call the Streams Dispose Method?
One solution would be to initialize the ResponseStream directly and let the BinaryReader take care about disposing the stream (which, of course, would only work, if the BinaryReader would dispose the stream in any situation)
Stream responseStream = response.GetResponseStream();
if(responseStream != null)
using (var br = new BinaryReader(responseStream)) //Always disposes the response stream?
[...]
I could use a try/finalize instead of the outer using statement to get something like this:
Stream responseStream = null;
try
{
responseStream = response.GetResponseStream();
if (responseStream != null)
using (var br = new BinaryReader(responseStream))
{
responseValue = br.ReadBytes(500000);
}
}
finally
{
if(stream != null)
stream.Dispose;
}
This isn't nice to look and unnecessary, when the BinaryReader always disposes the stream. Is there a better / preferred solution to solve this kind of problem?
You can actually look how BinaryReader.Dispose is implemented:
protected virtual void Dispose(bool disposing) {
if (disposing) {
Stream copyOfStream = m_stream;
m_stream = null;
if (copyOfStream != null && !m_leaveOpen)
copyOfStream.Close();
}
m_stream = null;
m_buffer = null;
m_decoder = null;
m_charBytes = null;
m_singleChar = null;
m_charBuffer = null;
}
public void Dispose()
{
Dispose(true);
}
Now, question is, what is m_leaveOpen? That's a flag which say if underlying stream should be disposed or not! It's by default set to false, which means underlying stream will be disposed:
public BinaryReader(Stream input) : this(input, new UTF8Encoding(), false) {
}
public BinaryReader(Stream input, Encoding encoding) : this(input, encoding, false) {
}
public BinaryReader(Stream input, Encoding encoding, bool leaveOpen) {
// (...)
m_leaveOpen = leaveOpen;
// (...)
}
So you can skip using statement around you stream, as it will be disposed anyway:
responseStream = response.GetResponseStream();
if (responseStream != null)
{
using (var br = new BinaryReader(responseStream))
{
responseValue = br.ReadBytes(500000);
}
}
or just
using (var br = new BinaryReader(response.GetResponseStream()))
{
responseValue = br.ReadBytes(500000);
}
If you are using VS 2012 with .NET 4.5, you can create a BinaryReader that won't close the stream. E.g.:
using(var reader = new BinaryReader(theStream, new UTF8Encoding(), true)
{
//...
}
new UTF8Encoding is the default if you used the BinaryReader(Stream) constructor, if you don't want UTF8Encoding, you can use something else. The true signifies "yes, leave the stream open".
Constructs like :
public BinaryReader(
Stream input,
Encoding encoding,
bool leaveOpen
)
Hope this leads you to something you are looking for.
Cheers.
Related
I would like to be able to return MemoryStream from my function but I think that when returning the stream its also automatically closed.
using (var httpStream = await httpClient.GetStreamAsync(link))
{
using (var stream = new MemoryStream())
{
await httpStream.CopyToAsync(stream);
return stream;
}
}
Is there any way to maybe override this so I can return stream so I can use it elsewhere.
Here's how I'm trying to use it in another method:
using (var fielStream = new FileStream(path, FileMode.Create))
{
Stream stream = await GetStreamAsync(videoid, type, quality);
await stream.CopyToAsync(fileStream);
}
Drop inner using: it is the caller (who calls for creation) should Dispose the stream:
using (var httpStream = await httpClient.GetStreamAsync(link)) {
var stream = new MemoryStream();
try {
await httpStream.CopyToAsync(stream);
return stream;
}
catch {
stream.Dispose();
throw;
}
}
It is the caller who should put using, like this:
// We create MemoryStream with the code above (GetStreamAsync)
/ and then Dispose the stream
using (var stream = await GetStreamAsync(...)) {
...
}
I'm trying to get body from request of an authorization class (AuthorizationHandler), but that body is a Stream and after reading your content, the post request that comes on next can not be executed because Stream content has been disposable.
I'm using this code to get Stream content:
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, Autorizacao requirement)
{
var routeValues = context.Resource as AuthorizationFilterContext;
if (routeValues != null)
{
var obj = StreamToObject(routeValues.HttpContext.Request.Body);
context.Succeed(requirement);
}
return Task.FromResult(0);
}
private Object StreamToObject(Stream stream)
{
try
{
string content;
using (var reader = new StreamReader(stream))
content = reader.ReadToEnd();
return Newtonsoft.Json.JsonConvert.DeserializeObject(content);
}
catch (Exception e)
{
throw e;
}
}
How i can do to workaround this problem ?
StreamReader has a special constructor that allow you to pass a boolean as last parameter. It will prevent dispose underlying stream
EDIT: Because ReadToEnd do not restore position in stream you should do it by yourself like this:
var position = stream.Position;
using (var reader = new StreamReader(stream, Encoding.UTF8, false, 8192, true))
content = reader.ReadToEnd();
stream.Seek(position, SeekOrigin.Begin);
EDIT 2: From MSDN I see that Body has a setter. So you can replace original Body with memory stream:
if (routeValues != null)
{
var memoryStream = new MemoryStream();
routeValues.HttpContext.Request.Body.CopyTo(memoryStream);
// reset position after CopyTo
memoryStream.Seek(0, SeekOrigin.Begin);
var obj = StreamToObject(memoryStream);
// reset position after ReadToEnd
memoryStream.Seek(0, SeekOrigin.Begin);
routeValues.HttpContext.Request.Body = memoryStream;
context.Succeed(requirement);
}
Maybe not needed any more, but you can set request.EnableRewind() and then do the request.Body.Seek(0, SeekOrigin.Begin);
Work for me
I need to read csv file twice. but after first reading:
using (var csvReader = new StreamReader(file.InputStream))
{
fileFullText += csvReader.ReadToEnd();
file.InputStream.Seek(0, SeekOrigin.Begin);
csvReader.Close();
}
using file in enother function:
public static List<string> ParceCsv(HttpPostedFileBase file)
{
//file.InputStream.Seek(0, SeekOrigin.Begin);
using (var csvReader = new StreamReader(file.InputStream))
{
// csvReader.DiscardBufferedData();
// csvReader.BaseStream.Seek(0, SeekOrigin.Begin);
string inputLine = "";
var values = new List<string>();
while ((inputLine = csvReader.ReadLine()) != null)
{
values.Add(inputLine.Trim().Replace(",", "").Replace(" ", ""));
}
csvReader.Close();
return values;
}
}
The file.Length is 0.
Can anybody help?
The reason is that SteramReader's Dispose() method also closes the underlying stream; In your case file.InputStream. The using statement calls Dispose() implicitly. Try to replace using with disposes of both your StreamReaded-s after you finished both read operations. As I remember some stream classes have a bool option to leave underlying stream open after dispose.
.NET 4.5 fixed this issue by introducing leaveOpen parameter in SteamReader constructor. See: MSDN
public StreamReader(
Stream stream,
Encoding encoding,
bool detectEncodingFromByteOrderMarks,
int bufferSize,
bool leaveOpen
)
One more thing. You do not need to close SteramReader yourself (the line with csvReader.Close();) when you wrap it in using statement, thus Dispose() and Close() are the same in case of StreamReader.
if your using HttpPostedFileBase you need to clone it first,
use the code this git here
or just add this as a class in your namespace:
public static class HttpPostedFileBaseExtensions
{
public static Byte[] ToByteArray(this HttpPostedFileBase value)
{
if (value == null)
return null;
var array = new Byte[value.ContentLength];
value.InputStream.Position = 0;
value.InputStream.Read(array, 0, value.ContentLength);
return array;
}
}
now you can read the HttpPostedFileBase like so:
private static void doSomeStuff(HttpPostedFileBase file)
{
try
{
using (var reader = new MemoryStream(file.ToByteArray()))
{
// do some stuff... say read it to xml
using (var xmlTextReader = new XmlTextReader(reader))
{
}
}
}
catch (Exception ex)
{
throw ex;
}
}
after using this you can still write in your main code:
file.SaveAs(path);
and it will save it to the file.
i have tried following the rules of code analysis on this method:
public static string Encrypt(string password)
{
string myPassword = string.Empty;
if (!string.IsNullOrEmpty(password))
{
myPassword = password;
byte[] Value = System.Text.Encoding.UTF8.GetBytes(myPassword);
SymmetricAlgorithm mCSP = new RijndaelManaged();
mCSP.Key = _key;
mCSP.IV = _initVector;
using (ICryptoTransform ct = mCSP.CreateEncryptor(mCSP.Key, mCSP.IV))
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write))
{
cs.Write(Value, 0, Value.Length);
cs.FlushFinalBlock();
cs.Close();
myPassword = Convert.ToBase64String(ms.ToArray());
}
}
}
}
return myPassword;
}
added all the Try {} Finaly{} blocks, but it was still yelling at me that i dont respect rule 2202.
anyone can give me a hand with this?
yes, i have read other posts about this subject and tried applying it,
but at the end i still get the same message.
To get rid of the CA2202 warning for cs, simply remove the call to its Close method.
The CA2202 problem for ms is a wee bit more complex. The warning is cropping up because CryptoStream has the effrontery to dispose the stream it received via is constructor, which means that there's one inappropriate call to ms.Close() that you can't avoid. The good news is that this untimely disposition has no side-effects in your case, and the same goes for the double disposition, so you can safely slap on a SuppressMessageAttribute and ignore the problem. (For cases where you actually need to passed stream to survive its unpreventable disposition by something like CryptoStream, the usual technique is to use a stream subclass whose disposition can be prevented by its instantiating code.)
Get rid of these two lines, they aren't needed:
cs.FlushFinalBlock();
cs.Close();
Following the documentation on this topic should lead to this code:
public static string Encrypt(string password)
{
string myPassword = string.Empty;
if (!string.IsNullOrEmpty(password))
{
myPassword = password;
byte[] Value = System.Text.Encoding.UTF8.GetBytes(myPassword);
SymmetricAlgorithm mCSP = new RijndaelManaged();
mCSP.Key = _key;
mCSP.IV = _initVector;
using (ICryptoTransform ct = mCSP.CreateEncryptor(mCSP.Key, mCSP.IV))
{
System.IO.MemoryStream ms = null;
try
{
ms = new System.IO.MemoryStream()
var tmp = ms;
using (CryptoStream cs = new CryptoStream(ms, ct,
CryptoStreamMode.Write))
{
ms = null;
cs.Write(Value, 0, Value.Length);
cs.FlushFinalBlock();
cs.Close();
myPassword = Convert.ToBase64String(tmp.ToArray());
}
}
finally
{
if(ms != null)
ms.Dispose();
}
}
}
return myPassword;
}
The documentation on this analysis warning (http://msdn.microsoft.com/en-us/library/ms182334.aspx) gives this example, similar to yours in that it's manipulating streams:
Stream stream = null;
try
{
stream = new FileStream("file.txt", FileMode.OpenOrCreate);
using (StreamWriter writer = new StreamWriter(stream))
{
stream = null;
// Use the writer object...
}
}
finally
{
if(stream != null)
stream.Dispose();
}
but this still gives the error. The following will solve the error:
Stream stream = null;
StreamWriter writer = null;
try
{
stream = new FileStream("file.txt", FileMode.OpenOrCreate);
writer = new StreamWriter(stream))
// Do some stuff on the stream writer..
}
finally
{
if(writer != null)
writer.Dispose();
else if(stream != null)
stream.Dispose();
}
The reason is simple; if the writer will always dispose the stream for you. Only in the scenario the writer is not successfully created should you dispose the stream yourself. But I must admit I like the following syntax a lot more, and if you create a MemoryStream instead of a FileStream the chance of an exception occurring is small and I would prefer suppressing the CA. Please notice that you can stack using statements, so a extra 'nesting level' is often not required.
using (Stream stream = new FileStream("file.txt", FileMode.OpenOrCreate))
using (StreamWriter writer = new StreamWriter(stream))
{
// Use the writer object...
}
How can I ensure the following code is disposing of all objects in a better fashion? Currently, Code Analysis is telling me
Error 45 CA2202 : Microsoft.Usage : Object 'ns' can be disposed more than once in method 'CPCommunicator.GetResults(string)'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 64, 65
NetworkStream ns = null;
StreamWriter requestStream = null;
TextReader responseStream = null;
var results = new StringBuilder();
try
{
ns = new NetworkStream(CreateConnection(), true);
requestStream = new StreamWriter(ns);
requestStream.Flush();
responseStream = new StreamReader(ns);
requestStream.Write(reportData);
requestStream.Flush();
while (responseStream.Peek() != -1)
{
var currentLine = responseStream.ReadLine();
results.Append(currentLine);
results.Append("\n");
}
}
finally
{
if (requestStream != null) requestStream.Close();
if (responseStream != null) responseStream.Close();
if (cpNetworkStream != null) cpNetworkStream.Close();
}
Since both requestStream and responseStream use ns, they both dispose of ns so in order to satisfy the code analysis warning, I have to comment out the last two close methods in the finally block. But do I really want to do this?????
Yes, imho you really should only call it once.
Alternatively you could use the using syntax on ns, which makes the whole situation even clearer.
using (ns = new NetworkStream(CreateConnection(), true)) {
...
}
I would refactor your code to be like this:
using (NetworkStream ns = new NetworkStream(CreateConnection(), true))
using (StreamWriter requestStream = new StreamWriter(ns))
using (TextReader responseStream = new StreamReader(ns))
{
var results = new StringBuilder();
requestStream.Flush();
requestStream.Write(reportData);
requestStream.Flush();
while (responseStream.Peek() != -1)
{
var currentLine = responseStream.ReadLine();
results.Append(currentLine);
results.Append("\n");
}
}